mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-10 15:17:41 +00:00
Refactor/space management (#404)
* refactor: reducing used queries on get communities (#385) * refactor: fix create space logic (#394) * Remove unique constraint on subspace and product in SubspaceProductAllocationEntity; update product relation to nullable in NewTagEntity * refactor: fix create space logic * device model updated to include the fixes and final columns * updated space models to include suggested fixes, update final logic and column names * task: removing old references of the old tag-product relation * task: remove old use of tags * task: remove old tag & tag model usage * refactor: delete space * task: remove unused functions * fix lint rule
This commit is contained in:
@ -1,51 +1,30 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { SnakeNamingStrategy } from './strategies';
|
|
||||||
import { UserEntity } from '../modules/user/entities/user.entity';
|
|
||||||
import { UserSessionEntity } from '../modules/session/entities/session.entity';
|
|
||||||
import { UserOtpEntity } from '../modules/user/entities';
|
|
||||||
import { ProductEntity } from '../modules/product/entities';
|
|
||||||
import { DeviceEntity } from '../modules/device/entities';
|
import { DeviceEntity } from '../modules/device/entities';
|
||||||
import { PermissionTypeEntity } from '../modules/permission/entities';
|
import { PermissionTypeEntity } from '../modules/permission/entities';
|
||||||
|
import { ProductEntity } from '../modules/product/entities';
|
||||||
|
import { UserSessionEntity } from '../modules/session/entities/session.entity';
|
||||||
|
import { UserOtpEntity } from '../modules/user/entities';
|
||||||
|
import { UserEntity } from '../modules/user/entities/user.entity';
|
||||||
|
import { SnakeNamingStrategy } from './strategies';
|
||||||
|
|
||||||
import { UserSpaceEntity } from '../modules/user/entities';
|
import { TypeOrmWinstonLogger } from '@app/common/logger/services/typeorm.logger';
|
||||||
import { DeviceUserPermissionEntity } from '../modules/device/entities';
|
import { createLogger } from 'winston';
|
||||||
import { RoleTypeEntity } from '../modules/role-type/entities';
|
import { winstonLoggerOptions } from '../logger/services/winston.logger';
|
||||||
import { UserNotificationEntity } from '../modules/user/entities';
|
import { AqiSpaceDailyPollutantStatsEntity } from '../modules/aqi/entities';
|
||||||
import { DeviceNotificationEntity } from '../modules/device/entities';
|
import { AutomationEntity } from '../modules/automation/entities';
|
||||||
import { RegionEntity } from '../modules/region/entities';
|
import { ClientEntity } from '../modules/client/entities';
|
||||||
import { TimeZoneEntity } from '../modules/timezone/entities';
|
|
||||||
import { VisitorPasswordEntity } from '../modules/visitor-password/entities';
|
|
||||||
import { CommunityEntity } from '../modules/community/entities';
|
import { CommunityEntity } from '../modules/community/entities';
|
||||||
import { DeviceStatusLogEntity } from '../modules/device-status-log/entities';
|
import { DeviceStatusLogEntity } from '../modules/device-status-log/entities';
|
||||||
import { SceneEntity, SceneIconEntity } from '../modules/scene/entities';
|
|
||||||
import { SceneDeviceEntity } from '../modules/scene-device/entities';
|
|
||||||
import { ProjectEntity } from '../modules/project/entities';
|
|
||||||
import {
|
import {
|
||||||
SpaceModelEntity,
|
DeviceNotificationEntity,
|
||||||
SubspaceModelEntity,
|
DeviceUserPermissionEntity,
|
||||||
TagModel,
|
} from '../modules/device/entities';
|
||||||
SpaceModelProductAllocationEntity,
|
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
} from '../modules/space-model/entities';
|
|
||||||
import {
|
import {
|
||||||
InviteUserEntity,
|
InviteUserEntity,
|
||||||
InviteUserSpaceEntity,
|
InviteUserSpaceEntity,
|
||||||
} from '../modules/Invite-user/entities';
|
} from '../modules/Invite-user/entities';
|
||||||
import { InviteSpaceEntity } from '../modules/space/entities/invite-space.entity';
|
|
||||||
import { AutomationEntity } from '../modules/automation/entities';
|
|
||||||
import { SpaceProductAllocationEntity } from '../modules/space/entities/space-product-allocation.entity';
|
|
||||||
import { NewTagEntity } from '../modules/tag/entities/tag.entity';
|
|
||||||
import { SpaceEntity } from '../modules/space/entities/space.entity';
|
|
||||||
import { SpaceLinkEntity } from '../modules/space/entities/space-link.entity';
|
|
||||||
import { SubspaceProductAllocationEntity } from '../modules/space/entities/subspace/subspace-product-allocation.entity';
|
|
||||||
import { SubspaceEntity } from '../modules/space/entities/subspace/subspace.entity';
|
|
||||||
import { TagEntity } from '../modules/space/entities/tag.entity';
|
|
||||||
import { ClientEntity } from '../modules/client/entities';
|
|
||||||
import { TypeOrmWinstonLogger } from '@app/common/logger/services/typeorm.logger';
|
|
||||||
import { createLogger } from 'winston';
|
|
||||||
import { winstonLoggerOptions } from '../logger/services/winston.logger';
|
|
||||||
import {
|
import {
|
||||||
PowerClampDailyEntity,
|
PowerClampDailyEntity,
|
||||||
PowerClampHourlyEntity,
|
PowerClampHourlyEntity,
|
||||||
@ -55,7 +34,30 @@ import {
|
|||||||
PresenceSensorDailyDeviceEntity,
|
PresenceSensorDailyDeviceEntity,
|
||||||
PresenceSensorDailySpaceEntity,
|
PresenceSensorDailySpaceEntity,
|
||||||
} from '../modules/presence-sensor/entities';
|
} from '../modules/presence-sensor/entities';
|
||||||
import { AqiSpaceDailyPollutantStatsEntity } from '../modules/aqi/entities';
|
import { ProjectEntity } from '../modules/project/entities';
|
||||||
|
import { RegionEntity } from '../modules/region/entities';
|
||||||
|
import { RoleTypeEntity } from '../modules/role-type/entities';
|
||||||
|
import { SceneDeviceEntity } from '../modules/scene-device/entities';
|
||||||
|
import { SceneEntity, SceneIconEntity } from '../modules/scene/entities';
|
||||||
|
import {
|
||||||
|
SpaceModelEntity,
|
||||||
|
SpaceModelProductAllocationEntity,
|
||||||
|
SubspaceModelEntity,
|
||||||
|
SubspaceModelProductAllocationEntity,
|
||||||
|
} from '../modules/space-model/entities';
|
||||||
|
import { InviteSpaceEntity } from '../modules/space/entities/invite-space.entity';
|
||||||
|
import { SpaceLinkEntity } from '../modules/space/entities/space-link.entity';
|
||||||
|
import { SpaceProductAllocationEntity } from '../modules/space/entities/space-product-allocation.entity';
|
||||||
|
import { SpaceEntity } from '../modules/space/entities/space.entity';
|
||||||
|
import { SubspaceProductAllocationEntity } from '../modules/space/entities/subspace/subspace-product-allocation.entity';
|
||||||
|
import { SubspaceEntity } from '../modules/space/entities/subspace/subspace.entity';
|
||||||
|
import { NewTagEntity } from '../modules/tag/entities/tag.entity';
|
||||||
|
import { TimeZoneEntity } from '../modules/timezone/entities';
|
||||||
|
import {
|
||||||
|
UserNotificationEntity,
|
||||||
|
UserSpaceEntity,
|
||||||
|
} from '../modules/user/entities';
|
||||||
|
import { VisitorPasswordEntity } from '../modules/visitor-password/entities';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forRootAsync({
|
TypeOrmModule.forRootAsync({
|
||||||
@ -86,7 +88,6 @@ import { AqiSpaceDailyPollutantStatsEntity } from '../modules/aqi/entities';
|
|||||||
SpaceEntity,
|
SpaceEntity,
|
||||||
SpaceLinkEntity,
|
SpaceLinkEntity,
|
||||||
SubspaceEntity,
|
SubspaceEntity,
|
||||||
TagEntity,
|
|
||||||
UserSpaceEntity,
|
UserSpaceEntity,
|
||||||
DeviceUserPermissionEntity,
|
DeviceUserPermissionEntity,
|
||||||
RoleTypeEntity,
|
RoleTypeEntity,
|
||||||
@ -101,7 +102,6 @@ import { AqiSpaceDailyPollutantStatsEntity } from '../modules/aqi/entities';
|
|||||||
SceneDeviceEntity,
|
SceneDeviceEntity,
|
||||||
SpaceModelEntity,
|
SpaceModelEntity,
|
||||||
SubspaceModelEntity,
|
SubspaceModelEntity,
|
||||||
TagModel,
|
|
||||||
InviteUserEntity,
|
InviteUserEntity,
|
||||||
InviteUserSpaceEntity,
|
InviteUserSpaceEntity,
|
||||||
InviteSpaceEntity,
|
InviteSpaceEntity,
|
||||||
|
@ -78,8 +78,8 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
|||||||
@OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.device, {})
|
@OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.device, {})
|
||||||
sceneDevices: SceneDeviceEntity[];
|
sceneDevices: SceneDeviceEntity[];
|
||||||
|
|
||||||
@OneToMany(() => NewTagEntity, (tag) => tag.devices)
|
@ManyToOne(() => NewTagEntity, (tag) => tag.devices)
|
||||||
// @JoinTable({ name: 'device_tags' })
|
@JoinColumn({ name: 'tag_uuid' })
|
||||||
public tag: NewTagEntity;
|
public tag: NewTagEntity;
|
||||||
@OneToMany(() => PowerClampHourlyEntity, (powerClamp) => powerClamp.device)
|
@OneToMany(() => PowerClampHourlyEntity, (powerClamp) => powerClamp.device)
|
||||||
powerClampHourly: PowerClampHourlyEntity[];
|
powerClampHourly: PowerClampHourlyEntity[];
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import { Column, Entity, OneToMany } from 'typeorm';
|
import { Column, Entity, OneToMany } from 'typeorm';
|
||||||
import { ProductDto } from '../dtos';
|
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
import { DeviceEntity } from '../../device/entities';
|
import { DeviceEntity } from '../../device/entities';
|
||||||
import { TagModel } from '../../space-model';
|
import { ProductDto } from '../dtos';
|
||||||
import { TagEntity } from '../../space/entities/tag.entity';
|
|
||||||
import { NewTagEntity } from '../../tag/entities';
|
|
||||||
@Entity({ name: 'product' })
|
@Entity({ name: 'product' })
|
||||||
export class ProductEntity extends AbstractEntity<ProductDto> {
|
export class ProductEntity extends AbstractEntity<ProductDto> {
|
||||||
@Column({
|
@Column({
|
||||||
@ -28,15 +25,6 @@ export class ProductEntity extends AbstractEntity<ProductDto> {
|
|||||||
})
|
})
|
||||||
public prodType: string;
|
public prodType: string;
|
||||||
|
|
||||||
@OneToMany(() => NewTagEntity, (tag) => tag.product, { cascade: true })
|
|
||||||
public newTags: NewTagEntity[];
|
|
||||||
|
|
||||||
@OneToMany(() => TagModel, (tag) => tag.product)
|
|
||||||
tagModels: TagModel[];
|
|
||||||
|
|
||||||
@OneToMany(() => TagEntity, (tag) => tag.product)
|
|
||||||
tags: TagEntity[];
|
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
() => DeviceEntity,
|
() => DeviceEntity,
|
||||||
(devicesProductEntity) => devicesProductEntity.productDevice,
|
(devicesProductEntity) => devicesProductEntity.productDevice,
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
import { IsNotEmpty, IsString } from 'class-validator';
|
|
||||||
|
|
||||||
export class TagModelDto {
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
public uuid: string;
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
public name: string;
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
public productUuid: string;
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
spaceModelUuid: string;
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
subspaceModelUuid: string;
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
|
export * from './space-model-product-allocation.entity';
|
||||||
export * from './space-model.entity';
|
export * from './space-model.entity';
|
||||||
export * from './subspace-model';
|
export * from './subspace-model';
|
||||||
export * from './tag-model.entity';
|
|
||||||
export * from './space-model-product-allocation.entity';
|
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
import {
|
import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
|
||||||
Entity,
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
Column,
|
|
||||||
ManyToOne,
|
|
||||||
ManyToMany,
|
|
||||||
JoinTable,
|
|
||||||
OneToMany,
|
|
||||||
} from 'typeorm';
|
|
||||||
import { SpaceModelEntity } from './space-model.entity';
|
|
||||||
import { NewTagEntity } from '../../tag/entities/tag.entity';
|
|
||||||
import { ProductEntity } from '../../product/entities/product.entity';
|
import { ProductEntity } from '../../product/entities/product.entity';
|
||||||
import { SpaceProductAllocationEntity } from '../../space/entities/space-product-allocation.entity';
|
import { SpaceProductAllocationEntity } from '../../space/entities/space-product-allocation.entity';
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { NewTagEntity } from '../../tag/entities/tag.entity';
|
||||||
|
import { SpaceModelEntity } from './space-model.entity';
|
||||||
|
|
||||||
@Entity({ name: 'space_model_product_allocation' })
|
@Entity({ name: 'space_model_product_allocation' })
|
||||||
|
@Unique(['spaceModel', 'product', 'tag'])
|
||||||
export class SpaceModelProductAllocationEntity extends AbstractEntity<SpaceModelProductAllocationEntity> {
|
export class SpaceModelProductAllocationEntity extends AbstractEntity<SpaceModelProductAllocationEntity> {
|
||||||
@Column({
|
@Column({
|
||||||
type: 'uuid',
|
type: 'uuid',
|
||||||
@ -31,9 +25,8 @@ export class SpaceModelProductAllocationEntity extends AbstractEntity<SpaceModel
|
|||||||
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
|
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
|
||||||
public product: ProductEntity;
|
public product: ProductEntity;
|
||||||
|
|
||||||
@ManyToMany(() => NewTagEntity, { cascade: true, onDelete: 'CASCADE' })
|
@ManyToOne(() => NewTagEntity, { nullable: true, onDelete: 'CASCADE' })
|
||||||
@JoinTable({ name: 'space_model_product_tags' })
|
public tag: NewTagEntity;
|
||||||
public tags: NewTagEntity[];
|
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
() => SpaceProductAllocationEntity,
|
() => SpaceProductAllocationEntity,
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Entity, Column, OneToMany, ManyToOne, JoinColumn } from 'typeorm';
|
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
import { SpaceModelDto } from '../dtos';
|
|
||||||
import { SubspaceModelEntity } from './subspace-model';
|
|
||||||
import { ProjectEntity } from '../../project/entities';
|
import { ProjectEntity } from '../../project/entities';
|
||||||
import { TagModel } from './tag-model.entity';
|
|
||||||
import { SpaceModelProductAllocationEntity } from './space-model-product-allocation.entity';
|
|
||||||
import { SpaceEntity } from '../../space/entities/space.entity';
|
import { SpaceEntity } from '../../space/entities/space.entity';
|
||||||
|
import { SpaceModelDto } from '../dtos';
|
||||||
|
import { SpaceModelProductAllocationEntity } from './space-model-product-allocation.entity';
|
||||||
|
import { SubspaceModelEntity } from './subspace-model';
|
||||||
|
|
||||||
@Entity({ name: 'space-model' })
|
@Entity({ name: 'space-model' })
|
||||||
export class SpaceModelEntity extends AbstractEntity<SpaceModelDto> {
|
export class SpaceModelEntity extends AbstractEntity<SpaceModelDto> {
|
||||||
@ -49,9 +48,6 @@ export class SpaceModelEntity extends AbstractEntity<SpaceModelDto> {
|
|||||||
})
|
})
|
||||||
public spaces: SpaceEntity[];
|
public spaces: SpaceEntity[];
|
||||||
|
|
||||||
@OneToMany(() => TagModel, (tag) => tag.spaceModel)
|
|
||||||
tags: TagModel[];
|
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
() => SpaceModelProductAllocationEntity,
|
() => SpaceModelProductAllocationEntity,
|
||||||
(allocation) => allocation.spaceModel,
|
(allocation) => allocation.spaceModel,
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { Entity, Column, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
|
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||||
import { SubspaceModelEntity } from './subspace-model.entity';
|
|
||||||
import { ProductEntity } from '@app/common/modules/product/entities/product.entity';
|
import { ProductEntity } from '@app/common/modules/product/entities/product.entity';
|
||||||
import { NewTagEntity } from '@app/common/modules/tag/entities/tag.entity';
|
import { NewTagEntity } from '@app/common/modules/tag/entities/tag.entity';
|
||||||
|
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
|
||||||
import { SubspaceModelProductAllocationDto } from '../../dtos/subspace-model/subspace-model-product-allocation.dto';
|
import { SubspaceModelProductAllocationDto } from '../../dtos/subspace-model/subspace-model-product-allocation.dto';
|
||||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
import { SubspaceModelEntity } from './subspace-model.entity';
|
||||||
|
|
||||||
@Entity({ name: 'subspace_model_product_allocation' })
|
@Entity({ name: 'subspace_model_product_allocation' })
|
||||||
|
@Unique(['subspaceModel', 'product', 'tag'])
|
||||||
export class SubspaceModelProductAllocationEntity extends AbstractEntity<SubspaceModelProductAllocationDto> {
|
export class SubspaceModelProductAllocationEntity extends AbstractEntity<SubspaceModelProductAllocationDto> {
|
||||||
@Column({
|
@Column({
|
||||||
type: 'uuid',
|
type: 'uuid',
|
||||||
@ -27,12 +28,8 @@ export class SubspaceModelProductAllocationEntity extends AbstractEntity<Subspac
|
|||||||
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
|
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
|
||||||
public product: ProductEntity;
|
public product: ProductEntity;
|
||||||
|
|
||||||
@ManyToMany(() => NewTagEntity, (tag) => tag.subspaceModelAllocations, {
|
@ManyToOne(() => NewTagEntity, { nullable: true, onDelete: 'CASCADE' })
|
||||||
cascade: true,
|
public tag: NewTagEntity;
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinTable({ name: 'subspace_model_product_tags' })
|
|
||||||
public tags: NewTagEntity[];
|
|
||||||
|
|
||||||
constructor(partial: Partial<SubspaceModelProductAllocationEntity>) {
|
constructor(partial: Partial<SubspaceModelProductAllocationEntity>) {
|
||||||
super();
|
super();
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||||
|
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
||||||
import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
|
import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
|
||||||
import { SubSpaceModelDto } from '../../dtos';
|
import { SubSpaceModelDto } from '../../dtos';
|
||||||
import { SpaceModelEntity } from '../space-model.entity';
|
import { SpaceModelEntity } from '../space-model.entity';
|
||||||
import { TagModel } from '../tag-model.entity';
|
|
||||||
import { SubspaceModelProductAllocationEntity } from './subspace-model-product-allocation.entity';
|
import { SubspaceModelProductAllocationEntity } from './subspace-model-product-allocation.entity';
|
||||||
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
|
||||||
|
|
||||||
@Entity({ name: 'subspace-model' })
|
@Entity({ name: 'subspace-model' })
|
||||||
export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
|
export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
|
||||||
@ -41,9 +40,6 @@ export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
|
|||||||
})
|
})
|
||||||
public disabled: boolean;
|
public disabled: boolean;
|
||||||
|
|
||||||
@OneToMany(() => TagModel, (tag) => tag.subspaceModel)
|
|
||||||
tags: TagModel[];
|
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
() => SubspaceModelProductAllocationEntity,
|
() => SubspaceModelProductAllocationEntity,
|
||||||
(allocation) => allocation.subspaceModel,
|
(allocation) => allocation.subspaceModel,
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
|
||||||
import { TagModelDto } from '../dtos/tag-model.dto';
|
|
||||||
import { SpaceModelEntity } from './space-model.entity';
|
|
||||||
import { SubspaceModelEntity } from './subspace-model';
|
|
||||||
import { ProductEntity } from '../../product/entities';
|
|
||||||
import { TagEntity } from '../../space/entities/tag.entity';
|
|
||||||
|
|
||||||
@Entity({ name: 'tag_model' })
|
|
||||||
export class TagModel extends AbstractEntity<TagModelDto> {
|
|
||||||
@Column({ type: 'varchar', length: 255 })
|
|
||||||
tag: string;
|
|
||||||
|
|
||||||
@ManyToOne(() => ProductEntity, (product) => product.tagModels, {
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
@JoinColumn({ name: 'product_id' })
|
|
||||||
product: ProductEntity;
|
|
||||||
|
|
||||||
@ManyToOne(() => SpaceModelEntity, (space) => space.tags, { nullable: true })
|
|
||||||
@JoinColumn({ name: 'space_model_id' })
|
|
||||||
spaceModel: SpaceModelEntity;
|
|
||||||
|
|
||||||
@ManyToOne(() => SubspaceModelEntity, (subspace) => subspace.tags, {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
@JoinColumn({ name: 'subspace_model_id' })
|
|
||||||
subspaceModel: SubspaceModelEntity;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
nullable: false,
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public disabled: boolean;
|
|
||||||
|
|
||||||
@OneToMany(() => TagEntity, (tag) => tag.model)
|
|
||||||
tags: TagEntity[];
|
|
||||||
}
|
|
@ -1,11 +1,10 @@
|
|||||||
import { DataSource, Repository } from 'typeorm';
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import {
|
import {
|
||||||
SpaceModelEntity,
|
SpaceModelEntity,
|
||||||
SpaceModelProductAllocationEntity,
|
SpaceModelProductAllocationEntity,
|
||||||
SubspaceModelEntity,
|
SubspaceModelEntity,
|
||||||
SubspaceModelProductAllocationEntity,
|
SubspaceModelProductAllocationEntity,
|
||||||
TagModel,
|
|
||||||
} from '../entities';
|
} from '../entities';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -21,13 +20,6 @@ export class SubspaceModelRepository extends Repository<SubspaceModelEntity> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class TagModelRepository extends Repository<TagModel> {
|
|
||||||
constructor(private dataSource: DataSource) {
|
|
||||||
super(TagModel, dataSource.createEntityManager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SpaceModelProductAllocationRepoitory extends Repository<SpaceModelProductAllocationEntity> {
|
export class SpaceModelProductAllocationRepoitory extends Repository<SpaceModelProductAllocationEntity> {
|
||||||
constructor(private dataSource: DataSource) {
|
constructor(private dataSource: DataSource) {
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
||||||
import { SpaceModelEntity, SubspaceModelEntity, TagModel } from './entities';
|
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { SpaceModelEntity, SubspaceModelEntity } from './entities';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [],
|
providers: [],
|
||||||
exports: [],
|
exports: [],
|
||||||
controllers: [],
|
controllers: [],
|
||||||
imports: [
|
imports: [TypeOrmModule.forFeature([SpaceModelEntity, SubspaceModelEntity])],
|
||||||
TypeOrmModule.forFeature([SpaceModelEntity, SubspaceModelEntity, TagModel]),
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class SpaceModelRepositoryModule {}
|
export class SpaceModelRepositoryModule {}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { Entity, Column, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
|
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
|
||||||
import { SpaceEntity } from './space.entity';
|
|
||||||
import { SpaceModelProductAllocationEntity } from '../../space-model/entities/space-model-product-allocation.entity';
|
|
||||||
import { ProductEntity } from '../../product/entities/product.entity';
|
|
||||||
import { NewTagEntity } from '../../tag/entities/tag.entity';
|
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
|
import { ProductEntity } from '../../product/entities/product.entity';
|
||||||
|
import { SpaceModelProductAllocationEntity } from '../../space-model/entities/space-model-product-allocation.entity';
|
||||||
|
import { NewTagEntity } from '../../tag/entities/tag.entity';
|
||||||
import { SpaceProductAllocationDto } from '../dtos/space-product-allocation.dto';
|
import { SpaceProductAllocationDto } from '../dtos/space-product-allocation.dto';
|
||||||
|
import { SpaceEntity } from './space.entity';
|
||||||
|
|
||||||
@Entity({ name: 'space_product_allocation' })
|
@Entity({ name: 'space_product_allocation' })
|
||||||
|
@Unique(['space', 'product', 'tag'], {})
|
||||||
export class SpaceProductAllocationEntity extends AbstractEntity<SpaceProductAllocationDto> {
|
export class SpaceProductAllocationEntity extends AbstractEntity<SpaceProductAllocationDto> {
|
||||||
@Column({
|
@Column({
|
||||||
type: 'uuid',
|
type: 'uuid',
|
||||||
@ -30,9 +31,8 @@ export class SpaceProductAllocationEntity extends AbstractEntity<SpaceProductAll
|
|||||||
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
|
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
|
||||||
public product: ProductEntity;
|
public product: ProductEntity;
|
||||||
|
|
||||||
@ManyToMany(() => NewTagEntity)
|
@ManyToOne(() => NewTagEntity, { nullable: true, onDelete: 'CASCADE' })
|
||||||
@JoinTable({ name: 'space_product_tags' })
|
public tag: NewTagEntity;
|
||||||
public tags: NewTagEntity[];
|
|
||||||
|
|
||||||
constructor(partial: Partial<SpaceProductAllocationEntity>) {
|
constructor(partial: Partial<SpaceProductAllocationEntity>) {
|
||||||
super();
|
super();
|
||||||
|
@ -1,20 +1,13 @@
|
|||||||
import {
|
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||||
Entity,
|
|
||||||
Column,
|
|
||||||
ManyToOne,
|
|
||||||
ManyToMany,
|
|
||||||
JoinTable,
|
|
||||||
Unique,
|
|
||||||
} from 'typeorm';
|
|
||||||
import { SubspaceEntity } from './subspace.entity';
|
|
||||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
import { ProductEntity } from '@app/common/modules/product/entities';
|
||||||
import { SubspaceModelProductAllocationEntity } from '@app/common/modules/space-model';
|
import { SubspaceModelProductAllocationEntity } from '@app/common/modules/space-model';
|
||||||
import { NewTagEntity } from '@app/common/modules/tag/entities/tag.entity';
|
import { NewTagEntity } from '@app/common/modules/tag/entities/tag.entity';
|
||||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
|
||||||
import { SubspaceProductAllocationDto } from '../../dtos/subspace-product-allocation.dto';
|
import { SubspaceProductAllocationDto } from '../../dtos/subspace-product-allocation.dto';
|
||||||
|
import { SubspaceEntity } from './subspace.entity';
|
||||||
|
|
||||||
@Entity({ name: 'subspace_product_allocation' })
|
@Entity({ name: 'subspace_product_allocation' })
|
||||||
// @Unique(['subspace', 'product'])
|
@Unique(['subspace', 'product', 'tag'])
|
||||||
export class SubspaceProductAllocationEntity extends AbstractEntity<SubspaceProductAllocationDto> {
|
export class SubspaceProductAllocationEntity extends AbstractEntity<SubspaceProductAllocationDto> {
|
||||||
@Column({
|
@Column({
|
||||||
type: 'uuid',
|
type: 'uuid',
|
||||||
@ -38,9 +31,8 @@ export class SubspaceProductAllocationEntity extends AbstractEntity<SubspaceProd
|
|||||||
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
|
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
|
||||||
public product: ProductEntity;
|
public product: ProductEntity;
|
||||||
|
|
||||||
@ManyToMany(() => NewTagEntity)
|
@ManyToOne(() => NewTagEntity, { nullable: true, onDelete: 'CASCADE' })
|
||||||
@JoinTable({ name: 'subspace_product_tags' })
|
public tag: NewTagEntity;
|
||||||
public tags: NewTagEntity[];
|
|
||||||
|
|
||||||
constructor(partial: Partial<SubspaceProductAllocationEntity>) {
|
constructor(partial: Partial<SubspaceProductAllocationEntity>) {
|
||||||
super();
|
super();
|
||||||
|
@ -4,7 +4,6 @@ import { SubspaceModelEntity } from '@app/common/modules/space-model';
|
|||||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||||
import { SubspaceDto } from '../../dtos';
|
import { SubspaceDto } from '../../dtos';
|
||||||
import { SpaceEntity } from '../space.entity';
|
import { SpaceEntity } from '../space.entity';
|
||||||
import { TagEntity } from '../tag.entity';
|
|
||||||
import { SubspaceProductAllocationEntity } from './subspace-product-allocation.entity';
|
import { SubspaceProductAllocationEntity } from './subspace-product-allocation.entity';
|
||||||
|
|
||||||
@Entity({ name: 'subspace' })
|
@Entity({ name: 'subspace' })
|
||||||
@ -43,9 +42,6 @@ export class SubspaceEntity extends AbstractEntity<SubspaceDto> {
|
|||||||
})
|
})
|
||||||
subSpaceModel?: SubspaceModelEntity;
|
subSpaceModel?: SubspaceModelEntity;
|
||||||
|
|
||||||
@OneToMany(() => TagEntity, (tag) => tag.subspace)
|
|
||||||
tags: TagEntity[];
|
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
() => SubspaceProductAllocationEntity,
|
() => SubspaceProductAllocationEntity,
|
||||||
(allocation) => allocation.subspace,
|
(allocation) => allocation.subspace,
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
import { Entity, Column, ManyToOne, JoinColumn, OneToOne } from 'typeorm';
|
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
|
||||||
import { ProductEntity } from '../../product/entities';
|
|
||||||
import { TagDto } from '../dtos';
|
|
||||||
import { TagModel } from '../../space-model/entities/tag-model.entity';
|
|
||||||
import { DeviceEntity } from '../../device/entities';
|
|
||||||
import { SubspaceEntity } from './subspace/subspace.entity';
|
|
||||||
|
|
||||||
@Entity({ name: 'tag' })
|
|
||||||
export class TagEntity extends AbstractEntity<TagDto> {
|
|
||||||
@Column({ type: 'varchar', length: 255, nullable: true })
|
|
||||||
tag: string;
|
|
||||||
|
|
||||||
@ManyToOne(() => TagModel, (model) => model.tags, {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
model: TagModel;
|
|
||||||
|
|
||||||
@ManyToOne(() => ProductEntity, (product) => product.tags, {
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
product: ProductEntity;
|
|
||||||
|
|
||||||
@ManyToOne(() => SubspaceEntity, (subspace) => subspace.tags, {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
@JoinColumn({ name: 'subspace_id' })
|
|
||||||
subspace: SubspaceEntity;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
nullable: false,
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public disabled: boolean;
|
|
||||||
|
|
||||||
@OneToOne(() => DeviceEntity, (device) => device.tag, {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
@JoinColumn({ name: 'device_id' })
|
|
||||||
device: DeviceEntity;
|
|
||||||
}
|
|
@ -1,10 +1,9 @@
|
|||||||
import { DataSource, Repository } from 'typeorm';
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import { InviteSpaceEntity } from '../entities/invite-space.entity';
|
import { InviteSpaceEntity } from '../entities/invite-space.entity';
|
||||||
import { SpaceLinkEntity } from '../entities/space-link.entity';
|
import { SpaceLinkEntity } from '../entities/space-link.entity';
|
||||||
import { SpaceEntity } from '../entities/space.entity';
|
|
||||||
import { TagEntity } from '../entities/tag.entity';
|
|
||||||
import { SpaceProductAllocationEntity } from '../entities/space-product-allocation.entity';
|
import { SpaceProductAllocationEntity } from '../entities/space-product-allocation.entity';
|
||||||
|
import { SpaceEntity } from '../entities/space.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SpaceRepository extends Repository<SpaceEntity> {
|
export class SpaceRepository extends Repository<SpaceEntity> {
|
||||||
@ -20,13 +19,6 @@ export class SpaceLinkRepository extends Repository<SpaceLinkEntity> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class TagRepository extends Repository<TagEntity> {
|
|
||||||
constructor(private dataSource: DataSource) {
|
|
||||||
super(TagEntity, dataSource.createEntityManager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class InviteSpaceRepository extends Repository<InviteSpaceEntity> {
|
export class InviteSpaceRepository extends Repository<InviteSpaceEntity> {
|
||||||
constructor(private dataSource: DataSource) {
|
constructor(private dataSource: DataSource) {
|
||||||
|
@ -6,7 +6,6 @@ import { SpaceProductAllocationEntity } from './entities/space-product-allocatio
|
|||||||
import { SpaceEntity } from './entities/space.entity';
|
import { SpaceEntity } from './entities/space.entity';
|
||||||
import { SubspaceProductAllocationEntity } from './entities/subspace/subspace-product-allocation.entity';
|
import { SubspaceProductAllocationEntity } from './entities/subspace/subspace-product-allocation.entity';
|
||||||
import { SubspaceEntity } from './entities/subspace/subspace.entity';
|
import { SubspaceEntity } from './entities/subspace/subspace.entity';
|
||||||
import { TagEntity } from './entities/tag.entity';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [],
|
providers: [],
|
||||||
@ -16,7 +15,6 @@ import { TagEntity } from './entities/tag.entity';
|
|||||||
TypeOrmModule.forFeature([
|
TypeOrmModule.forFeature([
|
||||||
SpaceEntity,
|
SpaceEntity,
|
||||||
SubspaceEntity,
|
SubspaceEntity,
|
||||||
TagEntity,
|
|
||||||
InviteSpaceEntity,
|
InviteSpaceEntity,
|
||||||
SpaceProductAllocationEntity,
|
SpaceProductAllocationEntity,
|
||||||
SubspaceProductAllocationEntity,
|
SubspaceProductAllocationEntity,
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Entity, Column, ManyToOne, Unique, ManyToMany } from 'typeorm';
|
import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
|
||||||
import { ProductEntity } from '../../product/entities';
|
|
||||||
import { ProjectEntity } from '../../project/entities';
|
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
import { NewTagDto } from '../dtos/tag.dto';
|
import { DeviceEntity } from '../../device/entities/device.entity';
|
||||||
|
import { ProjectEntity } from '../../project/entities';
|
||||||
import { SpaceModelProductAllocationEntity } from '../../space-model/entities/space-model-product-allocation.entity';
|
import { SpaceModelProductAllocationEntity } from '../../space-model/entities/space-model-product-allocation.entity';
|
||||||
import { SubspaceModelProductAllocationEntity } from '../../space-model/entities/subspace-model/subspace-model-product-allocation.entity';
|
import { SubspaceModelProductAllocationEntity } from '../../space-model/entities/subspace-model/subspace-model-product-allocation.entity';
|
||||||
import { DeviceEntity } from '../../device/entities/device.entity';
|
import { NewTagDto } from '../dtos/tag.dto';
|
||||||
|
|
||||||
@Entity({ name: 'new_tag' })
|
@Entity({ name: 'new_tag' })
|
||||||
@Unique(['name', 'project'])
|
@Unique(['name', 'project'])
|
||||||
@ -24,31 +23,25 @@ export class NewTagEntity extends AbstractEntity<NewTagDto> {
|
|||||||
})
|
})
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@ManyToOne(() => ProductEntity, (product) => product.newTags, {
|
|
||||||
nullable: true,
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
public product: ProductEntity;
|
|
||||||
|
|
||||||
@ManyToOne(() => ProjectEntity, (project) => project.tags, {
|
@ManyToOne(() => ProjectEntity, (project) => project.tags, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
public project: ProjectEntity;
|
public project: ProjectEntity;
|
||||||
|
|
||||||
@ManyToMany(
|
@OneToMany(
|
||||||
() => SpaceModelProductAllocationEntity,
|
() => SpaceModelProductAllocationEntity,
|
||||||
(allocation) => allocation.tags,
|
(allocation) => allocation.tag,
|
||||||
)
|
)
|
||||||
public spaceModelAllocations: SpaceModelProductAllocationEntity[];
|
public spaceModelAllocations: SpaceModelProductAllocationEntity[];
|
||||||
|
|
||||||
@ManyToMany(
|
@OneToMany(
|
||||||
() => SubspaceModelProductAllocationEntity,
|
() => SubspaceModelProductAllocationEntity,
|
||||||
(allocation) => allocation.tags,
|
(allocation) => allocation.tag,
|
||||||
)
|
)
|
||||||
public subspaceModelAllocations: SubspaceModelProductAllocationEntity[];
|
public subspaceModelAllocations: SubspaceModelProductAllocationEntity[];
|
||||||
|
|
||||||
@ManyToOne(() => DeviceEntity, (device) => device.tag)
|
@OneToMany(() => DeviceEntity, (device) => device.tag)
|
||||||
public devices: DeviceEntity[];
|
public devices: DeviceEntity[];
|
||||||
|
|
||||||
constructor(partial: Partial<NewTagEntity>) {
|
constructor(partial: Partial<NewTagEntity>) {
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"format": "prettier --write \"apps/**/*.ts\" \"libs/**/*.ts\"",
|
"format": "prettier --write \"apps/**/*.ts\" \"libs/**/*.ts\"",
|
||||||
"start": "npm run test && node dist/main",
|
"start": "npm run test && node dist/main",
|
||||||
"start:dev": "npm run test && npx nest start --watch",
|
"start:dev": "npm run test && npx nest start --watch",
|
||||||
|
"dev": "npx nest start --watch",
|
||||||
"start:debug": "npm run test && npx nest start --debug --watch",
|
"start:debug": "npm run test && npx nest start --debug --watch",
|
||||||
"start:prod": "npm run test && node dist/main",
|
"start:prod": "npm run test && node dist/main",
|
||||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||||
|
@ -1,45 +1,44 @@
|
|||||||
|
import { SeederModule } from '@app/common/seed/seeder.module';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import config from './config';
|
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||||
|
import { WinstonModule } from 'nest-winston';
|
||||||
import { AuthenticationModule } from './auth/auth.module';
|
import { AuthenticationModule } from './auth/auth.module';
|
||||||
import { UserModule } from './users/user.module';
|
|
||||||
import { GroupModule } from './group/group.module';
|
|
||||||
import { DeviceModule } from './device/device.module';
|
|
||||||
import { UserDevicePermissionModule } from './user-device-permission/user-device-permission.module';
|
|
||||||
import { CommunityModule } from './community/community.module';
|
|
||||||
import { SeederModule } from '@app/common/seed/seeder.module';
|
|
||||||
import { UserNotificationModule } from './user-notification/user-notification.module';
|
|
||||||
import { DeviceMessagesSubscriptionModule } from './device-messages/device-messages.module';
|
|
||||||
import { SceneModule } from './scene/scene.module';
|
|
||||||
import { DoorLockModule } from './door-lock/door.lock.module';
|
|
||||||
import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
|
|
||||||
import { LoggingInterceptor } from './interceptors/logging.interceptor';
|
|
||||||
import { AutomationModule } from './automation/automation.module';
|
import { AutomationModule } from './automation/automation.module';
|
||||||
import { RegionModule } from './region/region.module';
|
|
||||||
import { TimeZoneModule } from './timezone/timezone.module';
|
|
||||||
import { VisitorPasswordModule } from './vistor-password/visitor-password.module';
|
|
||||||
import { ScheduleModule } from './schedule/schedule.module';
|
|
||||||
import { SpaceModule } from './space/space.module';
|
|
||||||
import { ProductModule } from './product';
|
|
||||||
import { ProjectModule } from './project';
|
|
||||||
import { SpaceModelModule } from './space-model';
|
|
||||||
import { InviteUserModule } from './invite-user/invite-user.module';
|
|
||||||
import { PermissionModule } from './permission/permission.module';
|
|
||||||
import { RoleModule } from './role/role.module';
|
|
||||||
import { TermsConditionsModule } from './terms-conditions/terms-conditions.module';
|
|
||||||
import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
|
|
||||||
import { TagModule } from './tags/tags.module';
|
|
||||||
import { ClientModule } from './client/client.module';
|
import { ClientModule } from './client/client.module';
|
||||||
import { DeviceCommissionModule } from './commission-device/commission-device.module';
|
import { DeviceCommissionModule } from './commission-device/commission-device.module';
|
||||||
import { PowerClampModule } from './power-clamp/power-clamp.module';
|
import { CommunityModule } from './community/community.module';
|
||||||
import { WinstonModule } from 'nest-winston';
|
import config from './config';
|
||||||
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
|
import { DeviceMessagesSubscriptionModule } from './device-messages/device-messages.module';
|
||||||
|
import { DeviceModule } from './device/device.module';
|
||||||
|
import { DoorLockModule } from './door-lock/door.lock.module';
|
||||||
|
import { GroupModule } from './group/group.module';
|
||||||
import { HealthModule } from './health/health.module';
|
import { HealthModule } from './health/health.module';
|
||||||
|
import { LoggingInterceptor } from './interceptors/logging.interceptor';
|
||||||
|
import { InviteUserModule } from './invite-user/invite-user.module';
|
||||||
|
import { PermissionModule } from './permission/permission.module';
|
||||||
|
import { PowerClampModule } from './power-clamp/power-clamp.module';
|
||||||
|
import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
|
||||||
|
import { ProductModule } from './product';
|
||||||
|
import { ProjectModule } from './project';
|
||||||
|
import { RegionModule } from './region/region.module';
|
||||||
|
import { RoleModule } from './role/role.module';
|
||||||
|
import { SceneModule } from './scene/scene.module';
|
||||||
|
import { ScheduleModule } from './schedule/schedule.module';
|
||||||
|
import { SpaceModelModule } from './space-model';
|
||||||
|
import { SpaceModule } from './space/space.module';
|
||||||
|
import { TagModule } from './tags/tags.module';
|
||||||
|
import { TermsConditionsModule } from './terms-conditions/terms-conditions.module';
|
||||||
|
import { TimeZoneModule } from './timezone/timezone.module';
|
||||||
|
import { UserDevicePermissionModule } from './user-device-permission/user-device-permission.module';
|
||||||
|
import { UserNotificationModule } from './user-notification/user-notification.module';
|
||||||
|
import { UserModule } from './users/user.module';
|
||||||
|
import { VisitorPasswordModule } from './vistor-password/visitor-password.module';
|
||||||
|
|
||||||
import { winstonLoggerOptions } from '../libs/common/src/logger/services/winston.logger';
|
import { winstonLoggerOptions } from '../libs/common/src/logger/services/winston.logger';
|
||||||
|
import { AqiModule } from './aqi/aqi.module';
|
||||||
import { OccupancyModule } from './occupancy/occupancy.module';
|
import { OccupancyModule } from './occupancy/occupancy.module';
|
||||||
import { WeatherModule } from './weather/weather.module';
|
import { WeatherModule } from './weather/weather.module';
|
||||||
import { AqiModule } from './aqi/aqi.module';
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
import * as fs from 'fs';
|
|
||||||
import * as csv from 'csv-parser';
|
import * as csv from 'csv-parser';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
import { ProjectParam } from '@app/common/dto/project-param.dto';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { SpaceRepository } from '@app/common/modules/space';
|
||||||
|
import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities/space-product-allocation.entity';
|
||||||
|
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
|
||||||
|
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
||||||
|
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { DeviceService } from 'src/device/services';
|
import { DeviceService } from 'src/device/services';
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
|
||||||
import { SpaceRepository } from '@app/common/modules/space';
|
|
||||||
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
|
||||||
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|
||||||
import { ProjectParam } from '@app/common/dto/project-param.dto';
|
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeviceCommissionService {
|
export class DeviceCommissionService {
|
||||||
@ -118,7 +120,7 @@ export class DeviceCommissionService {
|
|||||||
where: { uuid: spaceId },
|
where: { uuid: spaceId },
|
||||||
relations: [
|
relations: [
|
||||||
'productAllocations',
|
'productAllocations',
|
||||||
'productAllocations.tags',
|
'productAllocations.tag',
|
||||||
'productAllocations.product',
|
'productAllocations.product',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -135,7 +137,7 @@ export class DeviceCommissionService {
|
|||||||
where: { uuid: subspaceId },
|
where: { uuid: subspaceId },
|
||||||
relations: [
|
relations: [
|
||||||
'productAllocations',
|
'productAllocations',
|
||||||
'productAllocations.tags',
|
'productAllocations.tag',
|
||||||
'productAllocations.product',
|
'productAllocations.product',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -151,19 +153,23 @@ export class DeviceCommissionService {
|
|||||||
subspace?.productAllocations || space.productAllocations;
|
subspace?.productAllocations || space.productAllocations;
|
||||||
|
|
||||||
const match = allocations
|
const match = allocations
|
||||||
.flatMap((pa) =>
|
.map(
|
||||||
(pa.tags || []).map((tag) => ({ product: pa.product, tag })),
|
({
|
||||||
|
product,
|
||||||
|
tag,
|
||||||
|
}:
|
||||||
|
| SpaceProductAllocationEntity
|
||||||
|
| SubspaceProductAllocationEntity) => ({ product, tag }),
|
||||||
)
|
)
|
||||||
.find(({ tag }) => tag.name === tagName);
|
.find(
|
||||||
|
({ tag, product }) =>
|
||||||
|
tag.name === tagName && product.name === productName,
|
||||||
|
);
|
||||||
|
|
||||||
if (!match) {
|
if (!match) {
|
||||||
console.error(`No matching tag found for Device ID: ${rawDeviceId}`);
|
console.error(
|
||||||
failureCount.value++;
|
`No matching tag-product combination found for Device ID: ${rawDeviceId}`,
|
||||||
return;
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (match.product.name !== productName) {
|
|
||||||
console.error(`Product name mismatch for Device ID: ${rawDeviceId}`);
|
|
||||||
failureCount.value++;
|
failureCount.value++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import {
|
|||||||
SpaceLinkRepository,
|
SpaceLinkRepository,
|
||||||
SpaceProductAllocationRepository,
|
SpaceProductAllocationRepository,
|
||||||
SpaceRepository,
|
SpaceRepository,
|
||||||
TagRepository,
|
|
||||||
} from '@app/common/modules/space/repositories';
|
} from '@app/common/modules/space/repositories';
|
||||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
||||||
import { UserRepositoryModule } from '@app/common/modules/user/user.repository.module';
|
import { UserRepositoryModule } from '@app/common/modules/user/user.repository.module';
|
||||||
@ -87,6 +86,7 @@ import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|||||||
SpaceProductAllocationService,
|
SpaceProductAllocationService,
|
||||||
SpaceLinkRepository,
|
SpaceLinkRepository,
|
||||||
SubspaceRepository,
|
SubspaceRepository,
|
||||||
|
// Todo: find out why this is needed
|
||||||
TagService,
|
TagService,
|
||||||
SubspaceDeviceService,
|
SubspaceDeviceService,
|
||||||
SubspaceProductAllocationService,
|
SubspaceProductAllocationService,
|
||||||
@ -98,7 +98,6 @@ import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|||||||
SpaceModelProductAllocationService,
|
SpaceModelProductAllocationService,
|
||||||
SpaceProductAllocationRepository,
|
SpaceProductAllocationRepository,
|
||||||
SubspaceProductAllocationRepository,
|
SubspaceProductAllocationRepository,
|
||||||
TagRepository,
|
|
||||||
SubspaceModelRepository,
|
SubspaceModelRepository,
|
||||||
SubspaceModelProductAllocationService,
|
SubspaceModelProductAllocationService,
|
||||||
SpaceModelProductAllocationRepoitory,
|
SpaceModelProductAllocationRepoitory,
|
||||||
|
@ -1,29 +1,30 @@
|
|||||||
import {
|
import { ORPHAN_COMMUNITY_NAME } from '@app/common/constants/orphan-constant';
|
||||||
Injectable,
|
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
|
||||||
NotFoundException,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { AddCommunityDto, GetCommunityParams, ProjectParam } from '../dtos';
|
|
||||||
import { UpdateCommunityNameDto } from '../dtos/update.community.dto';
|
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
import {
|
import {
|
||||||
ExtendedTypeORMCustomModelFindAllQuery,
|
ExtendedTypeORMCustomModelFindAllQuery,
|
||||||
TypeORMCustomModel,
|
TypeORMCustomModel,
|
||||||
} from '@app/common/models/typeOrmCustom.model';
|
} from '@app/common/models/typeOrmCustom.model';
|
||||||
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
|
||||||
import { CommunityDto } from '@app/common/modules/community/dtos';
|
import { CommunityDto } from '@app/common/modules/community/dtos';
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
import { CommunityEntity } from '@app/common/modules/community/entities';
|
||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|
||||||
import { ORPHAN_COMMUNITY_NAME } from '@app/common/constants/orphan-constant';
|
|
||||||
import { ILike, In, Not } from 'typeorm';
|
|
||||||
import { SpaceService } from 'src/space/services';
|
|
||||||
import { SpaceRepository } from '@app/common/modules/space';
|
|
||||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
import { DeviceEntity } from '@app/common/modules/device/entities';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { SpaceRepository } from '@app/common/modules/space';
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
import { addSpaceUuidToDevices } from '@app/common/util/device-utils';
|
import { addSpaceUuidToDevices } from '@app/common/util/device-utils';
|
||||||
|
import {
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
|
Injectable,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { SpaceService } from 'src/space/services';
|
||||||
|
import { SelectQueryBuilder } from 'typeorm';
|
||||||
|
import { AddCommunityDto, GetCommunityParams, ProjectParam } from '../dtos';
|
||||||
|
import { UpdateCommunityNameDto } from '../dtos/update.community.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CommunityService {
|
export class CommunityService {
|
||||||
@ -93,56 +94,35 @@ export class CommunityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getCommunities(
|
async getCommunities(
|
||||||
param: ProjectParam,
|
{ projectUuid }: ProjectParam,
|
||||||
pageable: Partial<ExtendedTypeORMCustomModelFindAllQuery>,
|
pageable: Partial<ExtendedTypeORMCustomModelFindAllQuery>,
|
||||||
): Promise<BaseResponseDto> {
|
): Promise<BaseResponseDto> {
|
||||||
try {
|
try {
|
||||||
const project = await this.validateProject(param.projectUuid);
|
const project = await this.validateProject(projectUuid);
|
||||||
|
|
||||||
pageable.modelName = 'community';
|
|
||||||
pageable.where = {
|
|
||||||
project: { uuid: param.projectUuid },
|
|
||||||
name: Not(`${ORPHAN_COMMUNITY_NAME}-${project.name}`),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: removing this breaks the code (should be fixed when refactoring @see TypeORMCustomModel
|
||||||
|
*/
|
||||||
|
pageable.where = {};
|
||||||
|
let qb: undefined | SelectQueryBuilder<CommunityEntity> = undefined;
|
||||||
if (pageable.search) {
|
if (pageable.search) {
|
||||||
const matchingCommunities = await this.communityRepository.find({
|
qb = this.communityRepository
|
||||||
where: {
|
.createQueryBuilder('c')
|
||||||
project: { uuid: param.projectUuid },
|
.leftJoin('c.spaces', 's')
|
||||||
name: ILike(`%${pageable.search}%`),
|
.where('c.project = :projectUuid', { projectUuid })
|
||||||
},
|
.andWhere(`c.name != '${ORPHAN_COMMUNITY_NAME}-${project.name}'`)
|
||||||
});
|
.andWhere('s.disabled = false')
|
||||||
|
.andWhere(
|
||||||
const matchingSpaces = await this.spaceRepository.find({
|
`c.name ILIKE '%${pageable.search}%' OR s.space_name ILIKE '%${pageable.search}%'`,
|
||||||
where: {
|
)
|
||||||
spaceName: ILike(`%${pageable.search}%`),
|
.distinct(true);
|
||||||
disabled: false,
|
|
||||||
community: { project: { uuid: param.projectUuid } },
|
|
||||||
},
|
|
||||||
relations: ['community'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const spaceCommunityUuids = [
|
|
||||||
...new Set(matchingSpaces.map((space) => space.community.uuid)),
|
|
||||||
];
|
|
||||||
|
|
||||||
const allMatchedCommunityUuids = [
|
|
||||||
...new Set([
|
|
||||||
...matchingCommunities.map((c) => c.uuid),
|
|
||||||
...spaceCommunityUuids,
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
|
|
||||||
pageable.where = {
|
|
||||||
...pageable.where,
|
|
||||||
uuid: In(allMatchedCommunityUuids),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
const customModel = TypeORMCustomModel(this.communityRepository);
|
const customModel = TypeORMCustomModel(this.communityRepository);
|
||||||
|
|
||||||
const { baseResponseDto, paginationResponseDto } =
|
const { baseResponseDto, paginationResponseDto } =
|
||||||
await customModel.findAll(pageable);
|
await customModel.findAll({ ...pageable, modelName: 'community' }, qb);
|
||||||
|
|
||||||
|
// todo: refactor this to minimize the number of queries
|
||||||
if (pageable.includeSpaces) {
|
if (pageable.includeSpaces) {
|
||||||
const communitiesWithSpaces = await Promise.all(
|
const communitiesWithSpaces = await Promise.all(
|
||||||
baseResponseDto.data.map(async (community: CommunityDto) => {
|
baseResponseDto.data.map(async (community: CommunityDto) => {
|
||||||
@ -150,7 +130,7 @@ export class CommunityService {
|
|||||||
await this.spaceService.getSpacesHierarchyForCommunity(
|
await this.spaceService.getSpacesHierarchyForCommunity(
|
||||||
{
|
{
|
||||||
communityUuid: community.uuid,
|
communityUuid: community.uuid,
|
||||||
projectUuid: param.projectUuid,
|
projectUuid: projectUuid,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onlyWithDevices: false,
|
onlyWithDevices: false,
|
||||||
|
@ -1,39 +1,46 @@
|
|||||||
import { ORPHAN_SPACE_NAME } from './../../../libs/common/src/constants/orphan-constant';
|
import { AUTOMATION_CONFIG } from '@app/common/constants/automation.enum';
|
||||||
import { ProductRepository } from './../../../libs/common/src/modules/product/repositories/product.repository';
|
import { BatchDeviceTypeEnum } from '@app/common/constants/batch-device.enum';
|
||||||
|
import { BatteryStatus } from '@app/common/constants/battery-status.enum';
|
||||||
|
import { DeviceStatuses } from '@app/common/constants/device-status.enum';
|
||||||
|
import { DeviceTypeEnum } from '@app/common/constants/device-type.enum';
|
||||||
|
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||||
|
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||||
|
import { SceneSwitchesTypeEnum } from '@app/common/constants/scene-switch-type.enum';
|
||||||
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
||||||
|
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||||
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
|
import { DeviceEntity } from '@app/common/modules/device/entities';
|
||||||
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { ProjectEntity } from '@app/common/modules/project/entities';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
|
import { addSpaceUuidToDevices } from '@app/common/util/device-utils';
|
||||||
import {
|
import {
|
||||||
Injectable,
|
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
|
||||||
NotFoundException,
|
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
Inject,
|
Inject,
|
||||||
|
Injectable,
|
||||||
|
NotFoundException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||||
|
import { AddAutomationDto } from 'src/automation/dtos';
|
||||||
|
import { SceneService } from 'src/scene/services';
|
||||||
|
import { In, Not, QueryRunner } from 'typeorm';
|
||||||
|
import { ProjectParam } from '../dtos';
|
||||||
import {
|
import {
|
||||||
AddDeviceDto,
|
AddDeviceDto,
|
||||||
AddSceneToFourSceneDeviceDto,
|
AddSceneToFourSceneDeviceDto,
|
||||||
UpdateDeviceDto,
|
|
||||||
AssignDeviceToSpaceDto,
|
AssignDeviceToSpaceDto,
|
||||||
|
UpdateDeviceDto,
|
||||||
} from '../dtos/add.device.dto';
|
} from '../dtos/add.device.dto';
|
||||||
import {
|
|
||||||
DeviceInstructionResponse,
|
|
||||||
GetDeviceDetailsFunctionsInterface,
|
|
||||||
GetDeviceDetailsFunctionsStatusInterface,
|
|
||||||
GetDeviceDetailsInterface,
|
|
||||||
GetMacAddressInterface,
|
|
||||||
GetPowerClampFunctionsStatusInterface,
|
|
||||||
controlDeviceInterface,
|
|
||||||
getDeviceLogsInterface,
|
|
||||||
updateDeviceFirmwareInterface,
|
|
||||||
} from '../interfaces/get.device.interface';
|
|
||||||
import {
|
|
||||||
GetDeviceBySpaceUuidDto,
|
|
||||||
GetDeviceLogsDto,
|
|
||||||
GetDevicesBySpaceOrCommunityDto,
|
|
||||||
GetDoorLockDevices,
|
|
||||||
} from '../dtos/get.device.dto';
|
|
||||||
import {
|
import {
|
||||||
BatchControlDevicesDto,
|
BatchControlDevicesDto,
|
||||||
BatchFactoryResetDevicesDto,
|
BatchFactoryResetDevicesDto,
|
||||||
@ -41,33 +48,29 @@ import {
|
|||||||
ControlDeviceDto,
|
ControlDeviceDto,
|
||||||
GetSceneFourSceneDeviceDto,
|
GetSceneFourSceneDeviceDto,
|
||||||
} from '../dtos/control.device.dto';
|
} from '../dtos/control.device.dto';
|
||||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
|
||||||
import { In, Not, QueryRunner } from 'typeorm';
|
|
||||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
|
||||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
|
||||||
import { DeviceStatuses } from '@app/common/constants/device-status.enum';
|
|
||||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
|
||||||
import { BatteryStatus } from '@app/common/constants/battery-status.enum';
|
|
||||||
import { SceneService } from 'src/scene/services';
|
|
||||||
import { AddAutomationDto } from 'src/automation/dtos';
|
|
||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
|
||||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
|
||||||
import { SceneSwitchesTypeEnum } from '@app/common/constants/scene-switch-type.enum';
|
|
||||||
import { AUTOMATION_CONFIG } from '@app/common/constants/automation.enum';
|
|
||||||
import { DeviceSceneParamDto } from '../dtos/device.param.dto';
|
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|
||||||
import { DeleteSceneFromSceneDeviceDto } from '../dtos/delete.device.dto';
|
import { DeleteSceneFromSceneDeviceDto } from '../dtos/delete.device.dto';
|
||||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
import { DeviceSceneParamDto } from '../dtos/device.param.dto';
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
import {
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
GetDeviceLogsDto,
|
||||||
import { ProjectParam } from '../dtos';
|
GetDevicesBySpaceOrCommunityDto,
|
||||||
import { BatchDeviceTypeEnum } from '@app/common/constants/batch-device.enum';
|
GetDoorLockDevices,
|
||||||
import { DeviceTypeEnum } from '@app/common/constants/device-type.enum';
|
} from '../dtos/get.device.dto';
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
import {
|
||||||
import { addSpaceUuidToDevices } from '@app/common/util/device-utils';
|
controlDeviceInterface,
|
||||||
|
DeviceInstructionResponse,
|
||||||
|
GetDeviceDetailsFunctionsInterface,
|
||||||
|
GetDeviceDetailsFunctionsStatusInterface,
|
||||||
|
GetDeviceDetailsInterface,
|
||||||
|
getDeviceLogsInterface,
|
||||||
|
GetMacAddressInterface,
|
||||||
|
GetPowerClampFunctionsStatusInterface,
|
||||||
|
updateDeviceFirmwareInterface,
|
||||||
|
} from '../interfaces/get.device.interface';
|
||||||
|
import {
|
||||||
|
ORPHAN_COMMUNITY_NAME,
|
||||||
|
ORPHAN_SPACE_NAME,
|
||||||
|
} from './../../../libs/common/src/constants/orphan-constant';
|
||||||
|
import { ProductRepository } from './../../../libs/common/src/modules/product/repositories/product.repository';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeviceService {
|
export class DeviceService {
|
||||||
@ -198,46 +201,6 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDevicesBySpaceId(
|
|
||||||
getDeviceBySpaceUuidDto: GetDeviceBySpaceUuidDto,
|
|
||||||
): Promise<GetDeviceDetailsInterface[]> {
|
|
||||||
try {
|
|
||||||
const devices = await this.deviceRepository.find({
|
|
||||||
where: {
|
|
||||||
spaceDevice: { uuid: getDeviceBySpaceUuidDto.spaceUuid },
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
relations: [
|
|
||||||
'spaceDevice',
|
|
||||||
'productDevice',
|
|
||||||
'permission',
|
|
||||||
'permission.permissionType',
|
|
||||||
],
|
|
||||||
});
|
|
||||||
const devicesData = await Promise.all(
|
|
||||||
devices.map(async (device) => {
|
|
||||||
return {
|
|
||||||
haveRoom: device.spaceDevice ? true : false,
|
|
||||||
productUuid: device.productDevice.uuid,
|
|
||||||
productType: device.productDevice.prodType,
|
|
||||||
permissionType: device.permission[0].permissionType.type,
|
|
||||||
...(await this.getDeviceDetailsByDeviceIdTuya(
|
|
||||||
device.deviceTuyaUuid,
|
|
||||||
)),
|
|
||||||
uuid: device.uuid,
|
|
||||||
} as GetDeviceDetailsInterface;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return devicesData;
|
|
||||||
} catch (error) {
|
|
||||||
// Handle the error here
|
|
||||||
throw new HttpException(
|
|
||||||
'Error fetching devices by space',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async transferDeviceInSpaces(
|
async transferDeviceInSpaces(
|
||||||
assignDeviceToSpaceDto: AssignDeviceToSpaceDto,
|
assignDeviceToSpaceDto: AssignDeviceToSpaceDto,
|
||||||
projectUuid: string,
|
projectUuid: string,
|
||||||
@ -1199,39 +1162,6 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFullSpaceHierarchy(
|
|
||||||
space: SpaceEntity,
|
|
||||||
): Promise<{ uuid: string; spaceName: string }[]> {
|
|
||||||
try {
|
|
||||||
// Fetch only the relevant spaces, starting with the target space
|
|
||||||
const targetSpace = await this.spaceRepository.findOne({
|
|
||||||
where: { uuid: space.uuid },
|
|
||||||
relations: ['parent', 'children'],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Fetch only the ancestors of the target space
|
|
||||||
const ancestors = await this.fetchAncestors(targetSpace);
|
|
||||||
|
|
||||||
// Optionally, fetch descendants if required
|
|
||||||
const descendants = await this.fetchDescendants(targetSpace);
|
|
||||||
|
|
||||||
const fullHierarchy = [...ancestors, targetSpace, ...descendants].map(
|
|
||||||
(space) => ({
|
|
||||||
uuid: space.uuid,
|
|
||||||
spaceName: space.spaceName,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return fullHierarchy;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching space hierarchy:', error.message);
|
|
||||||
throw new HttpException(
|
|
||||||
'Error fetching space hierarchy',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPowerClampInstructionStatus(deviceDetails: any) {
|
async getPowerClampInstructionStatus(deviceDetails: any) {
|
||||||
try {
|
try {
|
||||||
const deviceStatus = await this.getPowerClampInstructionStatusTuya(
|
const deviceStatus = await this.getPowerClampInstructionStatusTuya(
|
||||||
@ -1331,27 +1261,6 @@ export class DeviceService {
|
|||||||
return ancestors.reverse();
|
return ancestors.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchDescendants(space: SpaceEntity): Promise<SpaceEntity[]> {
|
|
||||||
const descendants: SpaceEntity[] = [];
|
|
||||||
|
|
||||||
// Fetch the immediate children of the current space
|
|
||||||
const children = await this.spaceRepository.find({
|
|
||||||
where: { parent: { uuid: space.uuid } },
|
|
||||||
relations: ['children'], // To continue fetching downwards
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const child of children) {
|
|
||||||
// Add the child to the descendants list
|
|
||||||
descendants.push(child);
|
|
||||||
|
|
||||||
// Recursively fetch the child's descendants
|
|
||||||
const childDescendants = await this.fetchDescendants(child);
|
|
||||||
descendants.push(...childDescendants);
|
|
||||||
}
|
|
||||||
|
|
||||||
return descendants;
|
|
||||||
}
|
|
||||||
|
|
||||||
async addSceneToSceneDevice(
|
async addSceneToSceneDevice(
|
||||||
deviceUuid: string,
|
deviceUuid: string,
|
||||||
addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto,
|
addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto,
|
||||||
@ -1654,22 +1563,6 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async moveDevicesToSpace(
|
|
||||||
targetSpace: SpaceEntity,
|
|
||||||
deviceIds: string[],
|
|
||||||
): Promise<void> {
|
|
||||||
if (!deviceIds || deviceIds.length === 0) {
|
|
||||||
throw new HttpException(
|
|
||||||
'No device IDs provided for transfer',
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.deviceRepository.update(
|
|
||||||
{ uuid: In(deviceIds) },
|
|
||||||
{ spaceDevice: targetSpace },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
async getDoorLockDevices(projectUuid: string) {
|
async getDoorLockDevices(projectUuid: string) {
|
||||||
await this.validateProject(projectUuid);
|
await this.validateProject(projectUuid);
|
||||||
|
|
||||||
@ -1860,4 +1753,39 @@ export class DeviceService {
|
|||||||
|
|
||||||
return allDevices;
|
return allDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async addDevicesToOrphanSpace(
|
||||||
|
space: SpaceEntity,
|
||||||
|
project: ProjectEntity,
|
||||||
|
queryRunner: QueryRunner,
|
||||||
|
) {
|
||||||
|
const spaceRepository = queryRunner.manager.getRepository(SpaceEntity);
|
||||||
|
const deviceRepository = queryRunner.manager.getRepository(DeviceEntity);
|
||||||
|
try {
|
||||||
|
const orphanSpace = await spaceRepository.findOne({
|
||||||
|
where: {
|
||||||
|
community: {
|
||||||
|
name: `${ORPHAN_COMMUNITY_NAME}-${project.name}`,
|
||||||
|
},
|
||||||
|
spaceName: ORPHAN_SPACE_NAME,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!orphanSpace) {
|
||||||
|
throw new HttpException(
|
||||||
|
`Orphan space not found in community ${project.name}`,
|
||||||
|
HttpStatus.NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await deviceRepository.update(
|
||||||
|
{ uuid: In(space.devices.map((device) => device.uuid)) },
|
||||||
|
{ spaceDevice: orphanSpace },
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to add devices to orphan spaces: ${error.message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,75 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { InviteUserService } from './services/invite-user.service';
|
|
||||||
import { InviteUserController } from './controllers/invite-user.controller';
|
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { InviteUserController } from './controllers/invite-user.controller';
|
||||||
|
import { InviteUserService } from './services/invite-user.service';
|
||||||
|
|
||||||
|
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
||||||
|
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
||||||
|
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
|
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
||||||
import {
|
import {
|
||||||
UserRepository,
|
DeviceRepository,
|
||||||
UserSpaceRepository,
|
DeviceUserPermissionRepository,
|
||||||
} from '@app/common/modules/user/repositories';
|
} from '@app/common/modules/device/repositories';
|
||||||
import { InviteUserRepositoryModule } from '@app/common/modules/Invite-user/Invite-user.repository.module';
|
import { InviteUserRepositoryModule } from '@app/common/modules/Invite-user/Invite-user.repository.module';
|
||||||
import {
|
import {
|
||||||
InviteUserRepository,
|
InviteUserRepository,
|
||||||
InviteUserSpaceRepository,
|
InviteUserSpaceRepository,
|
||||||
} from '@app/common/modules/Invite-user/repositiories';
|
} from '@app/common/modules/Invite-user/repositiories';
|
||||||
|
import { PermissionTypeRepository } from '@app/common/modules/permission/repositories';
|
||||||
|
import {
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||||
|
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
||||||
|
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||||
|
import {
|
||||||
|
SceneIconRepository,
|
||||||
|
SceneRepository,
|
||||||
|
} from '@app/common/modules/scene/repositories';
|
||||||
|
import {
|
||||||
|
InviteSpaceRepository,
|
||||||
|
SpaceLinkRepository,
|
||||||
|
SpaceProductAllocationRepository,
|
||||||
|
SpaceRepository,
|
||||||
|
} from '@app/common/modules/space';
|
||||||
|
import {
|
||||||
|
SpaceModelProductAllocationRepoitory,
|
||||||
|
SpaceModelRepository,
|
||||||
|
SubspaceModelProductAllocationRepoitory,
|
||||||
|
SubspaceModelRepository,
|
||||||
|
} from '@app/common/modules/space-model';
|
||||||
|
import {
|
||||||
|
SubspaceProductAllocationRepository,
|
||||||
|
SubspaceRepository,
|
||||||
|
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
|
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
||||||
|
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||||
|
import {
|
||||||
|
UserRepository,
|
||||||
|
UserSpaceRepository,
|
||||||
|
} from '@app/common/modules/user/repositories';
|
||||||
import { EmailService } from '@app/common/util/email.service';
|
import { EmailService } from '@app/common/util/email.service';
|
||||||
|
import { CommunityModule } from 'src/community/community.module';
|
||||||
|
import { CommunityService } from 'src/community/services';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
import { ProjectUserService } from 'src/project/services/project-user.service';
|
||||||
|
import { SceneService } from 'src/scene/services';
|
||||||
|
import {
|
||||||
|
SpaceModelService,
|
||||||
|
SubSpaceModelService,
|
||||||
|
} from 'src/space-model/services';
|
||||||
|
import { SpaceModelProductAllocationService } from 'src/space-model/services/space-model-product-allocation.service';
|
||||||
|
import { SubspaceModelProductAllocationService } from 'src/space-model/services/subspace/subspace-model-product-allocation.service';
|
||||||
import {
|
import {
|
||||||
SpaceLinkService,
|
SpaceLinkService,
|
||||||
SpaceService,
|
SpaceService,
|
||||||
@ -21,70 +78,11 @@ import {
|
|||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
ValidationService,
|
ValidationService,
|
||||||
} from 'src/space/services';
|
} from 'src/space/services';
|
||||||
import { CommunityService } from 'src/community/services';
|
|
||||||
import {
|
|
||||||
InviteSpaceRepository,
|
|
||||||
SpaceLinkRepository,
|
|
||||||
SpaceProductAllocationRepository,
|
|
||||||
SpaceRepository,
|
|
||||||
TagRepository,
|
|
||||||
} from '@app/common/modules/space';
|
|
||||||
import { SpaceModelRepository } from '@app/common/modules/space-model';
|
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|
||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
|
||||||
import { UserService, UserSpaceService } from 'src/users/services';
|
|
||||||
import { UserDevicePermissionService } from 'src/user-device-permission/services';
|
|
||||||
import {
|
|
||||||
DeviceRepository,
|
|
||||||
DeviceUserPermissionRepository,
|
|
||||||
} from '@app/common/modules/device/repositories';
|
|
||||||
import { PermissionTypeRepository } from '@app/common/modules/permission/repositories';
|
|
||||||
import { ProjectUserService } from 'src/project/services/project-user.service';
|
|
||||||
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
|
||||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
|
||||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
|
||||||
import { CommunityModule } from 'src/community/community.module';
|
|
||||||
import { TagService as NewTagService } from 'src/tags/services';
|
|
||||||
import { TagService } from 'src/space/services/tag';
|
|
||||||
import {
|
|
||||||
SpaceModelService,
|
|
||||||
SubSpaceModelService,
|
|
||||||
} from 'src/space-model/services';
|
|
||||||
import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service';
|
import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service';
|
||||||
import {
|
|
||||||
SubspaceProductAllocationRepository,
|
|
||||||
SubspaceRepository,
|
|
||||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
|
||||||
import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service';
|
import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service';
|
||||||
import {
|
import { TagService as NewTagService } from 'src/tags/services';
|
||||||
SpaceModelProductAllocationRepoitory,
|
import { UserDevicePermissionService } from 'src/user-device-permission/services';
|
||||||
SubspaceModelProductAllocationRepoitory,
|
import { UserService, UserSpaceService } from 'src/users/services';
|
||||||
SubspaceModelRepository,
|
|
||||||
} from '@app/common/modules/space-model';
|
|
||||||
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
|
||||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
|
||||||
import { SpaceModelProductAllocationService } from 'src/space-model/services/space-model-product-allocation.service';
|
|
||||||
import { SubspaceModelProductAllocationService } from 'src/space-model/services/subspace/subspace-model-product-allocation.service';
|
|
||||||
import { DeviceService } from 'src/device/services';
|
|
||||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
|
||||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
|
||||||
import { SceneService } from 'src/scene/services';
|
|
||||||
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
|
||||||
import {
|
|
||||||
SceneIconRepository,
|
|
||||||
SceneRepository,
|
|
||||||
} from '@app/common/modules/scene/repositories';
|
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
|
||||||
import {
|
|
||||||
PowerClampHourlyRepository,
|
|
||||||
PowerClampDailyRepository,
|
|
||||||
PowerClampMonthlyRepository,
|
|
||||||
} from '@app/common/modules/power-clamp/repositories';
|
|
||||||
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
|
||||||
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
|
||||||
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
|
||||||
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, InviteUserRepositoryModule, CommunityModule],
|
imports: [ConfigModule, InviteUserRepositoryModule, CommunityModule],
|
||||||
@ -125,7 +123,6 @@ import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|||||||
SpaceProductAllocationService,
|
SpaceProductAllocationService,
|
||||||
SpaceLinkRepository,
|
SpaceLinkRepository,
|
||||||
SubspaceRepository,
|
SubspaceRepository,
|
||||||
TagService,
|
|
||||||
SubspaceDeviceService,
|
SubspaceDeviceService,
|
||||||
SubspaceProductAllocationService,
|
SubspaceProductAllocationService,
|
||||||
SpaceModelRepository,
|
SpaceModelRepository,
|
||||||
@ -136,7 +133,6 @@ import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|||||||
SpaceModelProductAllocationService,
|
SpaceModelProductAllocationService,
|
||||||
SpaceProductAllocationRepository,
|
SpaceProductAllocationRepository,
|
||||||
SubspaceProductAllocationRepository,
|
SubspaceProductAllocationRepository,
|
||||||
TagRepository,
|
|
||||||
SubspaceModelRepository,
|
SubspaceModelRepository,
|
||||||
SubspaceModelProductAllocationService,
|
SubspaceModelProductAllocationService,
|
||||||
SpaceModelProductAllocationRepoitory,
|
SpaceModelProductAllocationRepoitory,
|
||||||
|
@ -1,13 +1,52 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
||||||
import { PowerClampService as PowerClamp } from './services/power-clamp.service';
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
import { PowerClampController } from './controllers';
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
|
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
||||||
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
import {
|
import {
|
||||||
PowerClampDailyRepository,
|
PowerClampDailyRepository,
|
||||||
PowerClampHourlyRepository,
|
PowerClampHourlyRepository,
|
||||||
PowerClampMonthlyRepository,
|
PowerClampMonthlyRepository,
|
||||||
} from '@app/common/modules/power-clamp/repositories';
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||||
|
import {
|
||||||
|
SceneIconRepository,
|
||||||
|
SceneRepository,
|
||||||
|
} from '@app/common/modules/scene/repositories';
|
||||||
|
import {
|
||||||
|
InviteSpaceRepository,
|
||||||
|
SpaceLinkRepository,
|
||||||
|
SpaceProductAllocationRepository,
|
||||||
|
SpaceRepository,
|
||||||
|
} from '@app/common/modules/space';
|
||||||
|
import {
|
||||||
|
SpaceModelProductAllocationRepoitory,
|
||||||
|
SpaceModelRepository,
|
||||||
|
SubspaceModelProductAllocationRepoitory,
|
||||||
|
SubspaceModelRepository,
|
||||||
|
} from '@app/common/modules/space-model';
|
||||||
|
import {
|
||||||
|
SubspaceProductAllocationRepository,
|
||||||
|
SubspaceRepository,
|
||||||
|
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
|
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { CommunityService } from 'src/community/services';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
import { SceneService } from 'src/scene/services';
|
||||||
|
import {
|
||||||
|
SpaceModelService,
|
||||||
|
SubSpaceModelService,
|
||||||
|
} from 'src/space-model/services';
|
||||||
|
import { SpaceModelProductAllocationService } from 'src/space-model/services/space-model-product-allocation.service';
|
||||||
|
import { SubspaceModelProductAllocationService } from 'src/space-model/services/subspace/subspace-model-product-allocation.service';
|
||||||
import {
|
import {
|
||||||
SpaceDeviceService,
|
SpaceDeviceService,
|
||||||
SpaceLinkService,
|
SpaceLinkService,
|
||||||
@ -16,51 +55,11 @@ import {
|
|||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
ValidationService,
|
ValidationService,
|
||||||
} from 'src/space/services';
|
} from 'src/space/services';
|
||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
|
||||||
import { DeviceService } from 'src/device/services';
|
|
||||||
import {
|
|
||||||
InviteSpaceRepository,
|
|
||||||
SpaceLinkRepository,
|
|
||||||
SpaceProductAllocationRepository,
|
|
||||||
SpaceRepository,
|
|
||||||
TagRepository,
|
|
||||||
} from '@app/common/modules/space';
|
|
||||||
import { CommunityService } from 'src/community/services';
|
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
|
||||||
import {
|
|
||||||
SpaceModelProductAllocationRepoitory,
|
|
||||||
SpaceModelRepository,
|
|
||||||
SubspaceModelProductAllocationRepoitory,
|
|
||||||
SubspaceModelRepository,
|
|
||||||
} from '@app/common/modules/space-model';
|
|
||||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
|
||||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
|
||||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
|
||||||
import { SceneService } from 'src/scene/services';
|
|
||||||
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
|
||||||
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
|
||||||
import {
|
|
||||||
SceneIconRepository,
|
|
||||||
SceneRepository,
|
|
||||||
} from '@app/common/modules/scene/repositories';
|
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
|
||||||
import { TagService } from 'src/tags/services';
|
|
||||||
import {
|
|
||||||
SpaceModelService,
|
|
||||||
SubSpaceModelService,
|
|
||||||
} from 'src/space-model/services';
|
|
||||||
import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service';
|
import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service';
|
||||||
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
|
||||||
import {
|
|
||||||
SubspaceProductAllocationRepository,
|
|
||||||
SubspaceRepository,
|
|
||||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
|
||||||
import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service';
|
import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service';
|
||||||
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
import { TagService } from 'src/tags/services';
|
||||||
import { SpaceModelProductAllocationService } from 'src/space-model/services/space-model-product-allocation.service';
|
import { PowerClampController } from './controllers';
|
||||||
import { SubspaceModelProductAllocationService } from 'src/space-model/services/subspace/subspace-model-product-allocation.service';
|
import { PowerClampService as PowerClamp } from './services/power-clamp.service';
|
||||||
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
|
||||||
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
@ -106,7 +105,6 @@ import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|||||||
SpaceModelProductAllocationService,
|
SpaceModelProductAllocationService,
|
||||||
SpaceProductAllocationRepository,
|
SpaceProductAllocationRepository,
|
||||||
SubspaceProductAllocationRepository,
|
SubspaceProductAllocationRepository,
|
||||||
TagRepository,
|
|
||||||
SubspaceModelRepository,
|
SubspaceModelRepository,
|
||||||
SubspaceModelProductAllocationService,
|
SubspaceModelProductAllocationService,
|
||||||
SpaceModelProductAllocationRepoitory,
|
SpaceModelProductAllocationRepoitory,
|
||||||
|
@ -1,24 +1,58 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
||||||
import { CqrsModule } from '@nestjs/cqrs';
|
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
||||||
import { ProjectController } from './controllers';
|
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
||||||
import { ProjectService } from './services';
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
|
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
||||||
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories';
|
||||||
|
import {
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
import { CreateOrphanSpaceHandler } from './handler';
|
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||||
|
import {
|
||||||
|
SceneIconRepository,
|
||||||
|
SceneRepository,
|
||||||
|
} from '@app/common/modules/scene/repositories';
|
||||||
import {
|
import {
|
||||||
InviteSpaceRepository,
|
InviteSpaceRepository,
|
||||||
SpaceLinkRepository,
|
SpaceLinkRepository,
|
||||||
SpaceProductAllocationRepository,
|
SpaceProductAllocationRepository,
|
||||||
SpaceRepository,
|
SpaceRepository,
|
||||||
TagRepository,
|
|
||||||
} from '@app/common/modules/space';
|
} from '@app/common/modules/space';
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
import {
|
||||||
import { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories';
|
SpaceModelProductAllocationRepoitory,
|
||||||
import { ProjectUserController } from './controllers/project-user.controller';
|
SpaceModelRepository,
|
||||||
import { ProjectUserService } from './services/project-user.service';
|
SubspaceModelProductAllocationRepoitory,
|
||||||
|
SubspaceModelRepository,
|
||||||
|
} from '@app/common/modules/space-model';
|
||||||
|
import {
|
||||||
|
SubspaceProductAllocationRepository,
|
||||||
|
SubspaceRepository,
|
||||||
|
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
|
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
||||||
import {
|
import {
|
||||||
UserRepository,
|
UserRepository,
|
||||||
UserSpaceRepository,
|
UserSpaceRepository,
|
||||||
} from '@app/common/modules/user/repositories';
|
} from '@app/common/modules/user/repositories';
|
||||||
|
import { Global, Module } from '@nestjs/common';
|
||||||
|
import { CqrsModule } from '@nestjs/cqrs';
|
||||||
|
import { CommunityService } from 'src/community/services';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
import { SceneService } from 'src/scene/services';
|
||||||
|
import {
|
||||||
|
SpaceModelService,
|
||||||
|
SubSpaceModelService,
|
||||||
|
} from 'src/space-model/services';
|
||||||
|
import { SpaceModelProductAllocationService } from 'src/space-model/services/space-model-product-allocation.service';
|
||||||
|
import { SubspaceModelProductAllocationService } from 'src/space-model/services/subspace/subspace-model-product-allocation.service';
|
||||||
import {
|
import {
|
||||||
SpaceLinkService,
|
SpaceLinkService,
|
||||||
SpaceService,
|
SpaceService,
|
||||||
@ -26,49 +60,14 @@ import {
|
|||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
ValidationService,
|
ValidationService,
|
||||||
} from 'src/space/services';
|
} from 'src/space/services';
|
||||||
import { TagService } from 'src/tags/services';
|
|
||||||
import {
|
|
||||||
SpaceModelService,
|
|
||||||
SubSpaceModelService,
|
|
||||||
} from 'src/space-model/services';
|
|
||||||
import { DeviceService } from 'src/device/services';
|
|
||||||
import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service';
|
import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service';
|
||||||
import {
|
|
||||||
SubspaceProductAllocationRepository,
|
|
||||||
SubspaceRepository,
|
|
||||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
|
||||||
import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service';
|
import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service';
|
||||||
import { CommunityService } from 'src/community/services';
|
import { TagService } from 'src/tags/services';
|
||||||
import {
|
import { ProjectController } from './controllers';
|
||||||
SpaceModelProductAllocationRepoitory,
|
import { ProjectUserController } from './controllers/project-user.controller';
|
||||||
SpaceModelRepository,
|
import { CreateOrphanSpaceHandler } from './handler';
|
||||||
SubspaceModelProductAllocationRepoitory,
|
import { ProjectService } from './services';
|
||||||
SubspaceModelRepository,
|
import { ProjectUserService } from './services/project-user.service';
|
||||||
} from '@app/common/modules/space-model';
|
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
|
||||||
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
|
||||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
|
||||||
import { SpaceModelProductAllocationService } from 'src/space-model/services/space-model-product-allocation.service';
|
|
||||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
|
||||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
|
||||||
import { SceneService } from 'src/scene/services';
|
|
||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
|
||||||
import { SubspaceModelProductAllocationService } from 'src/space-model/services/subspace/subspace-model-product-allocation.service';
|
|
||||||
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
|
||||||
import {
|
|
||||||
SceneIconRepository,
|
|
||||||
SceneRepository,
|
|
||||||
} from '@app/common/modules/scene/repositories';
|
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
|
||||||
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
|
||||||
import {
|
|
||||||
PowerClampDailyRepository,
|
|
||||||
PowerClampHourlyRepository,
|
|
||||||
PowerClampMonthlyRepository,
|
|
||||||
} from '@app/common/modules/power-clamp/repositories';
|
|
||||||
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
|
||||||
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
|
||||||
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|
||||||
|
|
||||||
const CommandHandlers = [CreateOrphanSpaceHandler];
|
const CommandHandlers = [CreateOrphanSpaceHandler];
|
||||||
|
|
||||||
@ -112,7 +111,6 @@ const CommandHandlers = [CreateOrphanSpaceHandler];
|
|||||||
DeviceStatusFirebaseService,
|
DeviceStatusFirebaseService,
|
||||||
SceneService,
|
SceneService,
|
||||||
TuyaService,
|
TuyaService,
|
||||||
TagRepository,
|
|
||||||
SubspaceModelRepository,
|
SubspaceModelRepository,
|
||||||
SubspaceModelProductAllocationService,
|
SubspaceModelProductAllocationService,
|
||||||
SpaceModelProductAllocationRepoitory,
|
SpaceModelProductAllocationRepoitory,
|
||||||
|
@ -1,4 +1,17 @@
|
|||||||
|
import { ORPHAN_COMMUNITY_NAME } from '@app/common/constants/orphan-constant';
|
||||||
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import {
|
||||||
|
TypeORMCustomModel,
|
||||||
|
TypeORMCustomModelFindAllQuery,
|
||||||
|
} from '@app/common/models/typeOrmCustom.model';
|
||||||
|
import { ProjectDto } from '@app/common/modules/project/dtos';
|
||||||
|
import { ProjectEntity } from '@app/common/modules/project/entities';
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
|
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||||
|
import { format } from '@fast-csv/format';
|
||||||
import {
|
import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
HttpException,
|
HttpException,
|
||||||
@ -6,24 +19,11 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { CreateProjectDto, GetProjectParam } from '../dto';
|
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|
||||||
import { ProjectEntity } from '@app/common/modules/project/entities';
|
|
||||||
import {
|
|
||||||
TypeORMCustomModel,
|
|
||||||
TypeORMCustomModelFindAllQuery,
|
|
||||||
} from '@app/common/models/typeOrmCustom.model';
|
|
||||||
import { ProjectDto } from '@app/common/modules/project/dtos';
|
|
||||||
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
|
||||||
import { CommandBus } from '@nestjs/cqrs';
|
import { CommandBus } from '@nestjs/cqrs';
|
||||||
import { CreateOrphanSpaceCommand } from '../command/create-orphan-space-command';
|
|
||||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
|
||||||
import { format } from '@fast-csv/format';
|
|
||||||
import { PassThrough } from 'stream';
|
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
|
||||||
import { SpaceService } from 'src/space/services';
|
import { SpaceService } from 'src/space/services';
|
||||||
import { ORPHAN_COMMUNITY_NAME } from '@app/common/constants/orphan-constant';
|
import { PassThrough } from 'stream';
|
||||||
|
import { CreateOrphanSpaceCommand } from '../command/create-orphan-space-command';
|
||||||
|
import { CreateProjectDto, GetProjectParam } from '../dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProjectService {
|
export class ProjectService {
|
||||||
@ -236,11 +236,11 @@ export class ProjectService {
|
|||||||
'communities.spaces.parent',
|
'communities.spaces.parent',
|
||||||
'communities.spaces.productAllocations',
|
'communities.spaces.productAllocations',
|
||||||
'communities.spaces.productAllocations.product',
|
'communities.spaces.productAllocations.product',
|
||||||
'communities.spaces.productAllocations.tags',
|
'communities.spaces.productAllocations.tag',
|
||||||
'communities.spaces.subspaces',
|
'communities.spaces.subspaces',
|
||||||
'communities.spaces.subspaces.productAllocations',
|
'communities.spaces.subspaces.productAllocations',
|
||||||
'communities.spaces.subspaces.productAllocations.product',
|
'communities.spaces.subspaces.productAllocations.product',
|
||||||
'communities.spaces.subspaces.productAllocations.tags',
|
'communities.spaces.subspaces.productAllocations.tag',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -303,14 +303,13 @@ export class ProjectService {
|
|||||||
if (subspace.disabled) continue;
|
if (subspace.disabled) continue;
|
||||||
|
|
||||||
for (const productAllocation of subspace.productAllocations || []) {
|
for (const productAllocation of subspace.productAllocations || []) {
|
||||||
for (const tag of productAllocation.tags || []) {
|
|
||||||
csvStream.write({
|
csvStream.write({
|
||||||
'Device ID': '',
|
'Device ID': '',
|
||||||
'Community Name': space.community?.name || '',
|
'Community Name': space.community?.name || '',
|
||||||
'Space Name': space.spaceName,
|
'Space Name': space.spaceName,
|
||||||
'Space Location': spaceLocation,
|
'Space Location': spaceLocation,
|
||||||
'Subspace Name': subspace.subspaceName || '',
|
'Subspace Name': subspace.subspaceName || '',
|
||||||
Tag: tag.name,
|
Tag: productAllocation.tag.name,
|
||||||
'Product Name': productAllocation.product.name || '',
|
'Product Name': productAllocation.product.name || '',
|
||||||
'Community UUID': space.community?.uuid || '',
|
'Community UUID': space.community?.uuid || '',
|
||||||
'Space UUID': space.uuid,
|
'Space UUID': space.uuid,
|
||||||
@ -318,17 +317,15 @@ export class ProjectService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const productAllocation of space.productAllocations || []) {
|
for (const productAllocation of space.productAllocations || []) {
|
||||||
for (const tag of productAllocation.tags || []) {
|
|
||||||
csvStream.write({
|
csvStream.write({
|
||||||
'Device ID': '',
|
'Device ID': '',
|
||||||
'Community Name': space.community?.name || '',
|
'Community Name': space.community?.name || '',
|
||||||
'Space Name': space.spaceName,
|
'Space Name': space.spaceName,
|
||||||
'Space Location': spaceLocation,
|
'Space Location': spaceLocation,
|
||||||
'Subspace Name': '',
|
'Subspace Name': '',
|
||||||
Tag: tag.name,
|
Tag: productAllocation.tag.name,
|
||||||
'Product Name': productAllocation.product.name || '',
|
'Product Name': productAllocation.product.name || '',
|
||||||
'Community UUID': space.community?.uuid || '',
|
'Community UUID': space.community?.uuid || '',
|
||||||
'Space UUID': space.uuid,
|
'Space UUID': space.uuid,
|
||||||
@ -336,19 +333,8 @@ export class ProjectService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
csvStream.end();
|
csvStream.end();
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSpaceLocation(space: SpaceEntity): string {
|
|
||||||
const names = [];
|
|
||||||
let current = space.parent;
|
|
||||||
while (current) {
|
|
||||||
names.unshift(current.spaceName);
|
|
||||||
current = current.parent;
|
|
||||||
}
|
|
||||||
return names.join(' > ');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
export * from './create-space-model.dto';
|
export * from './create-space-model.dto';
|
||||||
|
export * from './link-space-model.dto';
|
||||||
export * from './project-param.dto';
|
export * from './project-param.dto';
|
||||||
export * from './update-space-model.dto';
|
|
||||||
export * from './space-model-param';
|
export * from './space-model-param';
|
||||||
export * from './subspaces-model-dtos';
|
export * from './subspaces-model-dtos';
|
||||||
export * from './tag-model-dtos';
|
export * from './update-space-model.dto';
|
||||||
export * from './link-space-model.dto';
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
|
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
IsString,
|
|
||||||
IsOptional,
|
|
||||||
IsArray,
|
IsArray,
|
||||||
ValidateNested,
|
|
||||||
IsEnum,
|
IsEnum,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
ValidateNested,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { ModifyTagModelDto } from '../tag-model-dtos';
|
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
|
|
||||||
export class ModifySubspaceModelDto {
|
export class ModifySubspaceModelDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@ -37,11 +37,11 @@ export class ModifySubspaceModelDto {
|
|||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description:
|
description:
|
||||||
'List of tag modifications (add/update/delete) for the subspace',
|
'List of tag modifications (add/update/delete) for the subspace',
|
||||||
type: [ModifyTagModelDto],
|
type: [ModifyTagDto],
|
||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
@Type(() => ModifyTagModelDto)
|
@Type(() => ModifyTagDto)
|
||||||
tags?: ModifyTagModelDto[];
|
tags?: ModifyTagDto[];
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
||||||
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
|
||||||
|
|
||||||
export class CreateTagModelDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Tag associated with the space or subspace models',
|
|
||||||
example: 'Temperature Control',
|
|
||||||
})
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsString()
|
|
||||||
tag: string;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description: 'UUID of the tag model (required for update/delete)',
|
|
||||||
example: '123e4567-e89b-12d3-a456-426614174000',
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
uuid?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID of the product associated with the tag',
|
|
||||||
example: '123e4567-e89b-12d3-a456-426614174000',
|
|
||||||
})
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsString()
|
|
||||||
productUuid: string;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
export * from './create-tag-model.dto';
|
|
||||||
export * from './update-tag-model.dto';
|
|
||||||
export * from './modify-tag-model.dto';
|
|
@ -1,46 +0,0 @@
|
|||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
||||||
import { IsString, IsOptional, IsEnum, IsUUID } from 'class-validator';
|
|
||||||
|
|
||||||
export class ModifyTagModelDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Action to perform: add, update, or delete',
|
|
||||||
example: ModifyAction.ADD,
|
|
||||||
})
|
|
||||||
@IsEnum(ModifyAction)
|
|
||||||
action: ModifyAction;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description: 'UUID of the new tag',
|
|
||||||
example: '123e4567-e89b-12d3-a456-426614174000',
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsUUID()
|
|
||||||
newTagUuid: string;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description:
|
|
||||||
'UUID of an existing tag (required for update/delete, optional for add)',
|
|
||||||
example: 'a1b2c3d4-5678-90ef-abcd-1234567890ef',
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsUUID()
|
|
||||||
tagUuid?: string;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description: 'Name of the tag (required for add/update)',
|
|
||||||
example: 'Temperature Sensor',
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
name?: string;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description:
|
|
||||||
'UUID of the product associated with the tag (required for add)',
|
|
||||||
example: 'c789a91e-549a-4753-9006-02f89e8170e0',
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsUUID()
|
|
||||||
productUuid?: string;
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import { IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';
|
|
||||||
|
|
||||||
export class UpdateTagModelDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'UUID of the tag to be updated',
|
|
||||||
example: '123e4567-e89b-12d3-a456-426614174000',
|
|
||||||
})
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsUUID()
|
|
||||||
uuid: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Updated name of the tag',
|
|
||||||
example: 'Updated Tag Name',
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
tag?: string;
|
|
||||||
}
|
|
@ -1,48 +1,13 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { IsArray, IsOptional, IsString, ValidateNested } from 'class-validator';
|
|
||||||
import { CreateSubspaceModelDto } from './subspaces-model-dtos/create-subspace-model.dto';
|
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
|
import { IsArray, IsOptional, IsString, ValidateNested } from 'class-validator';
|
||||||
import {
|
import {
|
||||||
DeleteSubspaceModelDto,
|
DeleteSubspaceModelDto,
|
||||||
ModifySubspaceModelDto,
|
ModifySubspaceModelDto,
|
||||||
UpdateSubspaceModelDto,
|
UpdateSubspaceModelDto,
|
||||||
} from './subspaces-model-dtos';
|
} from './subspaces-model-dtos';
|
||||||
import { ModifyTagModelDto } from './tag-model-dtos';
|
import { CreateSubspaceModelDto } from './subspaces-model-dtos/create-subspace-model.dto';
|
||||||
|
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
||||||
export class ModifySubspacesModelDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'List of subspaces to add',
|
|
||||||
type: [CreateSubspaceModelDto],
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => CreateSubspaceModelDto)
|
|
||||||
add?: CreateSubspaceModelDto[];
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'List of subspaces to add',
|
|
||||||
type: [CreateSubspaceModelDto],
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => UpdateSubspaceModelDto)
|
|
||||||
update?: UpdateSubspaceModelDto[];
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'List of subspaces to delete',
|
|
||||||
type: [DeleteSubspaceModelDto],
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => DeleteSubspaceModelDto)
|
|
||||||
delete?: DeleteSubspaceModelDto[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UpdateSpaceModelDto {
|
export class UpdateSpaceModelDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@ -66,11 +31,11 @@ export class UpdateSpaceModelDto {
|
|||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description:
|
description:
|
||||||
'List of tag modifications (add/update/delete) for the space model',
|
'List of tag modifications (add/update/delete) for the space model',
|
||||||
type: [ModifyTagModelDto],
|
type: [ModifyTagDto],
|
||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
@Type(() => ModifyTagModelDto)
|
@Type(() => ModifyTagDto)
|
||||||
tags?: ModifyTagModelDto[];
|
tags?: ModifyTagDto[];
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
|
||||||
import { PropogateUpdateSpaceModelProductAllocationCommand } from '../commands';
|
|
||||||
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
|
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
|
||||||
import { SubspaceModelProductAllocationRepoitory } from '@app/common/modules/space-model';
|
import { SubspaceModelProductAllocationRepoitory } from '@app/common/modules/space-model';
|
||||||
import {
|
import {
|
||||||
SubspaceRepository,
|
|
||||||
SubspaceProductAllocationRepository,
|
SubspaceProductAllocationRepository,
|
||||||
|
SubspaceRepository,
|
||||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
|
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||||
|
import { PropogateUpdateSpaceModelProductAllocationCommand } from '../commands';
|
||||||
|
|
||||||
@CommandHandler(PropogateUpdateSpaceModelProductAllocationCommand)
|
@CommandHandler(PropogateUpdateSpaceModelProductAllocationCommand)
|
||||||
export class PropogateUpdateSpaceModelProductAllocationHandler
|
export class PropogateUpdateSpaceModelProductAllocationHandler
|
||||||
@ -31,89 +31,89 @@ export class PropogateUpdateSpaceModelProductAllocationHandler
|
|||||||
|
|
||||||
console.log(`Processing ${updatedAllocations.length} allocations...`);
|
console.log(`Processing ${updatedAllocations.length} allocations...`);
|
||||||
|
|
||||||
for (const allocation of updatedAllocations) {
|
// for (const allocation of updatedAllocations) {
|
||||||
try {
|
// try {
|
||||||
if (allocation.allocation) {
|
// if (allocation.allocation) {
|
||||||
const spaceAllocations = await this.spaceProductRepository.find({
|
// const spaceAllocations = await this.spaceProductRepository.find({
|
||||||
where: { uuid: allocation.allocation.uuid },
|
// where: { uuid: allocation.allocation.uuid },
|
||||||
relations: ['tags'],
|
// relations: ['tags'],
|
||||||
});
|
// });
|
||||||
|
|
||||||
if (!spaceAllocations || spaceAllocations.length === 0) {
|
// if (!spaceAllocations || spaceAllocations.length === 0) {
|
||||||
console.warn(
|
// console.warn(
|
||||||
`No space allocations found for UUID: ${allocation.allocation.uuid}`,
|
// `No space allocations found for UUID: ${allocation.allocation.uuid}`,
|
||||||
);
|
// );
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (allocation.tagsAdded?.length) {
|
// if (allocation.tagsAdded?.length) {
|
||||||
for (const spaceAllocation of spaceAllocations) {
|
// for (const spaceAllocation of spaceAllocations) {
|
||||||
spaceAllocation.tags.push(...allocation.tagsAdded);
|
// spaceAllocation.tags.push(...allocation.tagsAdded);
|
||||||
}
|
// }
|
||||||
await this.spaceProductRepository.save(spaceAllocations);
|
// await this.spaceProductRepository.save(spaceAllocations);
|
||||||
console.log(
|
// console.log(
|
||||||
`Added tags to ${spaceAllocations.length} space allocations.`,
|
// `Added tags to ${spaceAllocations.length} space allocations.`,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (allocation.tagsRemoved?.length) {
|
// if (allocation.tagsRemoved?.length) {
|
||||||
const tagsToRemoveUUIDs = new Set(
|
// const tagsToRemoveUUIDs = new Set(
|
||||||
allocation.tagsRemoved.map((tag) => tag.uuid),
|
// allocation.tagsRemoved.map((tag) => tag.uuid),
|
||||||
);
|
// );
|
||||||
|
|
||||||
for (const spaceAllocation of spaceAllocations) {
|
// for (const spaceAllocation of spaceAllocations) {
|
||||||
spaceAllocation.tags = spaceAllocation.tags.filter(
|
// spaceAllocation.tags = spaceAllocation.tags.filter(
|
||||||
(tag) => !tagsToRemoveUUIDs.has(tag.uuid),
|
// (tag) => !tagsToRemoveUUIDs.has(tag.uuid),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
await this.spaceProductRepository.save(spaceAllocations);
|
// await this.spaceProductRepository.save(spaceAllocations);
|
||||||
console.log(
|
// console.log(
|
||||||
`Removed tags from ${spaceAllocations.length} space allocations.`,
|
// `Removed tags from ${spaceAllocations.length} space allocations.`,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (allocation.deletedAllocation) {
|
// if (allocation.deletedAllocation) {
|
||||||
const spaceAllocations = await this.spaceProductRepository.find({
|
// const spaceAllocations = await this.spaceProductRepository.find({
|
||||||
where: { uuid: allocation.deletedAllocation.uuid },
|
// where: { uuid: allocation.deletedAllocation.uuid },
|
||||||
relations: ['tags'],
|
// relations: ['tags'],
|
||||||
});
|
// });
|
||||||
|
|
||||||
if (!spaceAllocations || spaceAllocations.length === 0) {
|
// if (!spaceAllocations || spaceAllocations.length === 0) {
|
||||||
console.warn(
|
// console.warn(
|
||||||
`No space allocations found to delete for UUID: ${allocation.deletedAllocation.uuid}`,
|
// `No space allocations found to delete for UUID: ${allocation.deletedAllocation.uuid}`,
|
||||||
);
|
// );
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
await this.spaceProductRepository.remove(spaceAllocations);
|
// await this.spaceProductRepository.remove(spaceAllocations);
|
||||||
console.log(
|
// console.log(
|
||||||
`Deleted ${spaceAllocations.length} space allocations.`,
|
// `Deleted ${spaceAllocations.length} space allocations.`,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (allocation.newAllocation) {
|
// if (allocation.newAllocation) {
|
||||||
const newAllocations = spaces.map((space) =>
|
// const newAllocations = spaces.map((space) =>
|
||||||
this.spaceProductRepository.create({
|
// this.spaceProductRepository.create({
|
||||||
space,
|
// space,
|
||||||
product: allocation.newAllocation.product,
|
// product: allocation.newAllocation.product,
|
||||||
tags: allocation.newAllocation.tags,
|
// tag: allocation.newAllocation.tag,
|
||||||
inheritedFromModel: allocation.newAllocation,
|
// inheritedFromModel: allocation.newAllocation,
|
||||||
}),
|
// }),
|
||||||
);
|
// );
|
||||||
|
|
||||||
await this.spaceProductRepository.save(newAllocations);
|
// await this.spaceProductRepository.save(newAllocations);
|
||||||
console.log(
|
// console.log(
|
||||||
`Created ${newAllocations.length} new space allocations.`,
|
// `Created ${newAllocations.length} new space allocations.`,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error(
|
// console.error(
|
||||||
`Error processing allocation update: ${JSON.stringify(allocation)}`,
|
// `Error processing allocation update: ${JSON.stringify(allocation)}`,
|
||||||
error,
|
// error,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
console.log('Finished processing all allocations.');
|
console.log('Finished processing all allocations.');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
||||||
import { PropogateUpdateSpaceModelCommand } from '../commands';
|
|
||||||
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
|
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
|
||||||
|
import { SubspaceModelProductAllocationRepoitory } from '@app/common/modules/space-model';
|
||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
import {
|
import {
|
||||||
SubspaceProductAllocationRepository,
|
SubspaceProductAllocationRepository,
|
||||||
SubspaceRepository,
|
SubspaceRepository,
|
||||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
import { SubspaceModelProductAllocationRepoitory } from '@app/common/modules/space-model';
|
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||||
import { In } from 'typeorm';
|
import { PropogateUpdateSpaceModelCommand } from '../commands';
|
||||||
import { ISingleSubspaceModel } from '../interfaces';
|
import { ISingleSubspaceModel } from '../interfaces';
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
|
||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { IUpdatedAllocations } from '../interfaces/subspace-product-allocation-update-result.interface';
|
import { IUpdatedAllocations } from '../interfaces/subspace-product-allocation-update-result.interface';
|
||||||
|
|
||||||
@CommandHandler(PropogateUpdateSpaceModelCommand)
|
@CommandHandler(PropogateUpdateSpaceModelCommand)
|
||||||
@ -72,48 +71,48 @@ export class PropogateUpdateSpaceModelHandler
|
|||||||
for (const allocation of allocations) {
|
for (const allocation of allocations) {
|
||||||
if (!allocation) continue;
|
if (!allocation) continue;
|
||||||
|
|
||||||
if (allocation.allocation) {
|
// if (allocation.allocation) {
|
||||||
try {
|
// try {
|
||||||
const subspaceAllocations =
|
// const subspaceAllocations =
|
||||||
await this.subspaceProductRepository.find({
|
// await this.subspaceProductRepository.find({
|
||||||
where: {
|
// where: {
|
||||||
inheritedFromModel: { uuid: allocation.allocation.uuid },
|
// inheritedFromModel: { uuid: allocation.allocation.uuid },
|
||||||
},
|
// },
|
||||||
relations: ['tags'],
|
// relations: ['tags'],
|
||||||
});
|
// });
|
||||||
|
|
||||||
if (!subspaceAllocations || subspaceAllocations.length === 0)
|
// if (!subspaceAllocations || subspaceAllocations.length === 0)
|
||||||
continue;
|
// continue;
|
||||||
|
|
||||||
if (allocation.tagsAdded?.length) {
|
// if (allocation.tagsAdded?.length) {
|
||||||
for (const subspaceAllocation of subspaceAllocations) {
|
// for (const subspaceAllocation of subspaceAllocations) {
|
||||||
subspaceAllocation.tags.push(...allocation.tagsAdded);
|
// subspaceAllocation.tags.push(...allocation.tagsAdded);
|
||||||
}
|
// }
|
||||||
await this.subspaceProductRepository.save(subspaceAllocations);
|
// await this.subspaceProductRepository.save(subspaceAllocations);
|
||||||
console.log(
|
// console.log(
|
||||||
`Added tags to ${subspaceAllocations.length} subspace allocations.`,
|
// `Added tags to ${subspaceAllocations.length} subspace allocations.`,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (allocation.tagsRemoved?.length) {
|
// if (allocation.tagsRemoved?.length) {
|
||||||
const tagsToRemoveUUIDs = allocation.tagsRemoved.map(
|
// const tagsToRemoveUUIDs = allocation.tagsRemoved.map(
|
||||||
(tag) => tag.uuid,
|
// (tag) => tag.uuid,
|
||||||
);
|
// );
|
||||||
|
|
||||||
for (const subspaceAllocation of subspaceAllocations) {
|
// for (const subspaceAllocation of subspaceAllocations) {
|
||||||
subspaceAllocation.tags = subspaceAllocation.tags.filter(
|
// subspaceAllocation.tags = subspaceAllocation.tags.filter(
|
||||||
(tag) => !tagsToRemoveUUIDs.includes(tag.uuid),
|
// (tag) => !tagsToRemoveUUIDs.includes(tag.uuid),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
await this.subspaceProductRepository.save(subspaceAllocations);
|
// await this.subspaceProductRepository.save(subspaceAllocations);
|
||||||
console.log(
|
// console.log(
|
||||||
`Removed tags from ${subspaceAllocations.length} subspace allocations.`,
|
// `Removed tags from ${subspaceAllocations.length} subspace allocations.`,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error('Error processing allocation update:', error);
|
// console.error('Error processing allocation update:', error);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (allocation.newAllocation) {
|
if (allocation.newAllocation) {
|
||||||
try {
|
try {
|
||||||
@ -127,7 +126,7 @@ export class PropogateUpdateSpaceModelHandler
|
|||||||
const newAllocations = subspaces.map((subspace) =>
|
const newAllocations = subspaces.map((subspace) =>
|
||||||
this.subspaceProductRepository.create({
|
this.subspaceProductRepository.create({
|
||||||
product: allocation.newAllocation.product,
|
product: allocation.newAllocation.product,
|
||||||
tags: allocation.newAllocation.tags,
|
tag: allocation.newAllocation.tag,
|
||||||
subspace,
|
subspace,
|
||||||
inheritedFromModel: allocation.newAllocation,
|
inheritedFromModel: allocation.newAllocation,
|
||||||
}),
|
}),
|
||||||
@ -198,7 +197,7 @@ export class PropogateUpdateSpaceModelHandler
|
|||||||
const subspaceAllocation = this.subspaceProductRepository.create({
|
const subspaceAllocation = this.subspaceProductRepository.create({
|
||||||
subspace: subspace,
|
subspace: subspace,
|
||||||
product: allocation.product,
|
product: allocation.product,
|
||||||
tags: allocation.tags,
|
tag: allocation.tag,
|
||||||
inheritedFromModel: allocation,
|
inheritedFromModel: allocation,
|
||||||
});
|
});
|
||||||
await this.subspaceProductRepository.save(subspaceAllocation);
|
await this.subspaceProductRepository.save(subspaceAllocation);
|
||||||
@ -211,67 +210,59 @@ export class PropogateUpdateSpaceModelHandler
|
|||||||
subspaceModel: ISingleSubspaceModel,
|
subspaceModel: ISingleSubspaceModel,
|
||||||
spaces: SpaceEntity[],
|
spaces: SpaceEntity[],
|
||||||
) {
|
) {
|
||||||
const subspaces = await this.subspaceRepository.find({
|
// const subspaces = await this.subspaceRepository.find({
|
||||||
where: {
|
// where: {
|
||||||
subSpaceModel: { uuid: subspaceModel.subspaceModel.uuid },
|
// subSpaceModel: { uuid: subspaceModel.subspaceModel.uuid },
|
||||||
disabled: false,
|
// disabled: false,
|
||||||
},
|
// },
|
||||||
relations: [
|
// relations: [
|
||||||
'productAllocations',
|
// 'productAllocations',
|
||||||
'productAllocations.product',
|
// 'productAllocations.product',
|
||||||
'productAllocations.tags',
|
// 'productAllocations.tags',
|
||||||
],
|
// ],
|
||||||
});
|
// });
|
||||||
|
// if (!subspaces.length) {
|
||||||
if (!subspaces.length) {
|
// return;
|
||||||
return;
|
// }
|
||||||
}
|
// const allocationUuidsToRemove = subspaces.flatMap((subspace) =>
|
||||||
|
// subspace.productAllocations.map((allocation) => allocation.uuid),
|
||||||
const allocationUuidsToRemove = subspaces.flatMap((subspace) =>
|
// );
|
||||||
subspace.productAllocations.map((allocation) => allocation.uuid),
|
// if (allocationUuidsToRemove.length) {
|
||||||
);
|
// await this.subspaceProductRepository.delete(allocationUuidsToRemove);
|
||||||
|
// }
|
||||||
if (allocationUuidsToRemove.length) {
|
// await this.subspaceRepository.update(
|
||||||
await this.subspaceProductRepository.delete(allocationUuidsToRemove);
|
// { uuid: In(subspaces.map((s) => s.uuid)) },
|
||||||
}
|
// { disabled: true },
|
||||||
|
// );
|
||||||
await this.subspaceRepository.update(
|
// const relocatedAllocations = subspaceModel.relocatedAllocations || [];
|
||||||
{ uuid: In(subspaces.map((s) => s.uuid)) },
|
// if (!relocatedAllocations.length) {
|
||||||
{ disabled: true },
|
// return;
|
||||||
);
|
// }
|
||||||
|
// for (const space of spaces) {
|
||||||
const relocatedAllocations = subspaceModel.relocatedAllocations || [];
|
// for (const { allocation, tags = [] } of relocatedAllocations) {
|
||||||
|
// const spaceAllocation = await this.spaceProductRepository.findOne({
|
||||||
if (!relocatedAllocations.length) {
|
// where: {
|
||||||
return;
|
// inheritedFromModel: { uuid: allocation.uuid },
|
||||||
}
|
// space: { uuid: space.uuid },
|
||||||
|
// },
|
||||||
for (const space of spaces) {
|
// relations: ['tags'],
|
||||||
for (const { allocation, tags = [] } of relocatedAllocations) {
|
// });
|
||||||
const spaceAllocation = await this.spaceProductRepository.findOne({
|
// if (spaceAllocation) {
|
||||||
where: {
|
// if (tags.length) {
|
||||||
inheritedFromModel: { uuid: allocation.uuid },
|
// spaceAllocation.tags.push(...tags);
|
||||||
space: { uuid: space.uuid },
|
// await this.spaceProductRepository.save(spaceAllocation);
|
||||||
},
|
// }
|
||||||
relations: ['tags'],
|
// } else {
|
||||||
});
|
// const newSpaceAllocation = this.spaceProductRepository.create({
|
||||||
|
// space,
|
||||||
if (spaceAllocation) {
|
// inheritedFromModel: allocation,
|
||||||
if (tags.length) {
|
// tag: allocation.tag,
|
||||||
spaceAllocation.tags.push(...tags);
|
// product: allocation.product,
|
||||||
await this.spaceProductRepository.save(spaceAllocation);
|
// });
|
||||||
}
|
// await this.spaceProductRepository.save(newSpaceAllocation);
|
||||||
} else {
|
// }
|
||||||
const newSpaceAllocation = this.spaceProductRepository.create({
|
// }
|
||||||
space,
|
// }
|
||||||
inheritedFromModel: allocation,
|
|
||||||
tags: allocation.tags,
|
|
||||||
product: allocation.product,
|
|
||||||
});
|
|
||||||
await this.spaceProductRepository.save(newSpaceAllocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateSubspaceModel(subspaceModel: ISingleSubspaceModel) {
|
async updateSubspaceModel(subspaceModel: ISingleSubspaceModel) {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
export * from './update-subspace.interface';
|
|
||||||
export * from './modify-subspace.interface';
|
|
||||||
export * from './single-subspace.interface';
|
export * from './single-subspace.interface';
|
||||||
export * from './space-product-allocation.interface';
|
export * from './space-product-allocation.interface';
|
||||||
|
export * from './update-subspace.interface';
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import { SubspaceModelEntity, TagModel } from '@app/common/modules/space-model';
|
|
||||||
|
|
||||||
export interface ModifyspaceModelPayload {
|
|
||||||
modifiedSubspaceModels?: ModifySubspaceModelPayload;
|
|
||||||
modifiedTags?: ModifiedTagsModelPayload;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ModifySubspaceModelPayload {
|
|
||||||
addedSubspaceModels?: SubspaceModelEntity[];
|
|
||||||
updatedSubspaceModels?: UpdatedSubspaceModelPayload[];
|
|
||||||
deletedSubspaceModels?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UpdatedSubspaceModelPayload {
|
|
||||||
subspaceName?: string;
|
|
||||||
modifiedTags?: ModifiedTagsModelPayload;
|
|
||||||
subspaceModelUuid: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ModifiedTagsModelPayload {
|
|
||||||
added?: TagModel[];
|
|
||||||
updated?: TagModel[];
|
|
||||||
deleted?: string[];
|
|
||||||
}
|
|
@ -1,11 +1,11 @@
|
|||||||
|
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
||||||
import {
|
import {
|
||||||
SpaceModelProductAllocationEntity,
|
SpaceModelProductAllocationEntity,
|
||||||
SubspaceModelEntity,
|
SubspaceModelEntity,
|
||||||
} from '@app/common/modules/space-model';
|
} from '@app/common/modules/space-model';
|
||||||
import { ModifyTagModelDto } from '../dtos';
|
|
||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { NewTagEntity } from '@app/common/modules/tag';
|
import { NewTagEntity } from '@app/common/modules/tag';
|
||||||
import { IUpdatedAllocations } from './subspace-product-allocation-update-result.interface';
|
import { IUpdatedAllocations } from './subspace-product-allocation-update-result.interface';
|
||||||
|
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
||||||
|
|
||||||
export interface IRelocatedAllocation {
|
export interface IRelocatedAllocation {
|
||||||
allocation: SpaceModelProductAllocationEntity;
|
allocation: SpaceModelProductAllocationEntity;
|
||||||
@ -14,7 +14,7 @@ export interface IRelocatedAllocation {
|
|||||||
export interface ISingleSubspaceModel {
|
export interface ISingleSubspaceModel {
|
||||||
subspaceModel: SubspaceModelEntity;
|
subspaceModel: SubspaceModelEntity;
|
||||||
action: ModifyAction;
|
action: ModifyAction;
|
||||||
tags?: ModifyTagModelDto[];
|
tags?: ModifyTagDto[];
|
||||||
relocatedAllocations?: IRelocatedAllocation[];
|
relocatedAllocations?: IRelocatedAllocation[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
import { In, QueryRunner } from 'typeorm';
|
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
|
import { In, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
import { ProductEntity } from '@app/common/modules/product/entities';
|
||||||
|
import { ProjectEntity } from '@app/common/modules/project/entities';
|
||||||
|
import { SpaceRepository } from '@app/common/modules/space';
|
||||||
import {
|
import {
|
||||||
SpaceModelEntity,
|
SpaceModelEntity,
|
||||||
SpaceModelProductAllocationEntity,
|
SpaceModelProductAllocationEntity,
|
||||||
SpaceModelProductAllocationRepoitory,
|
SpaceModelProductAllocationRepoitory,
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
} from '@app/common/modules/space-model';
|
} from '@app/common/modules/space-model';
|
||||||
import { TagService as NewTagService } from 'src/tags/services';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
|
||||||
import { ModifySubspaceModelDto, ModifyTagModelDto } from '../dtos';
|
|
||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { NewTagEntity } from '@app/common/modules/tag';
|
import { NewTagEntity } from '@app/common/modules/tag';
|
||||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
||||||
import { SpaceRepository } from '@app/common/modules/space';
|
import { ProcessTagDto } from 'src/tags/dtos';
|
||||||
import { ProjectEntity } from '@app/common/modules/project/entities';
|
import { TagService as NewTagService } from 'src/tags/services';
|
||||||
|
import { ModifySubspaceModelDto } from '../dtos';
|
||||||
import { IUpdatedSpaceAllocations } from '../interfaces';
|
import { IUpdatedSpaceAllocations } from '../interfaces';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -32,225 +31,220 @@ export class SpaceModelProductAllocationService {
|
|||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
modifySubspaceModels?: ModifySubspaceModelDto[],
|
modifySubspaceModels?: ModifySubspaceModelDto[],
|
||||||
): Promise<IUpdatedSpaceAllocations[]> {
|
): Promise<IUpdatedSpaceAllocations[]> {
|
||||||
try {
|
// try {
|
||||||
if (!tags.length) return [];
|
if (!tags.length) return [];
|
||||||
|
|
||||||
const allocationUpdates: IUpdatedSpaceAllocations[] = [];
|
const allocationUpdates: IUpdatedSpaceAllocations[] = [];
|
||||||
|
|
||||||
const processedTags = await this.tagService.processTags(
|
|
||||||
tags,
|
|
||||||
projectUuid,
|
|
||||||
queryRunner,
|
|
||||||
);
|
|
||||||
|
|
||||||
const productAllocations: SpaceModelProductAllocationEntity[] = [];
|
|
||||||
const existingAllocations = new Map<
|
|
||||||
string,
|
|
||||||
SpaceModelProductAllocationEntity
|
|
||||||
>();
|
|
||||||
|
|
||||||
for (const tag of processedTags) {
|
|
||||||
let isTagNeeded = true;
|
|
||||||
|
|
||||||
if (modifySubspaceModels) {
|
|
||||||
const relatedSubspaces = await queryRunner.manager.find(
|
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
product: { uuid: tag.product.uuid },
|
|
||||||
subspaceModel: { spaceModel: { uuid: spaceModel.uuid } },
|
|
||||||
tags: { uuid: tag.uuid },
|
|
||||||
},
|
|
||||||
relations: ['subspaceModel', 'tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const subspaceWithTag of relatedSubspaces) {
|
|
||||||
const modifyingSubspace = modifySubspaceModels.find(
|
|
||||||
(subspace) =>
|
|
||||||
subspace.action === ModifyAction.UPDATE &&
|
|
||||||
subspace.uuid === subspaceWithTag.subspaceModel.uuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
modifyingSubspace &&
|
|
||||||
modifyingSubspace.tags &&
|
|
||||||
modifyingSubspace.tags.some(
|
|
||||||
(subspaceTag) =>
|
|
||||||
subspaceTag.action === ModifyAction.DELETE &&
|
|
||||||
subspaceTag.tagUuid === tag.uuid,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
isTagNeeded = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTagNeeded) {
|
|
||||||
const hasTags = await this.validateTagWithinSpaceModel(
|
|
||||||
queryRunner,
|
|
||||||
tag,
|
|
||||||
spaceModel,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (hasTags) continue;
|
|
||||||
|
|
||||||
let allocation = existingAllocations.get(tag.product.uuid);
|
|
||||||
if (!allocation) {
|
|
||||||
allocation = await this.getAllocationByProduct(
|
|
||||||
tag.product,
|
|
||||||
spaceModel,
|
|
||||||
queryRunner,
|
|
||||||
);
|
|
||||||
if (allocation) {
|
|
||||||
existingAllocations.set(tag.product.uuid, allocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allocation) {
|
|
||||||
allocation = this.createNewAllocation(spaceModel, tag, queryRunner);
|
|
||||||
productAllocations.push(allocation);
|
|
||||||
allocationUpdates.push({
|
|
||||||
newAllocation: allocation,
|
|
||||||
});
|
|
||||||
} else if (!allocation.tags.some((t) => t.uuid === tag.uuid)) {
|
|
||||||
allocation.tags.push(tag);
|
|
||||||
allocationUpdates.push({
|
|
||||||
allocation: allocation,
|
|
||||||
tagsAdded: [tag],
|
|
||||||
});
|
|
||||||
await this.saveAllocation(allocation, queryRunner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (productAllocations.length > 0) {
|
|
||||||
await this.saveAllocations(productAllocations, queryRunner);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allocationUpdates;
|
return allocationUpdates;
|
||||||
} catch (error) {
|
// const processedTags = await this.tagService.processTags(
|
||||||
throw this.handleError(error, 'Failed to create product allocations');
|
// tags,
|
||||||
}
|
// projectUuid,
|
||||||
|
// queryRunner,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const productAllocations: SpaceModelProductAllocationEntity[] = [];
|
||||||
|
// const existingAllocations = new Map<
|
||||||
|
// string,
|
||||||
|
// SpaceModelProductAllocationEntity
|
||||||
|
// >();
|
||||||
|
|
||||||
|
// for (const tag of processedTags) {
|
||||||
|
// let isTagNeeded = true;
|
||||||
|
|
||||||
|
// if (modifySubspaceModels) {
|
||||||
|
// const relatedSubspaces = await queryRunner.manager.find(
|
||||||
|
// SubspaceModelProductAllocationEntity,
|
||||||
|
// {
|
||||||
|
// where: {
|
||||||
|
// product: { uuid: tag.product.uuid },
|
||||||
|
// subspaceModel: { spaceModel: { uuid: spaceModel.uuid } },
|
||||||
|
// tags: { uuid: tag.uuid },
|
||||||
|
// },
|
||||||
|
// relations: ['subspaceModel', 'tags'],
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
|
// for (const subspaceWithTag of relatedSubspaces) {
|
||||||
|
// const modifyingSubspace = modifySubspaceModels.find(
|
||||||
|
// (subspace) =>
|
||||||
|
// subspace.action === ModifyAction.UPDATE &&
|
||||||
|
// subspace.uuid === subspaceWithTag.subspaceModel.uuid,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if (
|
||||||
|
// modifyingSubspace &&
|
||||||
|
// modifyingSubspace.tags &&
|
||||||
|
// modifyingSubspace.tags.some(
|
||||||
|
// (subspaceTag) =>
|
||||||
|
// subspaceTag.action === ModifyAction.DELETE &&
|
||||||
|
// subspaceTag.tagUuid === tag.uuid,
|
||||||
|
// )
|
||||||
|
// ) {
|
||||||
|
// isTagNeeded = true;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (isTagNeeded) {
|
||||||
|
// const hasTags = await this.validateTagWithinSpaceModel(
|
||||||
|
// queryRunner,
|
||||||
|
// tag,
|
||||||
|
// spaceModel,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if (hasTags) continue;
|
||||||
|
|
||||||
|
// let allocation = existingAllocations.get(tag.product.uuid);
|
||||||
|
// if (!allocation) {
|
||||||
|
// allocation = await this.getAllocationByProduct(
|
||||||
|
// tag.product,
|
||||||
|
// spaceModel,
|
||||||
|
// queryRunner,
|
||||||
|
// );
|
||||||
|
// if (allocation) {
|
||||||
|
// existingAllocations.set(tag.product.uuid, allocation);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!allocation) {
|
||||||
|
// allocation = this.createNewAllocation(spaceModel, tag, queryRunner);
|
||||||
|
// productAllocations.push(allocation);
|
||||||
|
// allocationUpdates.push({
|
||||||
|
// newAllocation: allocation,
|
||||||
|
// });
|
||||||
|
// } else if (!allocation.tags.some((t) => t.uuid === tag.uuid)) {
|
||||||
|
// allocation.tags.push(tag);
|
||||||
|
// allocationUpdates.push({
|
||||||
|
// allocation: allocation,
|
||||||
|
// tagsAdded: [tag],
|
||||||
|
// });
|
||||||
|
// await this.saveAllocation(allocation, queryRunner);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (productAllocations.length > 0) {
|
||||||
|
// await this.saveAllocations(productAllocations, queryRunner);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return allocationUpdates;
|
||||||
|
// } catch (error) {
|
||||||
|
// throw this.handleError(error, 'Failed to create product allocations');
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateProductAllocations(
|
async updateProductAllocations(
|
||||||
dtos: ModifyTagModelDto[],
|
dtos: ModifyTagDto[],
|
||||||
project: ProjectEntity,
|
project: ProjectEntity,
|
||||||
spaceModel: SpaceModelEntity,
|
spaceModel: SpaceModelEntity,
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
modifySubspaceModels?: ModifySubspaceModelDto[],
|
modifySubspaceModels?: ModifySubspaceModelDto[],
|
||||||
): Promise<IUpdatedSpaceAllocations[]> {
|
): Promise<IUpdatedSpaceAllocations[]> {
|
||||||
try {
|
const allocationUpdates: IUpdatedSpaceAllocations[] = [];
|
||||||
const addDtos = dtos.filter((dto) => dto.action === ModifyAction.ADD);
|
return allocationUpdates;
|
||||||
const deleteDtos = dtos.filter(
|
// try {
|
||||||
(dto) => dto.action === ModifyAction.DELETE,
|
// const addDtos = dtos.filter((dto) => dto.action === ModifyAction.ADD);
|
||||||
);
|
// const deleteDtos = dtos.filter(
|
||||||
|
// (dto) => dto.action === ModifyAction.DELETE,
|
||||||
const addTagDtos: ProcessTagDto[] = addDtos.map((dto) => ({
|
// );
|
||||||
name: dto.name,
|
// const addTagDtos: ProcessTagDto[] = addDtos.map((dto) => ({
|
||||||
productUuid: dto.productUuid,
|
// name: dto.name,
|
||||||
uuid: dto.newTagUuid,
|
// productUuid: dto.productUuid,
|
||||||
}));
|
// uuid: dto.newTagUuid,
|
||||||
|
// }));
|
||||||
// Process added tags
|
// // Process added tags
|
||||||
const processedTags = await this.tagService.processTags(
|
// const processedTags = await this.tagService.processTags(
|
||||||
addTagDtos,
|
// addTagDtos,
|
||||||
project.uuid,
|
// project.uuid,
|
||||||
queryRunner,
|
// queryRunner,
|
||||||
);
|
// );
|
||||||
|
// const addTagUuidMap = new Map<string, ModifyTagModelDto>();
|
||||||
const addTagUuidMap = new Map<string, ModifyTagModelDto>();
|
// processedTags.forEach((tag, index) => {
|
||||||
processedTags.forEach((tag, index) => {
|
// addTagUuidMap.set(tag.uuid, addDtos[index]);
|
||||||
addTagUuidMap.set(tag.uuid, addDtos[index]);
|
// });
|
||||||
});
|
// const addTagUuids = new Set(processedTags.map((tag) => tag.uuid));
|
||||||
|
// const deleteTagUuids = new Set(deleteDtos.map((dto) => dto.tagUuid));
|
||||||
const addTagUuids = new Set(processedTags.map((tag) => tag.uuid));
|
// const tagsToIgnore = new Set(
|
||||||
const deleteTagUuids = new Set(deleteDtos.map((dto) => dto.tagUuid));
|
// [...addTagUuids].filter((uuid) => deleteTagUuids.has(uuid)),
|
||||||
|
// );
|
||||||
const tagsToIgnore = new Set(
|
// // Filter out tags that are added and deleted in the same request
|
||||||
[...addTagUuids].filter((uuid) => deleteTagUuids.has(uuid)),
|
// const filteredDtos = dtos.filter(
|
||||||
);
|
// (dto) =>
|
||||||
|
// !(
|
||||||
// Filter out tags that are added and deleted in the same request
|
// tagsToIgnore.has(dto.tagUuid) ||
|
||||||
const filteredDtos = dtos.filter(
|
// (dto.action === ModifyAction.ADD &&
|
||||||
(dto) =>
|
// tagsToIgnore.has(
|
||||||
!(
|
// [...addTagUuidMap.keys()].find(
|
||||||
tagsToIgnore.has(dto.tagUuid) ||
|
// (uuid) => addTagUuidMap.get(uuid) === dto,
|
||||||
(dto.action === ModifyAction.ADD &&
|
// ),
|
||||||
tagsToIgnore.has(
|
// ))
|
||||||
[...addTagUuidMap.keys()].find(
|
// ),
|
||||||
(uuid) => addTagUuidMap.get(uuid) === dto,
|
// );
|
||||||
),
|
// // Process add and delete actions concurrently
|
||||||
))
|
// const [updatedAllocations, deletedAllocations] = await Promise.all([
|
||||||
),
|
// this.processAddActions(
|
||||||
);
|
// filteredDtos,
|
||||||
|
// project.uuid,
|
||||||
// Process add and delete actions concurrently
|
// spaceModel,
|
||||||
const [updatedAllocations, deletedAllocations] = await Promise.all([
|
// queryRunner,
|
||||||
this.processAddActions(
|
// modifySubspaceModels,
|
||||||
filteredDtos,
|
// ),
|
||||||
project.uuid,
|
// this.processDeleteActions(filteredDtos, queryRunner, spaceModel),
|
||||||
spaceModel,
|
// ]);
|
||||||
queryRunner,
|
// // Combine results and return
|
||||||
modifySubspaceModels,
|
// return [...updatedAllocations, ...deletedAllocations];
|
||||||
),
|
// } catch (error) {
|
||||||
this.processDeleteActions(filteredDtos, queryRunner, spaceModel),
|
// throw this.handleError(error, 'Error while updating product allocations');
|
||||||
]);
|
// }
|
||||||
|
|
||||||
// Combine results and return
|
|
||||||
return [...updatedAllocations, ...deletedAllocations];
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleError(error, 'Error while updating product allocations');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async processAddActions(
|
private async processAddActions(
|
||||||
dtos: ModifyTagModelDto[],
|
dtos: ModifyTagDto[],
|
||||||
projectUuid: string,
|
projectUuid: string,
|
||||||
spaceModel: SpaceModelEntity,
|
spaceModel: SpaceModelEntity,
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
modifySubspaceModels?: ModifySubspaceModelDto[],
|
modifySubspaceModels?: ModifySubspaceModelDto[],
|
||||||
): Promise<IUpdatedSpaceAllocations[]> {
|
): Promise<IUpdatedSpaceAllocations[]> {
|
||||||
let allocationUpdates: IUpdatedSpaceAllocations[] = [];
|
const allocationUpdates: IUpdatedSpaceAllocations[] = [];
|
||||||
|
|
||||||
const addDtos: ProcessTagDto[] = dtos
|
|
||||||
.filter((dto) => dto.action === ModifyAction.ADD)
|
|
||||||
.map((dto) => ({
|
|
||||||
name: dto.name,
|
|
||||||
productUuid: dto.productUuid,
|
|
||||||
uuid: dto.newTagUuid,
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (addDtos.length > 0) {
|
|
||||||
allocationUpdates = await this.createProductAllocations(
|
|
||||||
projectUuid,
|
|
||||||
spaceModel,
|
|
||||||
addDtos,
|
|
||||||
queryRunner,
|
|
||||||
modifySubspaceModels,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return allocationUpdates;
|
return allocationUpdates;
|
||||||
|
// const addDtos: ProcessTagDto[] = dtos
|
||||||
|
// .filter((dto) => dto.action === ModifyAction.ADD)
|
||||||
|
// .map((dto) => ({
|
||||||
|
// name: dto.name,
|
||||||
|
// productUuid: dto.productUuid,
|
||||||
|
// uuid: dto.newTagUuid,
|
||||||
|
// }));
|
||||||
|
|
||||||
|
// if (addDtos.length > 0) {
|
||||||
|
// allocationUpdates = await this.createProductAllocations(
|
||||||
|
// projectUuid,
|
||||||
|
// spaceModel,
|
||||||
|
// addDtos,
|
||||||
|
// queryRunner,
|
||||||
|
// modifySubspaceModels,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// return allocationUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createNewAllocation(
|
private createNewAllocation(
|
||||||
spaceModel: SpaceModelEntity,
|
spaceModel: SpaceModelEntity,
|
||||||
tag: NewTagEntity,
|
tag: NewTagEntity,
|
||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
): SpaceModelProductAllocationEntity {
|
) {
|
||||||
return queryRunner
|
// : SpaceModelProductAllocationEntity
|
||||||
? queryRunner.manager.create(SpaceModelProductAllocationEntity, {
|
// return queryRunner
|
||||||
spaceModel,
|
// ? queryRunner.manager.create(SpaceModelProductAllocationEntity, {
|
||||||
product: tag.product,
|
// spaceModel,
|
||||||
tags: [tag],
|
// product: tag.product,
|
||||||
})
|
// tags: [tag],
|
||||||
: this.spaceModelProductAllocationRepository.create({
|
// })
|
||||||
spaceModel,
|
// : this.spaceModelProductAllocationRepository.create({
|
||||||
product: tag.product,
|
// spaceModel,
|
||||||
tags: [tag],
|
// product: tag.product,
|
||||||
});
|
// tags: [tag],
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAllocationByProduct(
|
private async getAllocationByProduct(
|
||||||
@ -309,7 +303,7 @@ export class SpaceModelProductAllocationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async processDeleteActions(
|
private async processDeleteActions(
|
||||||
dtos: ModifyTagModelDto[],
|
dtos: ModifyTagDto[],
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
spaceModel: SpaceModelEntity,
|
spaceModel: SpaceModelEntity,
|
||||||
): Promise<IUpdatedSpaceAllocations[]> {
|
): Promise<IUpdatedSpaceAllocations[]> {
|
||||||
@ -317,10 +311,10 @@ export class SpaceModelProductAllocationService {
|
|||||||
if (!dtos || dtos.length === 0) {
|
if (!dtos || dtos.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let allocationUpdateToPropagate: IUpdatedSpaceAllocations[] = [];
|
const allocationUpdateToPropagate: IUpdatedSpaceAllocations[] = [];
|
||||||
|
|
||||||
const tagUuidsToDelete = dtos
|
const tagUuidsToDelete = dtos
|
||||||
.filter((dto) => dto.action === ModifyAction.DELETE && dto.tagUuid)
|
// .filter((dto) => dto.action === ModifyAction.DELETE && dto.tagUuid)
|
||||||
.map((dto) => dto.tagUuid);
|
.map((dto) => dto.tagUuid);
|
||||||
|
|
||||||
if (tagUuidsToDelete.length === 0) return [];
|
if (tagUuidsToDelete.length === 0) return [];
|
||||||
@ -329,7 +323,7 @@ export class SpaceModelProductAllocationService {
|
|||||||
SpaceModelProductAllocationEntity,
|
SpaceModelProductAllocationEntity,
|
||||||
{
|
{
|
||||||
where: {
|
where: {
|
||||||
tags: { uuid: In(tagUuidsToDelete) },
|
tag: In(tagUuidsToDelete),
|
||||||
spaceModel: {
|
spaceModel: {
|
||||||
uuid: spaceModel.uuid,
|
uuid: spaceModel.uuid,
|
||||||
},
|
},
|
||||||
@ -348,31 +342,28 @@ export class SpaceModelProductAllocationService {
|
|||||||
const allocationUpdates: SpaceModelProductAllocationEntity[] = [];
|
const allocationUpdates: SpaceModelProductAllocationEntity[] = [];
|
||||||
|
|
||||||
for (const allocation of allocationsToUpdate) {
|
for (const allocation of allocationsToUpdate) {
|
||||||
const updatedTags = allocation.tags.filter(
|
// const updatedTags = allocation.tags.filter(
|
||||||
(tag) => !tagUuidsToDelete.includes(tag.uuid),
|
// (tag) => !tagUuidsToDelete.includes(tag.uuid),
|
||||||
);
|
// );
|
||||||
|
// const deletedTags = allocation.tags.filter((tag) =>
|
||||||
const deletedTags = allocation.tags.filter((tag) =>
|
// tagUuidsToDelete.includes(tag.uuid),
|
||||||
tagUuidsToDelete.includes(tag.uuid),
|
// );
|
||||||
);
|
// if (updatedTags.length === allocation.tags.length) {
|
||||||
|
// continue;
|
||||||
if (updatedTags.length === allocation.tags.length) {
|
// }
|
||||||
continue;
|
// if (updatedTags.length === 0) {
|
||||||
}
|
// deletedAllocations.push(allocation);
|
||||||
|
// allocationUpdateToPropagate.push({
|
||||||
if (updatedTags.length === 0) {
|
// deletedAllocation: allocation,
|
||||||
deletedAllocations.push(allocation);
|
// });
|
||||||
allocationUpdateToPropagate.push({
|
// } else {
|
||||||
deletedAllocation: allocation,
|
// allocation.tags = updatedTags;
|
||||||
});
|
// allocationUpdates.push(allocation);
|
||||||
} else {
|
// allocationUpdateToPropagate.push({
|
||||||
allocation.tags = updatedTags;
|
// allocation: allocation,
|
||||||
allocationUpdates.push(allocation);
|
// tagsRemoved: deletedTags,
|
||||||
allocationUpdateToPropagate.push({
|
// });
|
||||||
allocation: allocation,
|
// }
|
||||||
tagsRemoved: deletedTags,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allocationUpdates.length > 0) {
|
if (allocationUpdates.length > 0) {
|
||||||
@ -415,33 +406,34 @@ export class SpaceModelProductAllocationService {
|
|||||||
tag: NewTagEntity,
|
tag: NewTagEntity,
|
||||||
spaceModel: SpaceModelEntity,
|
spaceModel: SpaceModelEntity,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const existingAllocationsForProduct = await queryRunner.manager.find(
|
|
||||||
SpaceModelProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
spaceModel: {
|
|
||||||
uuid: spaceModel.uuid,
|
|
||||||
},
|
|
||||||
product: {
|
|
||||||
uuid: tag.product.uuid,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const existingTagsForProduct = existingAllocationsForProduct.flatMap(
|
|
||||||
(allocation) => allocation.tags,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isDuplicateTag = existingTagsForProduct.some(
|
|
||||||
(existingTag) => existingTag.uuid === tag.uuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isDuplicateTag) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
// const existingAllocationsForProduct = await queryRunner.manager.find(
|
||||||
return false;
|
// SpaceModelProductAllocationEntity,
|
||||||
|
// {
|
||||||
|
// where: {
|
||||||
|
// spaceModel: {
|
||||||
|
// uuid: spaceModel.uuid,
|
||||||
|
// },
|
||||||
|
// product: {
|
||||||
|
// uuid: tag.product.uuid,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// relations: ['tags'],
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const existingTagsForProduct = existingAllocationsForProduct.flatMap(
|
||||||
|
// (allocation) => allocation.tags,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const isDuplicateTag = existingTagsForProduct.some(
|
||||||
|
// (existingTag) => existingTag.uuid === tag.uuid,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if (isDuplicateTag) {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async clearAllAllocations(spaceModelUuid: string, queryRunner: QueryRunner) {
|
async clearAllAllocations(spaceModelUuid: string, queryRunner: QueryRunner) {
|
||||||
|
@ -1,58 +1,47 @@
|
|||||||
import {
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
SpaceModelEntity,
|
|
||||||
SpaceModelProductAllocationEntity,
|
|
||||||
SpaceModelRepository,
|
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
} from '@app/common/modules/space-model';
|
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|
||||||
import {
|
|
||||||
CreateSpaceModelDto,
|
|
||||||
LinkSpacesToModelDto,
|
|
||||||
UpdateSpaceModelDto,
|
|
||||||
} from '../dtos';
|
|
||||||
import { ProjectParam } from 'src/community/dtos';
|
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
import { SubSpaceModelService } from './subspace/subspace-model.service';
|
|
||||||
import { DataSource, In, QueryRunner, SelectQueryBuilder } from 'typeorm';
|
|
||||||
import {
|
import {
|
||||||
TypeORMCustomModel,
|
TypeORMCustomModel,
|
||||||
TypeORMCustomModelFindAllQuery,
|
TypeORMCustomModelFindAllQuery,
|
||||||
} from '@app/common/models/typeOrmCustom.model';
|
} from '@app/common/models/typeOrmCustom.model';
|
||||||
import { SpaceModelParam } from '../dtos/space-model-param';
|
|
||||||
import { ProjectService } from 'src/project/services';
|
|
||||||
import { ProjectEntity } from '@app/common/modules/project/entities';
|
import { ProjectEntity } from '@app/common/modules/project/entities';
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
import {
|
||||||
|
SpaceProductAllocationRepository,
|
||||||
|
SpaceRepository,
|
||||||
|
} from '@app/common/modules/space';
|
||||||
|
import {
|
||||||
|
SpaceModelEntity,
|
||||||
|
SpaceModelRepository,
|
||||||
|
} from '@app/common/modules/space-model';
|
||||||
|
import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities/space-product-allocation.entity';
|
||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
|
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
|
||||||
|
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
||||||
|
import {
|
||||||
|
SubspaceProductAllocationRepository,
|
||||||
|
SubspaceRepository,
|
||||||
|
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { CommandBus } from '@nestjs/cqrs';
|
import { CommandBus } from '@nestjs/cqrs';
|
||||||
|
import { ProjectParam } from 'src/community/dtos';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
import { ProjectService } from 'src/project/services';
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
import { ProcessTagDto } from 'src/tags/dtos';
|
||||||
import { SpaceModelProductAllocationService } from './space-model-product-allocation.service';
|
import { DataSource, In, QueryRunner, SelectQueryBuilder } from 'typeorm';
|
||||||
import {
|
import {
|
||||||
PropogateDeleteSpaceModelCommand,
|
PropogateDeleteSpaceModelCommand,
|
||||||
PropogateUpdateSpaceModelCommand,
|
PropogateUpdateSpaceModelCommand,
|
||||||
PropogateUpdateSpaceModelProductAllocationCommand,
|
PropogateUpdateSpaceModelProductAllocationCommand,
|
||||||
} from '../commands';
|
} from '../commands';
|
||||||
import {
|
import {
|
||||||
SpaceProductAllocationRepository,
|
CreateSpaceModelDto,
|
||||||
SpaceRepository,
|
LinkSpacesToModelDto,
|
||||||
} from '@app/common/modules/space';
|
UpdateSpaceModelDto,
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
} from '../dtos';
|
||||||
import {
|
import { SpaceModelParam } from '../dtos/space-model-param';
|
||||||
SubspaceProductAllocationRepository,
|
import { ISubspaceModelUpdates, IUpdatedSpaceAllocations } from '../interfaces';
|
||||||
SubspaceRepository,
|
import { SpaceModelProductAllocationService } from './space-model-product-allocation.service';
|
||||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
import { SubSpaceModelService } from './subspace';
|
||||||
import {
|
|
||||||
ORPHAN_COMMUNITY_NAME,
|
|
||||||
ORPHAN_SPACE_NAME,
|
|
||||||
} from '@app/common/constants/orphan-constant';
|
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
|
||||||
import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities/space-product-allocation.entity';
|
|
||||||
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
|
||||||
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
|
|
||||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
|
||||||
import {
|
|
||||||
ISingleSubspaceModel,
|
|
||||||
ISubspaceModelUpdates,
|
|
||||||
IUpdatedSpaceAllocations,
|
|
||||||
} from '../interfaces';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SpaceModelService {
|
export class SpaceModelService {
|
||||||
@ -60,6 +49,7 @@ export class SpaceModelService {
|
|||||||
private readonly dataSource: DataSource,
|
private readonly dataSource: DataSource,
|
||||||
private readonly spaceModelRepository: SpaceModelRepository,
|
private readonly spaceModelRepository: SpaceModelRepository,
|
||||||
private readonly projectService: ProjectService,
|
private readonly projectService: ProjectService,
|
||||||
|
private readonly deviceService: DeviceService,
|
||||||
private readonly subSpaceModelService: SubSpaceModelService,
|
private readonly subSpaceModelService: SubSpaceModelService,
|
||||||
private commandBus: CommandBus,
|
private commandBus: CommandBus,
|
||||||
private readonly spaceModelProductAllocationService: SpaceModelProductAllocationService,
|
private readonly spaceModelProductAllocationService: SpaceModelProductAllocationService,
|
||||||
@ -67,7 +57,6 @@ export class SpaceModelService {
|
|||||||
private readonly spaceProductAllocationRepository: SpaceProductAllocationRepository,
|
private readonly spaceProductAllocationRepository: SpaceProductAllocationRepository,
|
||||||
private readonly subspaceRepository: SubspaceRepository,
|
private readonly subspaceRepository: SubspaceRepository,
|
||||||
private readonly subspaceProductAllocationRepository: SubspaceProductAllocationRepository,
|
private readonly subspaceProductAllocationRepository: SubspaceProductAllocationRepository,
|
||||||
private readonly deviceRepository: DeviceRepository,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createSpaceModel(
|
async createSpaceModel(
|
||||||
@ -161,7 +150,7 @@ export class SpaceModelService {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
pageable.include =
|
pageable.include =
|
||||||
'subspaceModels.productAllocations,subspaceModelProductAllocations.tags,subspaceModels, productAllocations, productAllocations.tags';
|
'subspaceModels.productAllocations,subspaceModelProductAllocations.tag,subspaceModelProductAllocations.product,subspaceModels, productAllocations, productAllocations.tag,productAllocations.product';
|
||||||
|
|
||||||
const queryBuilder = this.buildSpaceModelQuery(param.projectUuid);
|
const queryBuilder = this.buildSpaceModelQuery(param.projectUuid);
|
||||||
|
|
||||||
@ -231,7 +220,7 @@ export class SpaceModelService {
|
|||||||
spaceModel,
|
spaceModel,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
param.projectUuid,
|
param.projectUuid,
|
||||||
dto.tags,
|
// dto.tags,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,10 +375,10 @@ export class SpaceModelService {
|
|||||||
'productAllocations',
|
'productAllocations',
|
||||||
'subspaceModels',
|
'subspaceModels',
|
||||||
'productAllocations.product',
|
'productAllocations.product',
|
||||||
'productAllocations.tags',
|
'productAllocations.tag',
|
||||||
'subspaceModels.productAllocations',
|
'subspaceModels.productAllocations',
|
||||||
'subspaceModels.productAllocations.product',
|
'subspaceModels.productAllocations.product',
|
||||||
'subspaceModels.productAllocations.tags',
|
'subspaceModels.productAllocations.tag',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -408,10 +397,10 @@ export class SpaceModelService {
|
|||||||
'subspaces',
|
'subspaces',
|
||||||
'productAllocations',
|
'productAllocations',
|
||||||
'productAllocations.product',
|
'productAllocations.product',
|
||||||
'productAllocations.tags',
|
'productAllocations.tag',
|
||||||
'subspaces.productAllocations',
|
'subspaces.productAllocations',
|
||||||
'subspaces.productAllocations.product',
|
'subspaces.productAllocations.product',
|
||||||
'subspaces.productAllocations.product.tags',
|
'subspaces.productAllocations.product.tag',
|
||||||
'community',
|
'community',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -433,7 +422,7 @@ export class SpaceModelService {
|
|||||||
if (!hasDependencies && !space.spaceModel) {
|
if (!hasDependencies && !space.spaceModel) {
|
||||||
await this.linkToSpace(space, spaceModel);
|
await this.linkToSpace(space, spaceModel);
|
||||||
} else if (dto.overwrite) {
|
} else if (dto.overwrite) {
|
||||||
await this.overwriteSpace(space, project);
|
await this.removeSpaceOldSubspacesAndAllocations(space, project);
|
||||||
await this.linkToSpace(space, spaceModel);
|
await this.linkToSpace(space, spaceModel);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@ -470,10 +459,9 @@ export class SpaceModelService {
|
|||||||
space,
|
space,
|
||||||
inheritedFromModel: modelAllocation,
|
inheritedFromModel: modelAllocation,
|
||||||
product: modelAllocation.product,
|
product: modelAllocation.product,
|
||||||
tags: modelAllocation.tags,
|
tag: modelAllocation.tag,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (queryRunner) {
|
if (queryRunner) {
|
||||||
await queryRunner.manager.save(
|
await queryRunner.manager.save(
|
||||||
SpaceProductAllocationEntity,
|
SpaceProductAllocationEntity,
|
||||||
@ -491,23 +479,20 @@ export class SpaceModelService {
|
|||||||
subSpaceModel: subspaceModel,
|
subSpaceModel: subspaceModel,
|
||||||
space: space,
|
space: space,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (queryRunner) {
|
if (queryRunner) {
|
||||||
await queryRunner.manager.save(SubspaceEntity, subspace);
|
await queryRunner.manager.save(SubspaceEntity, subspace);
|
||||||
} else {
|
} else {
|
||||||
await this.subspaceRepository.save(subspace);
|
await this.subspaceRepository.save(subspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
const subspaceAllocations = subspaceModel.productAllocations.map(
|
const subspaceAllocations = subspaceModel.productAllocations.map(
|
||||||
(modelAllocation) =>
|
(modelAllocation) =>
|
||||||
this.subspaceProductAllocationRepository.create({
|
this.subspaceProductAllocationRepository.create({
|
||||||
subspace,
|
subspace,
|
||||||
inheritedFromModel: modelAllocation,
|
inheritedFromModel: modelAllocation,
|
||||||
product: modelAllocation.product,
|
product: modelAllocation.product,
|
||||||
tags: modelAllocation.tags,
|
tag: modelAllocation.tag,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (subspaceAllocations.length) {
|
if (subspaceAllocations.length) {
|
||||||
if (queryRunner) {
|
if (queryRunner) {
|
||||||
await queryRunner.manager.save(
|
await queryRunner.manager.save(
|
||||||
@ -530,7 +515,7 @@ export class SpaceModelService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async overwriteSpace(
|
async removeSpaceOldSubspacesAndAllocations(
|
||||||
space: SpaceEntity,
|
space: SpaceEntity,
|
||||||
project: ProjectEntity,
|
project: ProjectEntity,
|
||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
@ -548,14 +533,6 @@ export class SpaceModelService {
|
|||||||
? queryRunner.manager.getRepository(SubspaceProductAllocationEntity)
|
? queryRunner.manager.getRepository(SubspaceProductAllocationEntity)
|
||||||
: this.subspaceProductAllocationRepository;
|
: this.subspaceProductAllocationRepository;
|
||||||
|
|
||||||
const spaceRepository = queryRunner
|
|
||||||
? queryRunner.manager.getRepository(SpaceEntity)
|
|
||||||
: this.spaceRepository;
|
|
||||||
|
|
||||||
const deviceRepository = queryRunner
|
|
||||||
? queryRunner.manager.getRepository(DeviceEntity)
|
|
||||||
: this.deviceRepository;
|
|
||||||
|
|
||||||
if (space.productAllocations.length) {
|
if (space.productAllocations.length) {
|
||||||
await spaceProductAllocationRepository.delete({
|
await spaceProductAllocationRepository.delete({
|
||||||
uuid: In(
|
uuid: In(
|
||||||
@ -584,26 +561,7 @@ export class SpaceModelService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (space.devices.length > 0) {
|
if (space.devices.length > 0) {
|
||||||
const orphanSpace = await spaceRepository.findOne({
|
this.deviceService.addDevicesToOrphanSpace(space, project, queryRunner);
|
||||||
where: {
|
|
||||||
community: {
|
|
||||||
name: `${ORPHAN_COMMUNITY_NAME}-${project.name}`,
|
|
||||||
},
|
|
||||||
spaceName: ORPHAN_SPACE_NAME,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!orphanSpace) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Orphan space not found in community ${project.name}`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await deviceRepository.update(
|
|
||||||
{ uuid: In(space.devices.map((device) => device.uuid)) },
|
|
||||||
{ spaceDevice: orphanSpace },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -612,19 +570,6 @@ export class SpaceModelService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateName(modelName: string, projectUuid: string): Promise<void> {
|
|
||||||
const isModelExist = await this.spaceModelRepository.findOne({
|
|
||||||
where: { modelName, project: { uuid: projectUuid }, disabled: false },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isModelExist) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Model name ${modelName} already exists in the project with UUID ${projectUuid}.`,
|
|
||||||
HttpStatus.CONFLICT,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async validateNameUsingQueryRunner(
|
async validateNameUsingQueryRunner(
|
||||||
modelName: string,
|
modelName: string,
|
||||||
projectUuid: string,
|
projectUuid: string,
|
||||||
@ -726,14 +671,20 @@ export class SpaceModelService {
|
|||||||
'subspaceModelProductAllocations',
|
'subspaceModelProductAllocations',
|
||||||
)
|
)
|
||||||
.leftJoinAndSelect(
|
.leftJoinAndSelect(
|
||||||
'subspaceModelProductAllocations.tags',
|
'subspaceModelProductAllocations.tag',
|
||||||
'subspaceModelTags',
|
'subspaceModelTag',
|
||||||
|
)
|
||||||
|
.leftJoinAndSelect(
|
||||||
|
'subspaceModelProductAllocations.product',
|
||||||
|
'subspaceModelProduct',
|
||||||
)
|
)
|
||||||
.leftJoinAndSelect('subspaceModelTags.product', 'subspaceModelTagProduct')
|
|
||||||
.leftJoinAndSelect('spaceModel.productAllocations', 'productAllocations')
|
.leftJoinAndSelect('spaceModel.productAllocations', 'productAllocations')
|
||||||
.leftJoinAndSelect('productAllocations.product', 'allocatedProduct')
|
.leftJoinAndSelect('productAllocations.product', 'allocatedProduct')
|
||||||
.leftJoinAndSelect('productAllocations.tags', 'productTags')
|
.leftJoinAndSelect('productAllocations.tag', 'spaceModelTag')
|
||||||
.leftJoinAndSelect('productTags.product', 'productTagProduct')
|
.leftJoinAndSelect(
|
||||||
|
'productAllocations.product',
|
||||||
|
'productAllocationsProduct',
|
||||||
|
)
|
||||||
.where('spaceModel.disabled = false')
|
.where('spaceModel.disabled = false')
|
||||||
.andWhere('spaceModel.project = :projectUuid', { projectUuid });
|
.andWhere('spaceModel.project = :projectUuid', { projectUuid });
|
||||||
}
|
}
|
||||||
@ -753,39 +704,9 @@ export class SpaceModelService {
|
|||||||
updatedAt: subspace.updatedAt,
|
updatedAt: subspace.updatedAt,
|
||||||
subspaceName: subspace.subspaceName,
|
subspaceName: subspace.subspaceName,
|
||||||
disabled: subspace.disabled,
|
disabled: subspace.disabled,
|
||||||
tags: this.extractTags(subspace.productAllocations),
|
productAllocations: subspace.productAllocations,
|
||||||
})),
|
})),
|
||||||
tags: this.extractTags(spaceModel.productAllocations),
|
productAllocations: spaceModel.productAllocations,
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private extractTags(
|
|
||||||
productAllocations:
|
|
||||||
| SpaceModelProductAllocationEntity[]
|
|
||||||
| SubspaceModelProductAllocationEntity[]
|
|
||||||
| undefined,
|
|
||||||
): any[] {
|
|
||||||
if (!productAllocations) return [];
|
|
||||||
|
|
||||||
return productAllocations
|
|
||||||
.flatMap((allocation) => allocation.tags ?? [])
|
|
||||||
.map((tag) => ({
|
|
||||||
uuid: tag.uuid,
|
|
||||||
createdAt: tag.createdAt,
|
|
||||||
updatedAt: tag.updatedAt,
|
|
||||||
name: tag.name,
|
|
||||||
disabled: tag.disabled,
|
|
||||||
product: tag.product
|
|
||||||
? {
|
|
||||||
uuid: tag.product.uuid,
|
|
||||||
createdAt: tag.product.createdAt,
|
|
||||||
updatedAt: tag.product.updatedAt,
|
|
||||||
catName: tag.product.catName,
|
|
||||||
prodId: tag.product.prodId,
|
|
||||||
name: tag.product.name,
|
|
||||||
prodType: tag.product.prodType,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,9 +724,9 @@ export class SpaceModelService {
|
|||||||
updatedAt: subspace.updatedAt,
|
updatedAt: subspace.updatedAt,
|
||||||
subspaceName: subspace.subspaceName,
|
subspaceName: subspace.subspaceName,
|
||||||
disabled: subspace.disabled,
|
disabled: subspace.disabled,
|
||||||
tags: this.extractTags(subspace.productAllocations),
|
productAllocations: subspace.productAllocations,
|
||||||
})) ?? [],
|
})) ?? [],
|
||||||
tags: this.extractTags(spaceModel.productAllocations),
|
productAllocations: spaceModel.productAllocations,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,9 @@ import {
|
|||||||
} from '@app/common/modules/space-model';
|
} from '@app/common/modules/space-model';
|
||||||
import { NewTagEntity } from '@app/common/modules/tag';
|
import { NewTagEntity } from '@app/common/modules/tag';
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { ModifyTagModelDto } from 'src/space-model/dtos';
|
|
||||||
import { ISingleSubspaceModel } from 'src/space-model/interfaces';
|
import { ISingleSubspaceModel } from 'src/space-model/interfaces';
|
||||||
import { IUpdatedAllocations } from 'src/space-model/interfaces/subspace-product-allocation-update-result.interface';
|
import { IUpdatedAllocations } from 'src/space-model/interfaces/subspace-product-allocation-update-result.interface';
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
||||||
import { TagService as NewTagService } from 'src/tags/services';
|
import { TagService as NewTagService } from 'src/tags/services';
|
||||||
import { In, QueryRunner } from 'typeorm';
|
import { In, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
@ -31,172 +30,159 @@ export class SubspaceModelProductAllocationService {
|
|||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
spaceAllocationsToExclude?: SpaceModelProductAllocationEntity[],
|
spaceAllocationsToExclude?: SpaceModelProductAllocationEntity[],
|
||||||
): Promise<IUpdatedAllocations[]> {
|
): Promise<IUpdatedAllocations[]> {
|
||||||
try {
|
// try {
|
||||||
const updatedAllocations: IUpdatedAllocations[] = [];
|
const updatedAllocations: IUpdatedAllocations[] = [];
|
||||||
|
|
||||||
const allocations: SubspaceModelProductAllocationEntity[] = [];
|
|
||||||
|
|
||||||
for (const tag of tags) {
|
|
||||||
// Step 1: Check if this specific tag is already allocated at the space level
|
|
||||||
const existingTagInSpaceModel = await (queryRunner
|
|
||||||
? queryRunner.manager.findOne(SpaceModelProductAllocationEntity, {
|
|
||||||
where: {
|
|
||||||
spaceModel: {
|
|
||||||
uuid: spaceModel.uuid,
|
|
||||||
}, // Check at the space level
|
|
||||||
tags: { uuid: tag.uuid }, // Check for the specific tag
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
})
|
|
||||||
: this.spaceModelAllocationRepository.findOne({
|
|
||||||
where: {
|
|
||||||
spaceModel: {
|
|
||||||
uuid: spaceModel.uuid,
|
|
||||||
},
|
|
||||||
tags: { uuid: tag.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags', 'product'],
|
|
||||||
}));
|
|
||||||
|
|
||||||
const isExcluded = spaceAllocationsToExclude?.some(
|
|
||||||
(excludedAllocation) =>
|
|
||||||
excludedAllocation.product.uuid === tag.product.uuid &&
|
|
||||||
excludedAllocation.tags.some((t) => t.uuid === tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
// If tag is found at the space level, prevent allocation at the subspace level
|
|
||||||
if (!isExcluded && existingTagInSpaceModel) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag ${tag.uuid} (Product: ${tag.product.uuid}) is already allocated at the space level (${subspaceModel.spaceModel.uuid}). Cannot allocate the same tag in a subspace.`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this specific tag is already allocated within another subspace of the same space
|
|
||||||
const existingTagInSameSpace = await (queryRunner
|
|
||||||
? queryRunner.manager.findOne(SubspaceModelProductAllocationEntity, {
|
|
||||||
where: {
|
|
||||||
product: { uuid: tag.product.uuid },
|
|
||||||
subspaceModel: { spaceModel: subspaceModel.spaceModel },
|
|
||||||
tags: { uuid: tag.uuid }, // Ensure the exact tag is checked
|
|
||||||
},
|
|
||||||
relations: ['subspaceModel', 'tags'],
|
|
||||||
})
|
|
||||||
: this.subspaceModelProductAllocationRepository.findOne({
|
|
||||||
where: {
|
|
||||||
product: { uuid: tag.product.uuid },
|
|
||||||
subspaceModel: { spaceModel: subspaceModel.spaceModel },
|
|
||||||
tags: { uuid: tag.uuid },
|
|
||||||
},
|
|
||||||
relations: ['subspaceModel', 'tags'],
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Prevent duplicate allocation if tag exists in another subspace of the same space
|
|
||||||
if (
|
|
||||||
existingTagInSameSpace &&
|
|
||||||
existingTagInSameSpace.subspaceModel.uuid !== subspaceModel.uuid
|
|
||||||
) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag ${tag.uuid} (Product: ${tag.product.uuid}) is already allocated in another subspace (${existingTagInSameSpace.subspaceModel.uuid}) within the same space (${subspaceModel.spaceModel.uuid}).`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if there are existing allocations for this product in the subspace
|
|
||||||
const existingAllocationsForProduct = await (queryRunner
|
|
||||||
? queryRunner.manager.find(SubspaceModelProductAllocationEntity, {
|
|
||||||
where: {
|
|
||||||
subspaceModel: { uuid: subspaceModel.uuid },
|
|
||||||
product: { uuid: tag.product.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
})
|
|
||||||
: this.subspaceModelProductAllocationRepository.find({
|
|
||||||
where: {
|
|
||||||
subspaceModel: { uuid: subspaceModel.uuid },
|
|
||||||
product: { uuid: tag.product.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
}));
|
|
||||||
|
|
||||||
//Flatten all existing tags for this product in the subspace
|
|
||||||
const existingTagsForProduct = existingAllocationsForProduct.flatMap(
|
|
||||||
(allocation) => allocation.tags,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check if the tag is already assigned to the same product in this subspace
|
|
||||||
const isDuplicateTag = existingTagsForProduct.some(
|
|
||||||
(existingTag) => existingTag.uuid === tag.uuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isDuplicateTag) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag ${tag.uuid} is already allocated to product ${tag.product.uuid} within this subspace (${subspaceModel.uuid}).`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no existing allocation, create a new one
|
|
||||||
if (existingAllocationsForProduct.length === 0) {
|
|
||||||
const allocation = queryRunner
|
|
||||||
? queryRunner.manager.create(SubspaceModelProductAllocationEntity, {
|
|
||||||
subspaceModel,
|
|
||||||
product: tag.product,
|
|
||||||
tags: [tag],
|
|
||||||
})
|
|
||||||
: this.subspaceModelProductAllocationRepository.create({
|
|
||||||
subspaceModel,
|
|
||||||
product: tag.product,
|
|
||||||
tags: [tag],
|
|
||||||
});
|
|
||||||
allocations.push(allocation);
|
|
||||||
} else {
|
|
||||||
//If allocation exists, add the tag to it
|
|
||||||
existingAllocationsForProduct[0].tags.push(tag);
|
|
||||||
if (queryRunner) {
|
|
||||||
await queryRunner.manager.save(
|
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
existingAllocationsForProduct[0],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await this.subspaceModelProductAllocationRepository.save(
|
|
||||||
existingAllocationsForProduct[0],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
updatedAllocations.push({
|
|
||||||
allocation: existingAllocationsForProduct[0],
|
|
||||||
tagsAdded: [tag],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save newly created allocations
|
|
||||||
if (allocations.length > 0) {
|
|
||||||
if (queryRunner) {
|
|
||||||
await queryRunner.manager.save(
|
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
allocations,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await this.subspaceModelProductAllocationRepository.save(allocations);
|
|
||||||
}
|
|
||||||
|
|
||||||
allocations.forEach((allocation) => {
|
|
||||||
updatedAllocations.push({ newAllocation: allocation });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return updatedAllocations;
|
return updatedAllocations;
|
||||||
} catch (error) {
|
// const allocations: SubspaceModelProductAllocationEntity[] = [];
|
||||||
throw new HttpException(
|
// for (const tag of tags) {
|
||||||
`An unexpected error occurred while creating subspace product allocations ${error}`,
|
// // Step 1: Check if this specific tag is already allocated at the space level
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
// const existingTagInSpaceModel = await (queryRunner
|
||||||
);
|
// ? queryRunner.manager.findOne(SpaceModelProductAllocationEntity, {
|
||||||
}
|
// where: {
|
||||||
|
// spaceModel: {
|
||||||
|
// uuid: spaceModel.uuid,
|
||||||
|
// }, // Check at the space level
|
||||||
|
// tags: { uuid: tag.uuid }, // Check for the specific tag
|
||||||
|
// },
|
||||||
|
// relations: ['tags'],
|
||||||
|
// })
|
||||||
|
// : this.spaceModelAllocationRepository.findOne({
|
||||||
|
// where: {
|
||||||
|
// spaceModel: {
|
||||||
|
// uuid: spaceModel.uuid,
|
||||||
|
// },
|
||||||
|
// tags: { uuid: tag.uuid },
|
||||||
|
// },
|
||||||
|
// relations: ['tags', 'product'],
|
||||||
|
// }));
|
||||||
|
// const isExcluded = spaceAllocationsToExclude?.some(
|
||||||
|
// (excludedAllocation) =>
|
||||||
|
// excludedAllocation.product.uuid === tag.product.uuid &&
|
||||||
|
// excludedAllocation.tags.some((t) => t.uuid === tag.uuid),
|
||||||
|
// );
|
||||||
|
// // If tag is found at the space level, prevent allocation at the subspace level
|
||||||
|
// if (!isExcluded && existingTagInSpaceModel) {
|
||||||
|
// throw new HttpException(
|
||||||
|
// `Tag ${tag.uuid} (Product: ${tag.product.uuid}) is already allocated at the space level (${subspaceModel.spaceModel.uuid}). Cannot allocate the same tag in a subspace.`,
|
||||||
|
// HttpStatus.BAD_REQUEST,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// // Check if this specific tag is already allocated within another subspace of the same space
|
||||||
|
// const existingTagInSameSpace = await (queryRunner
|
||||||
|
// ? queryRunner.manager.findOne(SubspaceModelProductAllocationEntity, {
|
||||||
|
// where: {
|
||||||
|
// product: { uuid: tag.product.uuid },
|
||||||
|
// subspaceModel: { spaceModel: subspaceModel.spaceModel },
|
||||||
|
// tags: { uuid: tag.uuid }, // Ensure the exact tag is checked
|
||||||
|
// },
|
||||||
|
// relations: ['subspaceModel', 'tags'],
|
||||||
|
// })
|
||||||
|
// : this.subspaceModelProductAllocationRepository.findOne({
|
||||||
|
// where: {
|
||||||
|
// product: { uuid: tag.product.uuid },
|
||||||
|
// subspaceModel: { spaceModel: subspaceModel.spaceModel },
|
||||||
|
// tags: { uuid: tag.uuid },
|
||||||
|
// },
|
||||||
|
// relations: ['subspaceModel', 'tags'],
|
||||||
|
// }));
|
||||||
|
// // Prevent duplicate allocation if tag exists in another subspace of the same space
|
||||||
|
// if (
|
||||||
|
// existingTagInSameSpace &&
|
||||||
|
// existingTagInSameSpace.subspaceModel.uuid !== subspaceModel.uuid
|
||||||
|
// ) {
|
||||||
|
// throw new HttpException(
|
||||||
|
// `Tag ${tag.uuid} (Product: ${tag.product.uuid}) is already allocated in another subspace (${existingTagInSameSpace.subspaceModel.uuid}) within the same space (${subspaceModel.spaceModel.uuid}).`,
|
||||||
|
// HttpStatus.BAD_REQUEST,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// //Check if there are existing allocations for this product in the subspace
|
||||||
|
// const existingAllocationsForProduct = await (queryRunner
|
||||||
|
// ? queryRunner.manager.find(SubspaceModelProductAllocationEntity, {
|
||||||
|
// where: {
|
||||||
|
// subspaceModel: { uuid: subspaceModel.uuid },
|
||||||
|
// product: { uuid: tag.product.uuid },
|
||||||
|
// },
|
||||||
|
// relations: ['tags'],
|
||||||
|
// })
|
||||||
|
// : this.subspaceModelProductAllocationRepository.find({
|
||||||
|
// where: {
|
||||||
|
// subspaceModel: { uuid: subspaceModel.uuid },
|
||||||
|
// product: { uuid: tag.product.uuid },
|
||||||
|
// },
|
||||||
|
// relations: ['tags'],
|
||||||
|
// }));
|
||||||
|
// //Flatten all existing tags for this product in the subspace
|
||||||
|
// const existingTagsForProduct = existingAllocationsForProduct.flatMap(
|
||||||
|
// (allocation) => allocation.tags,
|
||||||
|
// );
|
||||||
|
// // Check if the tag is already assigned to the same product in this subspace
|
||||||
|
// const isDuplicateTag = existingTagsForProduct.some(
|
||||||
|
// (existingTag) => existingTag.uuid === tag.uuid,
|
||||||
|
// );
|
||||||
|
// if (isDuplicateTag) {
|
||||||
|
// throw new HttpException(
|
||||||
|
// `Tag ${tag.uuid} is already allocated to product ${tag.product.uuid} within this subspace (${subspaceModel.uuid}).`,
|
||||||
|
// HttpStatus.BAD_REQUEST,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// // If no existing allocation, create a new one
|
||||||
|
// if (existingAllocationsForProduct.length === 0) {
|
||||||
|
// const allocation = queryRunner
|
||||||
|
// ? queryRunner.manager.create(SubspaceModelProductAllocationEntity, {
|
||||||
|
// subspaceModel,
|
||||||
|
// product: tag.product,
|
||||||
|
// tags: [tag],
|
||||||
|
// })
|
||||||
|
// : this.subspaceModelProductAllocationRepository.create({
|
||||||
|
// subspaceModel,
|
||||||
|
// product: tag.product,
|
||||||
|
// tags: [tag],
|
||||||
|
// });
|
||||||
|
// allocations.push(allocation);
|
||||||
|
// } else {
|
||||||
|
// //If allocation exists, add the tag to it
|
||||||
|
// existingAllocationsForProduct[0].tags.push(tag);
|
||||||
|
// if (queryRunner) {
|
||||||
|
// await queryRunner.manager.save(
|
||||||
|
// SubspaceModelProductAllocationEntity,
|
||||||
|
// existingAllocationsForProduct[0],
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// await this.subspaceModelProductAllocationRepository.save(
|
||||||
|
// existingAllocationsForProduct[0],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// updatedAllocations.push({
|
||||||
|
// allocation: existingAllocationsForProduct[0],
|
||||||
|
// tagsAdded: [tag],
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // Save newly created allocations
|
||||||
|
// if (allocations.length > 0) {
|
||||||
|
// if (queryRunner) {
|
||||||
|
// await queryRunner.manager.save(
|
||||||
|
// SubspaceModelProductAllocationEntity,
|
||||||
|
// allocations,
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// await this.subspaceModelProductAllocationRepository.save(allocations);
|
||||||
|
// }
|
||||||
|
// allocations.forEach((allocation) => {
|
||||||
|
// updatedAllocations.push({ newAllocation: allocation });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// return updatedAllocations;
|
||||||
|
// } catch (error) {
|
||||||
|
// throw new HttpException(
|
||||||
|
// `An unexpected error occurred while creating subspace product allocations ${error}`,
|
||||||
|
// HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async processDeleteActions(
|
async processDeleteActions(
|
||||||
dtos: ModifyTagModelDto[],
|
dtos: ModifyTagDto[],
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
): Promise<SubspaceModelProductAllocationEntity[]> {
|
): Promise<SubspaceModelProductAllocationEntity[]> {
|
||||||
try {
|
try {
|
||||||
@ -205,7 +191,7 @@ export class SubspaceModelProductAllocationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tagUuidsToDelete = dtos
|
const tagUuidsToDelete = dtos
|
||||||
.filter((dto) => dto.action === ModifyAction.DELETE && dto.tagUuid)
|
// .filter((dto) => dto.action === ModifyAction.DELETE && dto.tagUuid)
|
||||||
.map((dto) => dto.tagUuid);
|
.map((dto) => dto.tagUuid);
|
||||||
|
|
||||||
if (tagUuidsToDelete.length === 0) return [];
|
if (tagUuidsToDelete.length === 0) return [];
|
||||||
@ -213,8 +199,7 @@ export class SubspaceModelProductAllocationService {
|
|||||||
const allocationsToUpdate = await queryRunner.manager.find(
|
const allocationsToUpdate = await queryRunner.manager.find(
|
||||||
SubspaceModelProductAllocationEntity,
|
SubspaceModelProductAllocationEntity,
|
||||||
{
|
{
|
||||||
where: { tags: { uuid: In(tagUuidsToDelete) } },
|
where: { tag: In(tagUuidsToDelete) },
|
||||||
relations: ['tags'],
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -224,20 +209,18 @@ export class SubspaceModelProductAllocationService {
|
|||||||
const allocationUpdates: SubspaceModelProductAllocationEntity[] = [];
|
const allocationUpdates: SubspaceModelProductAllocationEntity[] = [];
|
||||||
|
|
||||||
for (const allocation of allocationsToUpdate) {
|
for (const allocation of allocationsToUpdate) {
|
||||||
const updatedTags = allocation.tags.filter(
|
// const updatedTags = allocation.tags.filter(
|
||||||
(tag) => !tagUuidsToDelete.includes(tag.uuid),
|
// (tag) => !tagUuidsToDelete.includes(tag.uuid),
|
||||||
);
|
// );
|
||||||
|
// if (updatedTags.length === allocation.tags.length) {
|
||||||
if (updatedTags.length === allocation.tags.length) {
|
// continue;
|
||||||
continue;
|
// }
|
||||||
}
|
// if (updatedTags.length === 0) {
|
||||||
|
// deletedAllocations.push(allocation);
|
||||||
if (updatedTags.length === 0) {
|
// } else {
|
||||||
deletedAllocations.push(allocation);
|
// allocation.tags = updatedTags;
|
||||||
} else {
|
// allocationUpdates.push(allocation);
|
||||||
allocation.tags = updatedTags;
|
// }
|
||||||
allocationUpdates.push(allocation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allocationUpdates.length > 0) {
|
if (allocationUpdates.length > 0) {
|
||||||
@ -280,254 +263,255 @@ export class SubspaceModelProductAllocationService {
|
|||||||
projectUuid: string,
|
projectUuid: string,
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
spaceModel: SpaceModelEntity,
|
spaceModel: SpaceModelEntity,
|
||||||
spaceTagUpdateDtos?: ModifyTagModelDto[],
|
spaceTagUpdateDtos?: ModifyTagDto[],
|
||||||
): Promise<IUpdatedAllocations[]> {
|
) {
|
||||||
|
// : Promise<IUpdatedAllocations[]>
|
||||||
const spaceAllocationToExclude: SpaceModelProductAllocationEntity[] = [];
|
const spaceAllocationToExclude: SpaceModelProductAllocationEntity[] = [];
|
||||||
const updatedAllocations: IUpdatedAllocations[] = [];
|
const updatedAllocations: IUpdatedAllocations[] = [];
|
||||||
|
return updatedAllocations;
|
||||||
|
// for (const subspaceModel of subspaceModels) {
|
||||||
|
// const tagDtos = subspaceModel.tags;
|
||||||
|
// if (tagDtos.length > 0) {
|
||||||
|
// const tagsToAddDto: ProcessTagDto[] = tagDtos
|
||||||
|
// .filter((dto) => dto.action === ModifyAction.ADD)
|
||||||
|
// .map((dto) => ({
|
||||||
|
// name: dto.name,
|
||||||
|
// productUuid: dto.productUuid,
|
||||||
|
// uuid: dto.newTagUuid,
|
||||||
|
// }));
|
||||||
|
|
||||||
for (const subspaceModel of subspaceModels) {
|
// const tagsToDeleteDto = tagDtos.filter(
|
||||||
const tagDtos = subspaceModel.tags;
|
// (dto) => dto.action === ModifyAction.DELETE,
|
||||||
if (tagDtos.length > 0) {
|
// );
|
||||||
const tagsToAddDto: ProcessTagDto[] = tagDtos
|
|
||||||
.filter((dto) => dto.action === ModifyAction.ADD)
|
|
||||||
.map((dto) => ({
|
|
||||||
name: dto.name,
|
|
||||||
productUuid: dto.productUuid,
|
|
||||||
uuid: dto.newTagUuid,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const tagsToDeleteDto = tagDtos.filter(
|
// if (tagsToAddDto.length > 0) {
|
||||||
(dto) => dto.action === ModifyAction.DELETE,
|
// let processedTags = await this.tagService.processTags(
|
||||||
);
|
// tagsToAddDto,
|
||||||
|
// projectUuid,
|
||||||
|
// queryRunner,
|
||||||
|
// );
|
||||||
|
|
||||||
if (tagsToAddDto.length > 0) {
|
// for (const subspaceDto of subspaceModels) {
|
||||||
let processedTags = await this.tagService.processTags(
|
// if (
|
||||||
tagsToAddDto,
|
// subspaceDto !== subspaceModel &&
|
||||||
projectUuid,
|
// subspaceDto.action === ModifyAction.UPDATE &&
|
||||||
queryRunner,
|
// subspaceDto.tags
|
||||||
);
|
// ) {
|
||||||
|
// // Tag is deleted from one subspace and added in another subspace
|
||||||
|
// const deletedTags = subspaceDto.tags.filter(
|
||||||
|
// (tagDto) =>
|
||||||
|
// tagDto.action === ModifyAction.DELETE &&
|
||||||
|
// processedTags.some((tag) => tag.uuid === tagDto.tagUuid),
|
||||||
|
// );
|
||||||
|
|
||||||
for (const subspaceDto of subspaceModels) {
|
// for (const deletedTag of deletedTags) {
|
||||||
if (
|
// const allocation = await queryRunner.manager.findOne(
|
||||||
subspaceDto !== subspaceModel &&
|
// SubspaceModelProductAllocationEntity,
|
||||||
subspaceDto.action === ModifyAction.UPDATE &&
|
// {
|
||||||
subspaceDto.tags
|
// where: {
|
||||||
) {
|
// tags: {
|
||||||
// Tag is deleted from one subspace and added in another subspace
|
// uuid: deletedTag.tagUuid,
|
||||||
const deletedTags = subspaceDto.tags.filter(
|
// },
|
||||||
(tagDto) =>
|
// subspaceModel: {
|
||||||
tagDto.action === ModifyAction.DELETE &&
|
// uuid: subspaceDto.subspaceModel.uuid,
|
||||||
processedTags.some((tag) => tag.uuid === tagDto.tagUuid),
|
// },
|
||||||
);
|
// },
|
||||||
|
// relations: ['tags', 'product', 'subspaceModel'],
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// if (allocation) {
|
||||||
|
// const isCommonTag = allocation.tags.some(
|
||||||
|
// (tag) => tag.uuid === deletedTag.tagUuid,
|
||||||
|
// );
|
||||||
|
|
||||||
for (const deletedTag of deletedTags) {
|
// if (allocation && isCommonTag) {
|
||||||
const allocation = await queryRunner.manager.findOne(
|
// const tagEntity = allocation.tags.find(
|
||||||
SubspaceModelProductAllocationEntity,
|
// (tag) => tag.uuid === deletedTag.tagUuid,
|
||||||
{
|
// );
|
||||||
where: {
|
|
||||||
tags: {
|
|
||||||
uuid: deletedTag.tagUuid,
|
|
||||||
},
|
|
||||||
subspaceModel: {
|
|
||||||
uuid: subspaceDto.subspaceModel.uuid,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
relations: ['tags', 'product', 'subspaceModel'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (allocation) {
|
|
||||||
const isCommonTag = allocation.tags.some(
|
|
||||||
(tag) => tag.uuid === deletedTag.tagUuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (allocation && isCommonTag) {
|
// allocation.tags = allocation.tags.filter(
|
||||||
const tagEntity = allocation.tags.find(
|
// (tag) => tag.uuid !== deletedTag.tagUuid,
|
||||||
(tag) => tag.uuid === deletedTag.tagUuid,
|
// );
|
||||||
);
|
|
||||||
|
|
||||||
allocation.tags = allocation.tags.filter(
|
// updatedAllocations.push({
|
||||||
(tag) => tag.uuid !== deletedTag.tagUuid,
|
// allocation,
|
||||||
);
|
// tagsRemoved: [tagEntity],
|
||||||
|
// });
|
||||||
|
|
||||||
updatedAllocations.push({
|
// await queryRunner.manager.save(allocation);
|
||||||
allocation,
|
|
||||||
tagsRemoved: [tagEntity],
|
|
||||||
});
|
|
||||||
|
|
||||||
await queryRunner.manager.save(allocation);
|
// const productAllocationExistInSubspace =
|
||||||
|
// await queryRunner.manager.findOne(
|
||||||
|
// SubspaceModelProductAllocationEntity,
|
||||||
|
// {
|
||||||
|
// where: {
|
||||||
|
// subspaceModel: {
|
||||||
|
// uuid: subspaceDto.subspaceModel.uuid,
|
||||||
|
// },
|
||||||
|
// product: { uuid: allocation.product.uuid },
|
||||||
|
// },
|
||||||
|
// relations: ['tags'],
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
const productAllocationExistInSubspace =
|
// if (productAllocationExistInSubspace) {
|
||||||
await queryRunner.manager.findOne(
|
// productAllocationExistInSubspace.tags.push(tagEntity);
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
subspaceModel: {
|
|
||||||
uuid: subspaceDto.subspaceModel.uuid,
|
|
||||||
},
|
|
||||||
product: { uuid: allocation.product.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (productAllocationExistInSubspace) {
|
// updatedAllocations.push({
|
||||||
productAllocationExistInSubspace.tags.push(tagEntity);
|
// allocation: productAllocationExistInSubspace,
|
||||||
|
// tagsAdded: [tagEntity],
|
||||||
|
// });
|
||||||
|
|
||||||
updatedAllocations.push({
|
// await queryRunner.manager.save(
|
||||||
allocation: productAllocationExistInSubspace,
|
// productAllocationExistInSubspace,
|
||||||
tagsAdded: [tagEntity],
|
// );
|
||||||
});
|
// } else {
|
||||||
|
// const newProductAllocation = queryRunner.manager.create(
|
||||||
|
// SubspaceModelProductAllocationEntity,
|
||||||
|
// {
|
||||||
|
// subspaceModel: subspaceModel.subspaceModel,
|
||||||
|
// product: allocation.product,
|
||||||
|
// tags: [tagEntity],
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
await queryRunner.manager.save(
|
// updatedAllocations.push({
|
||||||
productAllocationExistInSubspace,
|
// allocation: newProductAllocation,
|
||||||
);
|
// });
|
||||||
} else {
|
|
||||||
const newProductAllocation = queryRunner.manager.create(
|
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
{
|
|
||||||
subspaceModel: subspaceModel.subspaceModel,
|
|
||||||
product: allocation.product,
|
|
||||||
tags: [tagEntity],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
updatedAllocations.push({
|
// await queryRunner.manager.save(newProductAllocation);
|
||||||
allocation: newProductAllocation,
|
// }
|
||||||
});
|
|
||||||
|
|
||||||
await queryRunner.manager.save(newProductAllocation);
|
// // Remove the tag from processedTags to prevent duplication
|
||||||
}
|
// processedTags = processedTags.filter(
|
||||||
|
// (tag) => tag.uuid !== deletedTag.tagUuid,
|
||||||
|
// );
|
||||||
|
|
||||||
// Remove the tag from processedTags to prevent duplication
|
// // Remove the tag from subspaceDto.tags to ensure it's not processed again while processing other dtos.
|
||||||
processedTags = processedTags.filter(
|
// subspaceDto.tags = subspaceDto.tags.filter(
|
||||||
(tag) => tag.uuid !== deletedTag.tagUuid,
|
// (tagDto) => tagDto.tagUuid !== deletedTag.tagUuid,
|
||||||
);
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (
|
||||||
|
// subspaceDto !== subspaceModel &&
|
||||||
|
// subspaceDto.action === ModifyAction.DELETE
|
||||||
|
// ) {
|
||||||
|
// const allocation = await queryRunner.manager.findOne(
|
||||||
|
// SubspaceModelProductAllocationEntity,
|
||||||
|
// {
|
||||||
|
// where: {
|
||||||
|
// subspaceModel: { uuid: subspaceDto.subspaceModel.uuid },
|
||||||
|
// },
|
||||||
|
// relations: ['tags'],
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
// Remove the tag from subspaceDto.tags to ensure it's not processed again while processing other dtos.
|
// const repeatedTags = allocation?.tags.filter((tag) =>
|
||||||
subspaceDto.tags = subspaceDto.tags.filter(
|
// processedTags.some(
|
||||||
(tagDto) => tagDto.tagUuid !== deletedTag.tagUuid,
|
// (processedTag) => processedTag.uuid === tag.uuid,
|
||||||
);
|
// ),
|
||||||
}
|
// );
|
||||||
}
|
// if (repeatedTags.length > 0) {
|
||||||
}
|
// allocation.tags = allocation.tags.filter(
|
||||||
}
|
// (tag) =>
|
||||||
if (
|
// !repeatedTags.some(
|
||||||
subspaceDto !== subspaceModel &&
|
// (repeatedTag) => repeatedTag.uuid === tag.uuid,
|
||||||
subspaceDto.action === ModifyAction.DELETE
|
// ),
|
||||||
) {
|
// );
|
||||||
const allocation = await queryRunner.manager.findOne(
|
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
subspaceModel: { uuid: subspaceDto.subspaceModel.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const repeatedTags = allocation?.tags.filter((tag) =>
|
// updatedAllocations.push({
|
||||||
processedTags.some(
|
// allocation: allocation,
|
||||||
(processedTag) => processedTag.uuid === tag.uuid,
|
// tagsRemoved: repeatedTags,
|
||||||
),
|
// });
|
||||||
);
|
|
||||||
if (repeatedTags.length > 0) {
|
|
||||||
allocation.tags = allocation.tags.filter(
|
|
||||||
(tag) =>
|
|
||||||
!repeatedTags.some(
|
|
||||||
(repeatedTag) => repeatedTag.uuid === tag.uuid,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
updatedAllocations.push({
|
// await queryRunner.manager.save(allocation);
|
||||||
allocation: allocation,
|
|
||||||
tagsRemoved: repeatedTags,
|
|
||||||
});
|
|
||||||
|
|
||||||
await queryRunner.manager.save(allocation);
|
// const productAllocationExistInSubspace =
|
||||||
|
// await queryRunner.manager.findOne(
|
||||||
|
// SubspaceModelProductAllocationEntity,
|
||||||
|
// {
|
||||||
|
// where: {
|
||||||
|
// subspaceModel: { uuid: subspaceDto.subspaceModel.uuid },
|
||||||
|
// product: { uuid: allocation.product.uuid },
|
||||||
|
// },
|
||||||
|
// relations: ['tags'],
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
const productAllocationExistInSubspace =
|
// if (productAllocationExistInSubspace) {
|
||||||
await queryRunner.manager.findOne(
|
// updatedAllocations.push({
|
||||||
SubspaceModelProductAllocationEntity,
|
// allocation: productAllocationExistInSubspace,
|
||||||
{
|
// tagsAdded: repeatedTags,
|
||||||
where: {
|
// });
|
||||||
subspaceModel: { uuid: subspaceDto.subspaceModel.uuid },
|
|
||||||
product: { uuid: allocation.product.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (productAllocationExistInSubspace) {
|
// productAllocationExistInSubspace.tags.push(...repeatedTags);
|
||||||
updatedAllocations.push({
|
// await queryRunner.manager.save(
|
||||||
allocation: productAllocationExistInSubspace,
|
// productAllocationExistInSubspace,
|
||||||
tagsAdded: repeatedTags,
|
// );
|
||||||
});
|
// } else {
|
||||||
|
// const newProductAllocation = queryRunner.manager.create(
|
||||||
|
// SubspaceModelProductAllocationEntity,
|
||||||
|
// {
|
||||||
|
// subspaceModel: subspaceModel.subspaceModel,
|
||||||
|
// product: allocation.product,
|
||||||
|
// tags: repeatedTags,
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
productAllocationExistInSubspace.tags.push(...repeatedTags);
|
// updatedAllocations.push({
|
||||||
await queryRunner.manager.save(
|
// newAllocation: newProductAllocation,
|
||||||
productAllocationExistInSubspace,
|
// });
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const newProductAllocation = queryRunner.manager.create(
|
|
||||||
SubspaceModelProductAllocationEntity,
|
|
||||||
{
|
|
||||||
subspaceModel: subspaceModel.subspaceModel,
|
|
||||||
product: allocation.product,
|
|
||||||
tags: repeatedTags,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
updatedAllocations.push({
|
// await queryRunner.manager.save(newProductAllocation);
|
||||||
newAllocation: newProductAllocation,
|
// }
|
||||||
});
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (spaceTagUpdateDtos) {
|
||||||
|
// const deletedSpaceTags = spaceTagUpdateDtos.filter(
|
||||||
|
// (tagDto) =>
|
||||||
|
// tagDto.action === ModifyAction.DELETE &&
|
||||||
|
// processedTags.some((tag) => tag.uuid === tagDto.tagUuid),
|
||||||
|
// );
|
||||||
|
// for (const deletedTag of deletedSpaceTags) {
|
||||||
|
// const allocation = await queryRunner.manager.findOne(
|
||||||
|
// SpaceModelProductAllocationEntity,
|
||||||
|
// {
|
||||||
|
// where: {
|
||||||
|
// spaceModel: { uuid: spaceModel.uuid },
|
||||||
|
// tags: { uuid: deletedTag.tagUuid },
|
||||||
|
// },
|
||||||
|
// relations: ['tags', 'product'],
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
await queryRunner.manager.save(newProductAllocation);
|
// if (
|
||||||
}
|
// allocation &&
|
||||||
}
|
// allocation.tags.some((tag) => tag.uuid === deletedTag.tagUuid)
|
||||||
}
|
// ) {
|
||||||
}
|
// spaceAllocationToExclude.push(allocation);
|
||||||
if (spaceTagUpdateDtos) {
|
// }
|
||||||
const deletedSpaceTags = spaceTagUpdateDtos.filter(
|
// }
|
||||||
(tagDto) =>
|
// }
|
||||||
tagDto.action === ModifyAction.DELETE &&
|
|
||||||
processedTags.some((tag) => tag.uuid === tagDto.tagUuid),
|
|
||||||
);
|
|
||||||
for (const deletedTag of deletedSpaceTags) {
|
|
||||||
const allocation = await queryRunner.manager.findOne(
|
|
||||||
SpaceModelProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
spaceModel: { uuid: spaceModel.uuid },
|
|
||||||
tags: { uuid: deletedTag.tagUuid },
|
|
||||||
},
|
|
||||||
relations: ['tags', 'product'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
// // Create new product allocations
|
||||||
allocation &&
|
// const newAllocations = await this.createProductAllocations(
|
||||||
allocation.tags.some((tag) => tag.uuid === deletedTag.tagUuid)
|
// subspaceModel.subspaceModel,
|
||||||
) {
|
// spaceModel,
|
||||||
spaceAllocationToExclude.push(allocation);
|
// processedTags,
|
||||||
}
|
// queryRunner,
|
||||||
}
|
// spaceAllocationToExclude,
|
||||||
}
|
// );
|
||||||
|
// return [...updatedAllocations, ...newAllocations];
|
||||||
// Create new product allocations
|
// }
|
||||||
const newAllocations = await this.createProductAllocations(
|
// if (tagsToDeleteDto.length > 0) {
|
||||||
subspaceModel.subspaceModel,
|
// await this.processDeleteActions(tagsToDeleteDto, queryRunner);
|
||||||
spaceModel,
|
// }
|
||||||
processedTags,
|
// }
|
||||||
queryRunner,
|
// }
|
||||||
spaceAllocationToExclude,
|
|
||||||
);
|
|
||||||
return [...updatedAllocations, ...newAllocations];
|
|
||||||
}
|
|
||||||
if (tagsToDeleteDto.length > 0) {
|
|
||||||
await this.processDeleteActions(tagsToDeleteDto, queryRunner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async clearAllAllocations(subspaceIds: string[], queryRunner: QueryRunner) {
|
async clearAllAllocations(subspaceIds: string[], queryRunner: QueryRunner) {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
||||||
import {
|
import {
|
||||||
SpaceModelEntity,
|
SpaceModelEntity,
|
||||||
SpaceModelProductAllocationEntity,
|
SpaceModelProductAllocationEntity,
|
||||||
@ -5,21 +6,21 @@ import {
|
|||||||
SubspaceModelProductAllocationEntity,
|
SubspaceModelProductAllocationEntity,
|
||||||
SubspaceModelRepository,
|
SubspaceModelRepository,
|
||||||
} from '@app/common/modules/space-model';
|
} from '@app/common/modules/space-model';
|
||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { CreateSubspaceModelDto, ModifyTagModelDto } from '../../dtos';
|
|
||||||
import { In, Not, QueryFailedError, QueryRunner } from 'typeorm';
|
|
||||||
import { ModifySubspaceModelDto } from 'src/space-model/dtos/subspaces-model-dtos';
|
import { ModifySubspaceModelDto } from 'src/space-model/dtos/subspaces-model-dtos';
|
||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
|
||||||
import { TagService } from 'src/tags/services';
|
|
||||||
import { SubspaceModelProductAllocationService } from './subspace-model-product-allocation.service';
|
|
||||||
import {
|
import {
|
||||||
IRelocatedAllocation,
|
IRelocatedAllocation,
|
||||||
ISingleSubspaceModel,
|
ISingleSubspaceModel,
|
||||||
ISubspaceModelUpdates,
|
ISubspaceModelUpdates,
|
||||||
} from 'src/space-model/interfaces';
|
} from 'src/space-model/interfaces';
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
||||||
import { SubSpaceService } from 'src/space/services/subspace';
|
import { SubSpaceService } from 'src/space/services/subspace';
|
||||||
|
import { ProcessTagDto } from 'src/tags/dtos';
|
||||||
|
import { TagService } from 'src/tags/services';
|
||||||
|
import { In, Not, QueryFailedError, QueryRunner } from 'typeorm';
|
||||||
|
import { CreateSubspaceModelDto } from '../../dtos';
|
||||||
|
import { SubspaceModelProductAllocationService } from './subspace-model-product-allocation.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SubSpaceModelService {
|
export class SubSpaceModelService {
|
||||||
@ -117,7 +118,7 @@ export class SubSpaceModelService {
|
|||||||
spaceModel: SpaceModelEntity,
|
spaceModel: SpaceModelEntity,
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
projectUuid: string,
|
projectUuid: string,
|
||||||
spaceTagUpdateDtos?: ModifyTagModelDto[],
|
spaceTagUpdateDtos?: ModifyTagDto[],
|
||||||
spaces?: SpaceEntity[],
|
spaces?: SpaceEntity[],
|
||||||
): Promise<ISubspaceModelUpdates> {
|
): Promise<ISubspaceModelUpdates> {
|
||||||
try {
|
try {
|
||||||
@ -152,7 +153,7 @@ export class SubSpaceModelService {
|
|||||||
projectUuid,
|
projectUuid,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
spaceModel,
|
spaceModel,
|
||||||
spaceTagUpdateDtos,
|
// spaceTagUpdateDtos,
|
||||||
);
|
);
|
||||||
|
|
||||||
const deletedSubspaces = await this.deleteSubspaceModels(
|
const deletedSubspaces = await this.deleteSubspaceModels(
|
||||||
@ -188,7 +189,7 @@ export class SubSpaceModelService {
|
|||||||
deleteDtos: ModifySubspaceModelDto[],
|
deleteDtos: ModifySubspaceModelDto[],
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
spaceModel: SpaceModelEntity,
|
spaceModel: SpaceModelEntity,
|
||||||
spaceTagUpdateDtos?: ModifyTagModelDto[],
|
spaceTagUpdateDtos?: ModifyTagDto[],
|
||||||
): Promise<ISingleSubspaceModel[]> {
|
): Promise<ISingleSubspaceModel[]> {
|
||||||
try {
|
try {
|
||||||
if (!deleteDtos || deleteDtos.length === 0) {
|
if (!deleteDtos || deleteDtos.length === 0) {
|
||||||
@ -230,92 +231,82 @@ export class SubSpaceModelService {
|
|||||||
>();
|
>();
|
||||||
|
|
||||||
for (const allocation of allocationsToRemove) {
|
for (const allocation of allocationsToRemove) {
|
||||||
const product = allocation.product;
|
// const product = allocation.product;
|
||||||
const tags = allocation.tags;
|
// const tags = allocation.tags;
|
||||||
const subspaceUuid = allocation.subspaceModel.uuid;
|
// const subspaceUuid = allocation.subspaceModel.uuid;
|
||||||
const spaceAllocationKey = `${spaceModel.uuid}-${product.uuid}`;
|
// const spaceAllocationKey = `${spaceModel.uuid}-${product.uuid}`;
|
||||||
|
// if (!spaceAllocationsMap.has(spaceAllocationKey)) {
|
||||||
if (!spaceAllocationsMap.has(spaceAllocationKey)) {
|
// const spaceAllocation = await queryRunner.manager.findOne(
|
||||||
const spaceAllocation = await queryRunner.manager.findOne(
|
// SpaceModelProductAllocationEntity,
|
||||||
SpaceModelProductAllocationEntity,
|
// {
|
||||||
{
|
// where: {
|
||||||
where: {
|
// spaceModel: { uuid: spaceModel.uuid },
|
||||||
spaceModel: { uuid: spaceModel.uuid },
|
// product: { uuid: product.uuid },
|
||||||
product: { uuid: product.uuid },
|
// },
|
||||||
},
|
// relations: ['tags'],
|
||||||
relations: ['tags'],
|
// },
|
||||||
},
|
// );
|
||||||
);
|
// if (spaceAllocation) {
|
||||||
if (spaceAllocation) {
|
// spaceAllocationsMap.set(spaceAllocationKey, spaceAllocation);
|
||||||
spaceAllocationsMap.set(spaceAllocationKey, spaceAllocation);
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// const movedToAlreadyExistingSpaceAllocations: IRelocatedAllocation[] =
|
||||||
|
// [];
|
||||||
const movedToAlreadyExistingSpaceAllocations: IRelocatedAllocation[] =
|
// const spaceAllocation = spaceAllocationsMap.get(spaceAllocationKey);
|
||||||
[];
|
// if (spaceAllocation) {
|
||||||
const spaceAllocation = spaceAllocationsMap.get(spaceAllocationKey);
|
// const existingTagUuids = new Set(
|
||||||
|
// spaceAllocation.tags.map((tag) => tag.uuid),
|
||||||
if (spaceAllocation) {
|
// );
|
||||||
const existingTagUuids = new Set(
|
// const newTags = tags.filter(
|
||||||
spaceAllocation.tags.map((tag) => tag.uuid),
|
// (tag) => !existingTagUuids.has(tag.uuid),
|
||||||
);
|
// );
|
||||||
const newTags = tags.filter(
|
// if (newTags.length > 0) {
|
||||||
(tag) => !existingTagUuids.has(tag.uuid),
|
// movedToAlreadyExistingSpaceAllocations.push({
|
||||||
);
|
// tags: newTags,
|
||||||
|
// allocation: spaceAllocation,
|
||||||
if (newTags.length > 0) {
|
// });
|
||||||
movedToAlreadyExistingSpaceAllocations.push({
|
// spaceAllocation.tags.push(...newTags);
|
||||||
tags: newTags,
|
// await queryRunner.manager.save(spaceAllocation);
|
||||||
allocation: spaceAllocation,
|
// }
|
||||||
});
|
// } else {
|
||||||
spaceAllocation.tags.push(...newTags);
|
// let tagsToAdd = [...tags];
|
||||||
|
// if (spaceTagUpdateDtos && spaceTagUpdateDtos.length > 0) {
|
||||||
await queryRunner.manager.save(spaceAllocation);
|
// const spaceTagDtosToAdd = spaceTagUpdateDtos.filter(
|
||||||
}
|
// (dto) => dto.action === ModifyAction.ADD,
|
||||||
} else {
|
// );
|
||||||
let tagsToAdd = [...tags];
|
// tagsToAdd = tagsToAdd.filter(
|
||||||
|
// (tag) =>
|
||||||
if (spaceTagUpdateDtos && spaceTagUpdateDtos.length > 0) {
|
// !spaceTagDtosToAdd.some(
|
||||||
const spaceTagDtosToAdd = spaceTagUpdateDtos.filter(
|
// (addDto) =>
|
||||||
(dto) => dto.action === ModifyAction.ADD,
|
// (addDto.name && addDto.name === tag.name) ||
|
||||||
);
|
// (addDto.newTagUuid && addDto.newTagUuid === tag.uuid),
|
||||||
|
// ),
|
||||||
tagsToAdd = tagsToAdd.filter(
|
// );
|
||||||
(tag) =>
|
// }
|
||||||
!spaceTagDtosToAdd.some(
|
// if (tagsToAdd.length > 0) {
|
||||||
(addDto) =>
|
// const newSpaceAllocation = queryRunner.manager.create(
|
||||||
(addDto.name && addDto.name === tag.name) ||
|
// SpaceModelProductAllocationEntity,
|
||||||
(addDto.newTagUuid && addDto.newTagUuid === tag.uuid),
|
// {
|
||||||
),
|
// spaceModel: spaceModel,
|
||||||
);
|
// product: product,
|
||||||
}
|
// tags: tags,
|
||||||
|
// },
|
||||||
if (tagsToAdd.length > 0) {
|
// );
|
||||||
const newSpaceAllocation = queryRunner.manager.create(
|
// movedToAlreadyExistingSpaceAllocations.push({
|
||||||
SpaceModelProductAllocationEntity,
|
// allocation: newSpaceAllocation,
|
||||||
{
|
// tags: tags,
|
||||||
spaceModel: spaceModel,
|
// });
|
||||||
product: product,
|
// await queryRunner.manager.save(newSpaceAllocation);
|
||||||
tags: tags,
|
// }
|
||||||
},
|
// }
|
||||||
);
|
// if (movedToAlreadyExistingSpaceAllocations.length > 0) {
|
||||||
|
// if (!relocatedAllocationsMap.has(subspaceUuid)) {
|
||||||
movedToAlreadyExistingSpaceAllocations.push({
|
// relocatedAllocationsMap.set(subspaceUuid, []);
|
||||||
allocation: newSpaceAllocation,
|
// }
|
||||||
tags: tags,
|
// relocatedAllocationsMap
|
||||||
});
|
// .get(subspaceUuid)
|
||||||
await queryRunner.manager.save(newSpaceAllocation);
|
// .push(...movedToAlreadyExistingSpaceAllocations);
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
if (movedToAlreadyExistingSpaceAllocations.length > 0) {
|
|
||||||
if (!relocatedAllocationsMap.has(subspaceUuid)) {
|
|
||||||
relocatedAllocationsMap.set(subspaceUuid, []);
|
|
||||||
}
|
|
||||||
relocatedAllocationsMap
|
|
||||||
.get(subspaceUuid)
|
|
||||||
.push(...movedToAlreadyExistingSpaceAllocations);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await queryRunner.manager.remove(
|
await queryRunner.manager.remove(
|
||||||
@ -404,7 +395,7 @@ export class SubSpaceModelService {
|
|||||||
|
|
||||||
const updatedSubspaces: {
|
const updatedSubspaces: {
|
||||||
subspaceModel: SubspaceModelEntity;
|
subspaceModel: SubspaceModelEntity;
|
||||||
tags: ModifyTagModelDto[];
|
tags: ModifyTagDto[];
|
||||||
action: ModifyAction.UPDATE;
|
action: ModifyAction.UPDATE;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
@ -508,12 +499,6 @@ export class SubSpaceModelService {
|
|||||||
return subspaceModels.flatMap((subspace) => subspace.tags || []);
|
return subspaceModels.flatMap((subspace) => subspace.tags || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
extractTagsFromModifiedSubspaceModels(
|
|
||||||
subspaceModels: ModifySubspaceModelDto[],
|
|
||||||
): ModifyTagModelDto[] {
|
|
||||||
return subspaceModels.flatMap((subspace) => subspace.tags || []);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getSubspacesByUuids(
|
private async getSubspacesByUuids(
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
subspaceUuids: string[],
|
subspaceUuids: string[],
|
||||||
|
@ -1,34 +1,50 @@
|
|||||||
import { SpaceRepositoryModule } from '@app/common/modules/space/space.repository.module';
|
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
||||||
import { Module } from '@nestjs/common';
|
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
||||||
import { SpaceModelController } from './controllers';
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
import { SpaceModelService, SubSpaceModelService } from './services';
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
|
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
||||||
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
import {
|
import {
|
||||||
SpaceModelProductAllocationRepoitory,
|
PowerClampDailyRepository,
|
||||||
SpaceModelRepository,
|
PowerClampHourlyRepository,
|
||||||
SubspaceModelProductAllocationRepoitory,
|
PowerClampMonthlyRepository,
|
||||||
SubspaceModelRepository,
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
TagModelRepository,
|
|
||||||
} from '@app/common/modules/space-model';
|
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|
||||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||||
import {
|
import {
|
||||||
PropogateDeleteSpaceModelHandler,
|
SceneIconRepository,
|
||||||
PropogateUpdateSpaceModelHandler,
|
SceneRepository,
|
||||||
PropogateUpdateSpaceModelProductAllocationHandler,
|
} from '@app/common/modules/scene/repositories';
|
||||||
} from './handlers';
|
|
||||||
import { CqrsModule } from '@nestjs/cqrs';
|
|
||||||
import {
|
import {
|
||||||
InviteSpaceRepository,
|
InviteSpaceRepository,
|
||||||
SpaceLinkRepository,
|
SpaceLinkRepository,
|
||||||
SpaceProductAllocationRepository,
|
SpaceProductAllocationRepository,
|
||||||
SpaceRepository,
|
SpaceRepository,
|
||||||
TagRepository,
|
|
||||||
} from '@app/common/modules/space';
|
} from '@app/common/modules/space';
|
||||||
|
import {
|
||||||
|
SpaceModelProductAllocationRepoitory,
|
||||||
|
SpaceModelRepository,
|
||||||
|
SubspaceModelProductAllocationRepoitory,
|
||||||
|
SubspaceModelRepository,
|
||||||
|
} from '@app/common/modules/space-model';
|
||||||
import {
|
import {
|
||||||
SubspaceProductAllocationRepository,
|
SubspaceProductAllocationRepository,
|
||||||
SubspaceRepository,
|
SubspaceRepository,
|
||||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
|
import { SpaceRepositoryModule } from '@app/common/modules/space/space.repository.module';
|
||||||
|
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { CqrsModule } from '@nestjs/cqrs';
|
||||||
|
import { CommunityModule } from 'src/community/community.module';
|
||||||
|
import { CommunityService } from 'src/community/services';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
import { SceneService } from 'src/scene/services';
|
||||||
import {
|
import {
|
||||||
SpaceLinkService,
|
SpaceLinkService,
|
||||||
SpaceService,
|
SpaceService,
|
||||||
@ -36,37 +52,18 @@ import {
|
|||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
ValidationService,
|
ValidationService,
|
||||||
} from 'src/space/services';
|
} from 'src/space/services';
|
||||||
import { TagService } from 'src/space/services/tag';
|
|
||||||
import { CommunityService } from 'src/community/services';
|
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
|
||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
|
||||||
import { TagService as NewTagService } from 'src/tags/services/tags.service';
|
|
||||||
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
|
||||||
import { SpaceModelProductAllocationService } from './services/space-model-product-allocation.service';
|
|
||||||
import { SubspaceModelProductAllocationService } from './services/subspace/subspace-model-product-allocation.service';
|
|
||||||
import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service';
|
import { SpaceProductAllocationService } from 'src/space/services/space-product-allocation.service';
|
||||||
import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service';
|
import { SubspaceProductAllocationService } from 'src/space/services/subspace/subspace-product-allocation.service';
|
||||||
import { DeviceService } from 'src/device/services';
|
import { TagService as NewTagService } from 'src/tags/services/tags.service';
|
||||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
import { SpaceModelController } from './controllers';
|
||||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
|
||||||
import { SceneService } from 'src/scene/services';
|
|
||||||
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
|
||||||
import {
|
import {
|
||||||
SceneIconRepository,
|
PropogateDeleteSpaceModelHandler,
|
||||||
SceneRepository,
|
PropogateUpdateSpaceModelHandler,
|
||||||
} from '@app/common/modules/scene/repositories';
|
PropogateUpdateSpaceModelProductAllocationHandler,
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
} from './handlers';
|
||||||
import { CommunityModule } from 'src/community/community.module';
|
import { SpaceModelService, SubSpaceModelService } from './services';
|
||||||
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
import { SpaceModelProductAllocationService } from './services/space-model-product-allocation.service';
|
||||||
import {
|
import { SubspaceModelProductAllocationService } from './services/subspace/subspace-model-product-allocation.service';
|
||||||
PowerClampHourlyRepository,
|
|
||||||
PowerClampDailyRepository,
|
|
||||||
PowerClampMonthlyRepository,
|
|
||||||
} from '@app/common/modules/power-clamp/repositories';
|
|
||||||
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
|
||||||
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
|
||||||
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|
||||||
|
|
||||||
const CommandHandlers = [
|
const CommandHandlers = [
|
||||||
PropogateUpdateSpaceModelHandler,
|
PropogateUpdateSpaceModelHandler,
|
||||||
@ -88,13 +85,10 @@ const CommandHandlers = [
|
|||||||
SubspaceModelRepository,
|
SubspaceModelRepository,
|
||||||
ProductRepository,
|
ProductRepository,
|
||||||
SubspaceRepository,
|
SubspaceRepository,
|
||||||
TagModelRepository,
|
|
||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
ValidationService,
|
ValidationService,
|
||||||
TagService,
|
|
||||||
SubspaceDeviceService,
|
SubspaceDeviceService,
|
||||||
CommunityService,
|
CommunityService,
|
||||||
TagRepository,
|
|
||||||
DeviceRepository,
|
DeviceRepository,
|
||||||
TuyaService,
|
TuyaService,
|
||||||
CommunityRepository,
|
CommunityRepository,
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
|
import { ORPHAN_SPACE_NAME } from '@app/common/constants/orphan-constant';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
|
ArrayUnique,
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsNotEmpty,
|
IsNotEmpty,
|
||||||
IsNumber,
|
IsNumber,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
IsUUID,
|
IsUUID,
|
||||||
|
NotEquals,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { AddSubspaceDto } from './subspace';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
import { ProcessTagDto } from 'src/tags/dtos';
|
||||||
|
import { AddSubspaceDto } from './subspace';
|
||||||
|
|
||||||
export class AddSpaceDto {
|
export class AddSpaceDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@ -19,6 +22,11 @@ export class AddSpaceDto {
|
|||||||
})
|
})
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
|
@NotEquals(ORPHAN_SPACE_NAME, {
|
||||||
|
message() {
|
||||||
|
return `Space name cannot be "${ORPHAN_SPACE_NAME}". Please choose a different name.`;
|
||||||
|
},
|
||||||
|
})
|
||||||
spaceName: string;
|
spaceName: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@ -74,6 +82,20 @@ export class AddSpaceDto {
|
|||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
|
@ArrayUnique((subspace) => subspace.subspaceName, {
|
||||||
|
message(validationArguments) {
|
||||||
|
const subspaces = validationArguments.value;
|
||||||
|
const nameCounts = subspaces.reduce((acc, curr) => {
|
||||||
|
acc[curr.subspaceName] = (acc[curr.subspaceName] || 0) + 1;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
// Find duplicates
|
||||||
|
const duplicates = Object.keys(nameCounts).filter(
|
||||||
|
(name) => nameCounts[name] > 1,
|
||||||
|
);
|
||||||
|
return `Duplicate subspace names found: ${duplicates.join(', ')}`;
|
||||||
|
},
|
||||||
|
})
|
||||||
@Type(() => AddSubspaceDto)
|
@Type(() => AddSubspaceDto)
|
||||||
subspaces?: AddSubspaceDto[];
|
subspaces?: AddSubspaceDto[];
|
||||||
|
|
||||||
|
29
src/space/dtos/create-allocations.dto.ts
Normal file
29
src/space/dtos/create-allocations.dto.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
|
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
||||||
|
import { ProcessTagDto } from 'src/tags/dtos';
|
||||||
|
import { QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export enum AllocationsOwnerType {
|
||||||
|
SPACE = 'space',
|
||||||
|
SUBSPACE = 'subspace',
|
||||||
|
}
|
||||||
|
export class BaseCreateAllocationsDto {
|
||||||
|
tags: ProcessTagDto[];
|
||||||
|
projectUuid: string;
|
||||||
|
queryRunner: QueryRunner;
|
||||||
|
type: AllocationsOwnerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateSpaceAllocationsDto extends BaseCreateAllocationsDto {
|
||||||
|
space: SpaceEntity;
|
||||||
|
type: AllocationsOwnerType.SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateSubspaceAllocationsDto extends BaseCreateAllocationsDto {
|
||||||
|
subspace: SubspaceEntity;
|
||||||
|
type: AllocationsOwnerType.SUBSPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateAllocationsDto =
|
||||||
|
| CreateSpaceAllocationsDto
|
||||||
|
| CreateSubspaceAllocationsDto;
|
@ -1,47 +1,14 @@
|
|||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
import { ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { IsOptional, IsUUID } from 'class-validator';
|
||||||
import { Type } from 'class-transformer';
|
import { AddSubspaceDto } from './add.subspace.dto';
|
||||||
import {
|
|
||||||
IsEnum,
|
|
||||||
IsOptional,
|
|
||||||
IsString,
|
|
||||||
IsArray,
|
|
||||||
ValidateNested,
|
|
||||||
} from 'class-validator';
|
|
||||||
import { ModifyTagDto } from '../tag/modify-tag.dto';
|
|
||||||
|
|
||||||
export class ModifySubspaceDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Action to perform: add, update, or delete',
|
|
||||||
example: ModifyAction.ADD,
|
|
||||||
})
|
|
||||||
@IsEnum(ModifyAction)
|
|
||||||
action: ModifyAction;
|
|
||||||
|
|
||||||
|
export class ModifySubspaceDto extends PartialType(AddSubspaceDto) {
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description: 'UUID of the subspace (required for update/delete)',
|
description:
|
||||||
|
'UUID of the subspace (will present if updating an existing subspace)',
|
||||||
example: '123e4567-e89b-12d3-a456-426614174000',
|
example: '123e4567-e89b-12d3-a456-426614174000',
|
||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsUUID()
|
||||||
uuid?: string;
|
uuid?: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description: 'Name of the subspace (required for add/update)',
|
|
||||||
example: 'Living Room',
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
subspaceName?: string;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description:
|
|
||||||
'List of tag modifications (add/update/delete) for the subspace',
|
|
||||||
type: [ModifyTagDto],
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => ModifyTagDto)
|
|
||||||
tags?: ModifyTagDto[];
|
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,9 @@
|
|||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { IsOptional, IsString, IsUUID } from 'class-validator';
|
||||||
import { IsEnum, IsOptional, IsString, IsUUID } from 'class-validator';
|
|
||||||
|
|
||||||
export class ModifyTagDto {
|
export class ModifyTagDto {
|
||||||
@ApiProperty({
|
|
||||||
description: 'Action to perform: add, update, or delete',
|
|
||||||
example: ModifyAction.ADD,
|
|
||||||
})
|
|
||||||
@IsEnum(ModifyAction)
|
|
||||||
action: ModifyAction;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description: 'UUID of the new tag',
|
description: 'UUID of an existing tag',
|
||||||
example: '123e4567-e89b-12d3-a456-426614174000',
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsUUID()
|
|
||||||
newTagUuid: string;
|
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
|
||||||
description:
|
|
||||||
'UUID of an existing tag (required for update/delete, optional for add)',
|
|
||||||
example: 'a1b2c3d4-5678-90ef-abcd-1234567890ef',
|
example: 'a1b2c3d4-5678-90ef-abcd-1234567890ef',
|
||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@ -28,7 +11,7 @@ export class ModifyTagDto {
|
|||||||
tagUuid?: string;
|
tagUuid?: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description: 'Name of the tag (required for add/update)',
|
description: 'Name of the tag',
|
||||||
example: 'Temperature Sensor',
|
example: 'Temperature Sensor',
|
||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@ -36,8 +19,7 @@ export class ModifyTagDto {
|
|||||||
name?: string;
|
name?: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description:
|
description: 'UUID of the product associated with the tag',
|
||||||
'UUID of the product associated with the tag (required for add)',
|
|
||||||
example: 'c789a91e-549a-4753-9006-02f89e8170e0',
|
example: 'c789a91e-549a-4753-9006-02f89e8170e0',
|
||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
|
import { ORPHAN_SPACE_NAME } from '@app/common/constants/orphan-constant';
|
||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
IsArray,
|
IsArray,
|
||||||
IsNumber,
|
IsNumber,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
|
NotEquals,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { ModifySubspaceDto } from './subspace';
|
import { ModifySubspaceDto } from './subspace';
|
||||||
import { Type } from 'class-transformer';
|
|
||||||
import { ModifyTagDto } from './tag/modify-tag.dto';
|
import { ModifyTagDto } from './tag/modify-tag.dto';
|
||||||
|
|
||||||
export class UpdateSpaceDto {
|
export class UpdateSpaceDto {
|
||||||
@ -17,6 +19,11 @@ export class UpdateSpaceDto {
|
|||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@NotEquals(ORPHAN_SPACE_NAME, {
|
||||||
|
message() {
|
||||||
|
return `Space name cannot be "${ORPHAN_SPACE_NAME}". Please choose a different name.`;
|
||||||
|
},
|
||||||
|
})
|
||||||
spaceName?: string;
|
spaceName?: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@ -46,7 +53,7 @@ export class UpdateSpaceDto {
|
|||||||
@IsArray()
|
@IsArray()
|
||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
@Type(() => ModifySubspaceDto)
|
@Type(() => ModifySubspaceDto)
|
||||||
subspace?: ModifySubspaceDto[];
|
subspaces?: ModifySubspaceDto[];
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description:
|
description:
|
||||||
@ -58,6 +65,7 @@ export class UpdateSpaceDto {
|
|||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
@Type(() => ModifyTagDto)
|
@Type(() => ModifyTagDto)
|
||||||
tags?: ModifyTagDto[];
|
tags?: ModifyTagDto[];
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'UUID of the Space',
|
description: 'UUID of the Space',
|
||||||
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
|
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||||
import { DeviceService } from 'src/device/services';
|
import { DeviceService } from 'src/device/services';
|
||||||
@ -5,12 +6,10 @@ import { UserSpaceService } from 'src/users/services';
|
|||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { DisableSpaceCommand } from '../commands';
|
import { DisableSpaceCommand } from '../commands';
|
||||||
import {
|
import {
|
||||||
SubSpaceService,
|
|
||||||
SpaceLinkService,
|
SpaceLinkService,
|
||||||
SpaceSceneService,
|
SpaceSceneService,
|
||||||
|
SubSpaceService,
|
||||||
} from '../services';
|
} from '../services';
|
||||||
import { TagService } from '../services/tag';
|
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
|
||||||
|
|
||||||
@CommandHandler(DisableSpaceCommand)
|
@CommandHandler(DisableSpaceCommand)
|
||||||
export class DisableSpaceHandler
|
export class DisableSpaceHandler
|
||||||
@ -19,7 +18,6 @@ export class DisableSpaceHandler
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly subSpaceService: SubSpaceService,
|
private readonly subSpaceService: SubSpaceService,
|
||||||
private readonly userService: UserSpaceService,
|
private readonly userService: UserSpaceService,
|
||||||
private readonly tagService: TagService,
|
|
||||||
private readonly deviceService: DeviceService,
|
private readonly deviceService: DeviceService,
|
||||||
private readonly spaceLinkService: SpaceLinkService,
|
private readonly spaceLinkService: SpaceLinkService,
|
||||||
private readonly sceneService: SpaceSceneService,
|
private readonly sceneService: SpaceSceneService,
|
||||||
@ -46,6 +44,9 @@ export class DisableSpaceHandler
|
|||||||
'scenes',
|
'scenes',
|
||||||
'children',
|
'children',
|
||||||
'userSpaces',
|
'userSpaces',
|
||||||
|
'productAllocations',
|
||||||
|
'productAllocations.tag',
|
||||||
|
'productAllocations.product',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -64,15 +65,15 @@ export class DisableSpaceHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagUuids = space.productAllocations?.map((tag) => tag.uuid) || [];
|
const tagUuids =
|
||||||
|
space.productAllocations?.map(({ tag }) => tag.uuid) || [];
|
||||||
/* const subspaceDtos =
|
/* const subspaceDtos =
|
||||||
space.subspaces?.map((subspace) => ({
|
space.subspaces?.map((subspace) => ({
|
||||||
subspaceUuid: subspace.uuid,
|
subspaceUuid: subspace.uuid,
|
||||||
})) || []; */
|
})) || []; */
|
||||||
const deletionTasks = [
|
const deletionTasks = [
|
||||||
// this.subSpaceService.deleteSubspaces(subspaceDtos, queryRunner),
|
|
||||||
this.userService.deleteUserSpace(space.uuid),
|
this.userService.deleteUserSpace(space.uuid),
|
||||||
this.tagService.deleteTags(tagUuids, queryRunner),
|
|
||||||
this.deviceService.deleteDevice(
|
this.deviceService.deleteDevice(
|
||||||
space.devices,
|
space.devices,
|
||||||
orphanSpace,
|
orphanSpace,
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
|
||||||
import { ModifyTagDto } from '../dtos/tag/modify-tag.dto';
|
|
||||||
|
|
||||||
export interface ISingleSubspace {
|
|
||||||
subspace: SubspaceEntity;
|
|
||||||
action: ModifyAction;
|
|
||||||
tags: ModifyTagDto[];
|
|
||||||
}
|
|
6
src/space/interfaces/update-subspace-allocation.dto.ts
Normal file
6
src/space/interfaces/update-subspace-allocation.dto.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { ProcessTagDto } from 'src/tags/dtos';
|
||||||
|
|
||||||
|
export interface UpdateSpaceAllocationDto {
|
||||||
|
uuid: string;
|
||||||
|
tags: ProcessTagDto[];
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { TagService } from 'src/tags/services';
|
||||||
|
import {
|
||||||
|
AllocationsOwnerType,
|
||||||
|
CreateAllocationsDto,
|
||||||
|
} from '../../dtos/create-allocations.dto';
|
||||||
|
import { SpaceProductAllocationService } from '../space-product-allocation.service';
|
||||||
|
import { SubspaceProductAllocationService } from '../subspace/subspace-product-allocation.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ProductAllocationService {
|
||||||
|
constructor(
|
||||||
|
private readonly tagService: TagService,
|
||||||
|
private readonly spaceProductAllocationService: SpaceProductAllocationService,
|
||||||
|
private readonly subSpaceProductAllocationService: SubspaceProductAllocationService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async createAllocations(dto: CreateAllocationsDto): Promise<void> {
|
||||||
|
const { projectUuid, queryRunner, tags, type } = dto;
|
||||||
|
|
||||||
|
const allocationsData = await this.tagService.processTags(
|
||||||
|
tags,
|
||||||
|
projectUuid,
|
||||||
|
queryRunner,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a mapping of created tags by UUID and name for quick lookup
|
||||||
|
const createdTagsByUUID = new Map(allocationsData.map((t) => [t.uuid, t]));
|
||||||
|
const createdTagsByName = new Map(allocationsData.map((t) => [t.name, t]));
|
||||||
|
|
||||||
|
// Create the product-tag mapping based on the processed tags
|
||||||
|
const productTagMapping = tags.map(({ uuid, name, productUuid }) => {
|
||||||
|
const inputTag = uuid
|
||||||
|
? createdTagsByUUID.get(uuid)
|
||||||
|
: createdTagsByName.get(name);
|
||||||
|
return {
|
||||||
|
tag: inputTag?.uuid,
|
||||||
|
product: productUuid,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AllocationsOwnerType.SPACE: {
|
||||||
|
// todo: take to consideration original method implementation
|
||||||
|
await this.spaceProductAllocationService.createProductAllocations(
|
||||||
|
dto.space,
|
||||||
|
productTagMapping,
|
||||||
|
queryRunner,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AllocationsOwnerType.SUBSPACE: {
|
||||||
|
await this.subSpaceProductAllocationService.createProductAllocations(
|
||||||
|
dto.subspace,
|
||||||
|
productTagMapping,
|
||||||
|
queryRunner,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,113 +1,37 @@
|
|||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
|
||||||
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
|
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
|
||||||
import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities/space-product-allocation.entity';
|
import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities/space-product-allocation.entity';
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
import { NewTagEntity } from '@app/common/modules/tag';
|
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
import { In, QueryRunner } from 'typeorm';
|
import { In, QueryRunner } from 'typeorm';
|
||||||
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
|
|
||||||
import { ModifyTagDto } from '../dtos/tag/modify-tag.dto';
|
|
||||||
import { ModifySubspaceDto } from '../dtos';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
|
||||||
import { TagService as NewTagService } from 'src/tags/services';
|
|
||||||
import { SpaceModelProductAllocationEntity } from '@app/common/modules/space-model';
|
|
||||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
|
||||||
import { ProjectEntity } from '@app/common/modules/project/entities';
|
|
||||||
import { ValidationService } from './space-validation.service';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SpaceProductAllocationService {
|
export class SpaceProductAllocationService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly tagService: NewTagService,
|
|
||||||
private readonly spaceProductAllocationRepository: SpaceProductAllocationRepository,
|
private readonly spaceProductAllocationRepository: SpaceProductAllocationRepository,
|
||||||
private readonly spaceService: ValidationService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createSpaceProductAllocations(
|
async createProductAllocations(
|
||||||
space: SpaceEntity,
|
space: SpaceEntity,
|
||||||
processedTags: NewTagEntity[],
|
allocationsData: { product: string; tag: string }[],
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
modifySubspaces?: ModifySubspaceDto[],
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
if (!processedTags.length) return;
|
if (!allocationsData.length) return;
|
||||||
|
|
||||||
const productAllocations: SpaceProductAllocationEntity[] = [];
|
const productAllocations: SpaceProductAllocationEntity[] = [];
|
||||||
const existingAllocations = new Map<
|
|
||||||
string,
|
|
||||||
SpaceProductAllocationEntity
|
|
||||||
>();
|
|
||||||
|
|
||||||
for (const tag of processedTags) {
|
for (const allocationData of allocationsData) {
|
||||||
let isTagNeeded = true;
|
if (await this.isAllocationExist(queryRunner, allocationData, space))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (modifySubspaces) {
|
const allocation = this.createNewAllocation(
|
||||||
const relatedSubspaces = await queryRunner.manager.find(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
product: tag.product,
|
|
||||||
subspace: { space: { uuid: space.uuid } },
|
|
||||||
tags: { uuid: tag.uuid },
|
|
||||||
},
|
|
||||||
relations: ['subspace', 'tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const subspaceWithTag of relatedSubspaces) {
|
|
||||||
const modifyingSubspace = modifySubspaces.find(
|
|
||||||
(subspace) =>
|
|
||||||
subspace.action === ModifyAction.UPDATE &&
|
|
||||||
subspace.uuid === subspaceWithTag.subspace.uuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
modifyingSubspace &&
|
|
||||||
modifyingSubspace.tags &&
|
|
||||||
modifyingSubspace.tags.some(
|
|
||||||
(subspaceTag) =>
|
|
||||||
subspaceTag.action === ModifyAction.DELETE &&
|
|
||||||
subspaceTag.tagUuid === tag.uuid,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
isTagNeeded = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTagNeeded) {
|
|
||||||
const isDuplicated = await this.validateTagWithinSpace(
|
|
||||||
queryRunner,
|
|
||||||
tag,
|
|
||||||
space,
|
|
||||||
);
|
|
||||||
if (isDuplicated) continue;
|
|
||||||
|
|
||||||
let allocation = existingAllocations.get(tag.product.uuid);
|
|
||||||
if (!allocation) {
|
|
||||||
allocation = await this.getAllocationByProduct(
|
|
||||||
tag.product,
|
|
||||||
space,
|
space,
|
||||||
|
allocationData,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
if (allocation) {
|
|
||||||
existingAllocations.set(tag.product.uuid, allocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allocation) {
|
|
||||||
allocation = this.createNewAllocation(space, tag, queryRunner);
|
|
||||||
productAllocations.push(allocation);
|
productAllocations.push(allocation);
|
||||||
} else if (!allocation.tags.some((t) => t.uuid === tag.uuid)) {
|
|
||||||
allocation.tags.push(tag);
|
|
||||||
await this.saveAllocation(allocation, queryRunner);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (productAllocations.length > 0) {
|
if (productAllocations.length > 0) {
|
||||||
await this.saveAllocations(productAllocations, queryRunner);
|
await this.saveAllocations(productAllocations, queryRunner);
|
||||||
}
|
}
|
||||||
@ -118,97 +42,6 @@ export class SpaceProductAllocationService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async createAllocationFromModel(
|
|
||||||
modelAllocations: SpaceModelProductAllocationEntity[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
spaces?: SpaceEntity[],
|
|
||||||
) {
|
|
||||||
if (!spaces || spaces.length === 0 || !modelAllocations.length) return;
|
|
||||||
|
|
||||||
const allocations: SpaceProductAllocationEntity[] = [];
|
|
||||||
|
|
||||||
for (const space of spaces) {
|
|
||||||
for (const modelAllocation of modelAllocations) {
|
|
||||||
const allocation = queryRunner.manager.create(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
space,
|
|
||||||
product: modelAllocation.product,
|
|
||||||
tags: modelAllocation.tags,
|
|
||||||
inheritedFromModel: modelAllocation,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
allocations.push(allocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allocations.length > 0) {
|
|
||||||
await queryRunner.manager.save(SpaceProductAllocationEntity, allocations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async addTagToAllocationFromModel(
|
|
||||||
modelAllocation: SpaceModelProductAllocationEntity,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
tag: NewTagEntity,
|
|
||||||
spaces?: SpaceEntity[],
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
if (!spaces || spaces.length === 0 || !modelAllocation) return;
|
|
||||||
|
|
||||||
const spaceAllocations = await queryRunner.manager.find(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: { inheritedFromModel: { uuid: modelAllocation.uuid } },
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (spaceAllocations.length === 0) return;
|
|
||||||
|
|
||||||
for (const allocation of spaceAllocations) {
|
|
||||||
allocation.tags.push(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
await queryRunner.manager.save(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
spaceAllocations,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
'Failed to add tag to allocation from model',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSpaceProductAllocations(
|
|
||||||
dtos: ModifyTagDto[],
|
|
||||||
projectUuid: string,
|
|
||||||
space: SpaceEntity,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
modifySubspace?: ModifySubspaceDto[],
|
|
||||||
): Promise<void> {
|
|
||||||
if (!dtos || dtos.length === 0) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await Promise.all([
|
|
||||||
this.processAddActions(
|
|
||||||
dtos,
|
|
||||||
projectUuid,
|
|
||||||
space,
|
|
||||||
queryRunner,
|
|
||||||
modifySubspace,
|
|
||||||
),
|
|
||||||
|
|
||||||
this.processDeleteActions(dtos, queryRunner, space),
|
|
||||||
]);
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleError(error, 'Error while updating product allocations');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async unlinkModels(space: SpaceEntity, queryRunner: QueryRunner) {
|
async unlinkModels(space: SpaceEntity, queryRunner: QueryRunner) {
|
||||||
try {
|
try {
|
||||||
if (!space.productAllocations || space.productAllocations.length === 0)
|
if (!space.productAllocations || space.productAllocations.length === 0)
|
||||||
@ -231,307 +64,30 @@ export class SpaceProductAllocationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async propagateDeleteToInheritedAllocations(
|
private async isAllocationExist(
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
allocationsToUpdate: SpaceModelProductAllocationEntity[],
|
allocation: { product: string; tag: string },
|
||||||
tagUuidsToDelete: string[],
|
|
||||||
project: ProjectEntity,
|
|
||||||
spaces?: SpaceEntity[],
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
|
||||||
const inheritedAllocationUpdates: SpaceProductAllocationEntity[] = [];
|
|
||||||
const inheritedAllocationsToDelete: SpaceProductAllocationEntity[] = [];
|
|
||||||
|
|
||||||
for (const allocation of allocationsToUpdate) {
|
|
||||||
for (const inheritedAllocation of allocation.inheritedSpaceAllocations) {
|
|
||||||
const updatedInheritedTags = inheritedAllocation.tags.filter(
|
|
||||||
(tag) => !tagUuidsToDelete.includes(tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (updatedInheritedTags.length === inheritedAllocation.tags.length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updatedInheritedTags.length === 0) {
|
|
||||||
inheritedAllocationsToDelete.push(inheritedAllocation);
|
|
||||||
} else {
|
|
||||||
inheritedAllocation.tags = updatedInheritedTags;
|
|
||||||
inheritedAllocationUpdates.push(inheritedAllocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inheritedAllocationUpdates.length > 0) {
|
|
||||||
await queryRunner.manager.save(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
inheritedAllocationUpdates,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inheritedAllocationsToDelete.length > 0) {
|
|
||||||
await queryRunner.manager.remove(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
inheritedAllocationsToDelete,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spaces && spaces.length > 0) {
|
|
||||||
await this.moveDevicesToOrphanSpace(
|
|
||||||
queryRunner,
|
|
||||||
spaces,
|
|
||||||
tagUuidsToDelete,
|
|
||||||
project,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.delete()
|
|
||||||
.from('space_product_tags')
|
|
||||||
.where(
|
|
||||||
'space_product_allocation_uuid NOT IN (' +
|
|
||||||
queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.select('allocation.uuid')
|
|
||||||
.from(SpaceProductAllocationEntity, 'allocation')
|
|
||||||
.getQuery() +
|
|
||||||
')',
|
|
||||||
)
|
|
||||||
.execute();
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleError(
|
|
||||||
error,
|
|
||||||
`Failed to propagate tag deletion to inherited allocations`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async moveDevicesToOrphanSpace(
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
spaces: SpaceEntity[],
|
|
||||||
tagUuidsToDelete: string[],
|
|
||||||
project: ProjectEntity,
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
|
||||||
const orphanSpace = await this.spaceService.getOrphanSpace(project);
|
|
||||||
|
|
||||||
const devicesToMove = await queryRunner.manager
|
|
||||||
.createQueryBuilder(DeviceEntity, 'device')
|
|
||||||
.leftJoinAndSelect('device.tag', 'tag')
|
|
||||||
.where('device.spaceDevice IN (:...spaceUuids)', {
|
|
||||||
spaceUuids: spaces.map((space) => space.uuid),
|
|
||||||
})
|
|
||||||
.andWhere('tag.uuid IN (:...tagUuidsToDelete)', { tagUuidsToDelete })
|
|
||||||
.getMany();
|
|
||||||
|
|
||||||
if (devicesToMove.length === 0) return;
|
|
||||||
|
|
||||||
await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.update(DeviceEntity)
|
|
||||||
.set({ spaceDevice: orphanSpace })
|
|
||||||
.where('uuid IN (:...deviceUuids)', {
|
|
||||||
deviceUuids: devicesToMove.map((device) => device.uuid),
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleError(error, `Failed to move devices to orphan space`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async processDeleteActions(
|
|
||||||
dtos: ModifyTagDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
space: SpaceEntity,
|
|
||||||
): Promise<SpaceProductAllocationEntity[]> {
|
|
||||||
try {
|
|
||||||
if (!dtos || dtos.length === 0) return;
|
|
||||||
const tagUuidsToDelete = dtos
|
|
||||||
.filter((dto) => dto.action === ModifyAction.DELETE && dto.tagUuid)
|
|
||||||
.map((dto) => dto.tagUuid);
|
|
||||||
|
|
||||||
if (tagUuidsToDelete.length === 0) return [];
|
|
||||||
|
|
||||||
const allocationsToUpdate = await queryRunner.manager.find(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
tags: { uuid: In(tagUuidsToDelete) },
|
|
||||||
space: { uuid: space.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!allocationsToUpdate || allocationsToUpdate.length === 0) return [];
|
|
||||||
|
|
||||||
const deletedAllocations: SpaceProductAllocationEntity[] = [];
|
|
||||||
const allocationUpdates: SpaceProductAllocationEntity[] = [];
|
|
||||||
|
|
||||||
for (const allocation of allocationsToUpdate) {
|
|
||||||
const updatedTags = allocation.tags.filter(
|
|
||||||
(tag) => !tagUuidsToDelete.includes(tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (updatedTags.length === allocation.tags.length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updatedTags.length === 0) {
|
|
||||||
deletedAllocations.push(allocation);
|
|
||||||
} else {
|
|
||||||
allocation.tags = updatedTags;
|
|
||||||
allocationUpdates.push(allocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allocationUpdates.length > 0) {
|
|
||||||
await queryRunner.manager.save(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
allocationUpdates,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deletedAllocations.length > 0) {
|
|
||||||
await queryRunner.manager.remove(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
deletedAllocations,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.delete()
|
|
||||||
.from('space_product_tags')
|
|
||||||
.where(
|
|
||||||
'space_product_allocation_uuid NOT IN (' +
|
|
||||||
queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.select('allocation.uuid')
|
|
||||||
.from(SpaceProductAllocationEntity, 'allocation')
|
|
||||||
.getQuery() +
|
|
||||||
')',
|
|
||||||
)
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
return deletedAllocations;
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleError(error, `Failed to delete tags in space`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private async processAddActions(
|
|
||||||
dtos: ModifyTagDto[],
|
|
||||||
projectUuid: string,
|
|
||||||
space: SpaceEntity,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
modifySubspace?: ModifySubspaceDto[],
|
|
||||||
): Promise<void> {
|
|
||||||
const addDtos: ProcessTagDto[] = dtos
|
|
||||||
.filter((dto) => dto.action === ModifyAction.ADD)
|
|
||||||
.map((dto) => ({
|
|
||||||
name: dto.name,
|
|
||||||
productUuid: dto.productUuid,
|
|
||||||
uuid: dto.newTagUuid,
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (addDtos.length > 0) {
|
|
||||||
const processedTags = await this.tagService.processTags(
|
|
||||||
addDtos,
|
|
||||||
projectUuid,
|
|
||||||
queryRunner,
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.createSpaceProductAllocations(
|
|
||||||
space,
|
|
||||||
processedTags,
|
|
||||||
queryRunner,
|
|
||||||
modifySubspace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private async validateTagWithinSpace(
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
tag: NewTagEntity,
|
|
||||||
space: SpaceEntity,
|
space: SpaceEntity,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const existingAllocationsForProduct = await queryRunner.manager.find(
|
const existingAllocations =
|
||||||
|
await queryRunner.manager.findOne<SpaceProductAllocationEntity>(
|
||||||
SpaceProductAllocationEntity,
|
SpaceProductAllocationEntity,
|
||||||
{
|
{
|
||||||
where: {
|
where: {
|
||||||
space: {
|
space: {
|
||||||
uuid: space.uuid,
|
uuid: space.uuid,
|
||||||
},
|
},
|
||||||
|
tag: {
|
||||||
|
uuid: allocation.tag,
|
||||||
|
},
|
||||||
product: {
|
product: {
|
||||||
uuid: tag.product.uuid,
|
uuid: allocation.product,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['tags'],
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
return existingAllocations ? true : false;
|
||||||
!existingAllocationsForProduct ||
|
|
||||||
existingAllocationsForProduct.length === 0
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const existingTagsForProduct = existingAllocationsForProduct.flatMap(
|
|
||||||
(allocation) => allocation.tags || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
return existingTagsForProduct.some(
|
|
||||||
(existingTag) => existingTag.uuid === tag.uuid,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getAllocationByProduct(
|
|
||||||
product: ProductEntity,
|
|
||||||
space: SpaceEntity,
|
|
||||||
queryRunner?: QueryRunner,
|
|
||||||
): Promise<SpaceProductAllocationEntity | null> {
|
|
||||||
return queryRunner
|
|
||||||
? queryRunner.manager.findOne(SpaceProductAllocationEntity, {
|
|
||||||
where: {
|
|
||||||
space: { uuid: space.uuid },
|
|
||||||
product: { uuid: product.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
})
|
|
||||||
: this.spaceProductAllocationRepository.findOne({
|
|
||||||
where: {
|
|
||||||
space: { uuid: space.uuid },
|
|
||||||
product: { uuid: product.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
createNewAllocation(
|
|
||||||
space: SpaceEntity,
|
|
||||||
tag: NewTagEntity,
|
|
||||||
queryRunner?: QueryRunner,
|
|
||||||
): SpaceProductAllocationEntity {
|
|
||||||
return queryRunner
|
|
||||||
? queryRunner.manager.create(SpaceProductAllocationEntity, {
|
|
||||||
space,
|
|
||||||
product: tag.product,
|
|
||||||
tags: [tag],
|
|
||||||
})
|
|
||||||
: this.spaceProductAllocationRepository.create({
|
|
||||||
space,
|
|
||||||
product: tag.product,
|
|
||||||
tags: [tag],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async saveAllocation(
|
|
||||||
allocation: SpaceProductAllocationEntity,
|
|
||||||
queryRunner?: QueryRunner,
|
|
||||||
) {
|
|
||||||
queryRunner
|
|
||||||
? await queryRunner.manager.save(SpaceProductAllocationEntity, allocation)
|
|
||||||
: await this.spaceProductAllocationRepository.save(allocation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveAllocations(
|
async saveAllocations(
|
||||||
@ -546,6 +102,34 @@ export class SpaceProductAllocationService {
|
|||||||
: await this.spaceProductAllocationRepository.save(allocations);
|
: await this.spaceProductAllocationRepository.save(allocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clearAllAllocations(spaceUuid: string, queryRunner: QueryRunner) {
|
||||||
|
try {
|
||||||
|
await queryRunner.manager.delete(SpaceProductAllocationEntity, {
|
||||||
|
space: { uuid: spaceUuid },
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw this.handleError(error, 'Failed to clear all allocations');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createNewAllocation(
|
||||||
|
space: SpaceEntity,
|
||||||
|
allocationData: { product: string; tag: string },
|
||||||
|
queryRunner?: QueryRunner,
|
||||||
|
): SpaceProductAllocationEntity {
|
||||||
|
return queryRunner
|
||||||
|
? queryRunner.manager.create(SpaceProductAllocationEntity, {
|
||||||
|
space,
|
||||||
|
product: { uuid: allocationData.product },
|
||||||
|
tag: { uuid: allocationData.tag },
|
||||||
|
})
|
||||||
|
: this.spaceProductAllocationRepository.create({
|
||||||
|
space,
|
||||||
|
product: { uuid: allocationData.product },
|
||||||
|
tag: { uuid: allocationData.tag },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private handleError(error: any, message: string): HttpException {
|
private handleError(error: any, message: string): HttpException {
|
||||||
return new HttpException(
|
return new HttpException(
|
||||||
error instanceof HttpException ? error.message : message,
|
error instanceof HttpException ? error.message : message,
|
||||||
@ -554,36 +138,4 @@ export class SpaceProductAllocationService {
|
|||||||
: HttpStatus.INTERNAL_SERVER_ERROR,
|
: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
async clearAllAllocations(spaceUuid: string, queryRunner: QueryRunner) {
|
|
||||||
try {
|
|
||||||
const allocationUuids = await queryRunner.manager
|
|
||||||
.createQueryBuilder(SpaceProductAllocationEntity, 'allocation')
|
|
||||||
.select('allocation.uuid')
|
|
||||||
.where('allocation.space_uuid = :spaceUuid', { spaceUuid })
|
|
||||||
.getRawMany()
|
|
||||||
.then((results) => results.map((r) => r.allocation_uuid));
|
|
||||||
|
|
||||||
if (allocationUuids.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.delete()
|
|
||||||
.from('space_product_tags')
|
|
||||||
.where('space_product_allocation_uuid IN (:...allocationUuids)', {
|
|
||||||
allocationUuids,
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.delete()
|
|
||||||
.from(SpaceProductAllocationEntity)
|
|
||||||
.where('space_uuid = :spaceUuid', { spaceUuid })
|
|
||||||
.execute();
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleError(error, 'Failed to clear all allocations');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import {
|
||||||
|
SpaceModelEntity,
|
||||||
|
SpaceModelRepository,
|
||||||
|
} from '@app/common/modules/space-model';
|
||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
@ -7,25 +16,11 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { In } from 'typeorm';
|
||||||
import { CommunityService } from '../../community/services';
|
import { CommunityService } from '../../community/services';
|
||||||
import { ProjectService } from '../../project/services';
|
import { ProjectService } from '../../project/services';
|
||||||
import {
|
|
||||||
SpaceModelEntity,
|
|
||||||
SpaceModelRepository,
|
|
||||||
} from '@app/common/modules/space-model';
|
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
|
||||||
import { ValidateSpacesDto } from '../dtos/validation.space.dto';
|
|
||||||
import { ProjectParam } from '../dtos';
|
import { ProjectParam } from '../dtos';
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
import { ValidateSpacesDto } from '../dtos/validation.space.dto';
|
||||||
import { In } from 'typeorm';
|
|
||||||
import {
|
|
||||||
ORPHAN_COMMUNITY_NAME,
|
|
||||||
ORPHAN_SPACE_NAME,
|
|
||||||
} from '@app/common/constants/orphan-constant';
|
|
||||||
import { ProjectEntity } from '@app/common/modules/project/entities';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ValidationService {
|
export class ValidationService {
|
||||||
@ -130,9 +125,7 @@ export class ValidationService {
|
|||||||
'subspaces',
|
'subspaces',
|
||||||
'productAllocations',
|
'productAllocations',
|
||||||
'productAllocations.product',
|
'productAllocations.product',
|
||||||
'productAllocations.tags',
|
|
||||||
'subspaces.productAllocations',
|
'subspaces.productAllocations',
|
||||||
'subspaces.productAllocations.tags',
|
|
||||||
'subspaces.productAllocations.product',
|
'subspaces.productAllocations.product',
|
||||||
'subspaces.devices',
|
'subspaces.devices',
|
||||||
'spaceModel',
|
'spaceModel',
|
||||||
@ -146,13 +139,13 @@ export class ValidationService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const devices = await this.deviceRepository.find({
|
// const devices = await this.deviceRepository.find({
|
||||||
where: { spaceDevice: { uuid: spaceUuid } },
|
// where: { spaceDevice: { uuid: spaceUuid } },
|
||||||
select: ['uuid', 'deviceTuyaUuid', 'isActive', 'createdAt', 'updatedAt'],
|
// select: ['uuid', 'deviceTuyaUuid', 'isActive', 'createdAt', 'updatedAt'],
|
||||||
relations: ['productDevice', 'subspace'],
|
// relations: ['productDevice', 'subspace'],
|
||||||
});
|
// });
|
||||||
|
|
||||||
space.devices = devices;
|
// space.devices = devices;
|
||||||
|
|
||||||
return space;
|
return space;
|
||||||
}
|
}
|
||||||
@ -191,8 +184,8 @@ export class ValidationService {
|
|||||||
'subspaceProductAllocations',
|
'subspaceProductAllocations',
|
||||||
)
|
)
|
||||||
.leftJoinAndSelect(
|
.leftJoinAndSelect(
|
||||||
'subspaceProductAllocations.tags',
|
'subspaceProductAllocations.tag',
|
||||||
'subspaceAllocationTags',
|
'subspaceAllocationTag',
|
||||||
)
|
)
|
||||||
.leftJoinAndSelect(
|
.leftJoinAndSelect(
|
||||||
'subspaceProductAllocations.product',
|
'subspaceProductAllocations.product',
|
||||||
@ -203,7 +196,7 @@ export class ValidationService {
|
|||||||
'productAllocations.product',
|
'productAllocations.product',
|
||||||
'productAllocationProduct',
|
'productAllocationProduct',
|
||||||
)
|
)
|
||||||
.leftJoinAndSelect('productAllocations.tags', 'productAllocationTags')
|
.leftJoinAndSelect('productAllocations.tag', 'productAllocationTag')
|
||||||
.andWhere('spaceModel.disabled = :disabled', { disabled: false })
|
.andWhere('spaceModel.disabled = :disabled', { disabled: false })
|
||||||
.where('spaceModel.uuid = :uuid', { uuid: spaceModelUuid });
|
.where('spaceModel.uuid = :uuid', { uuid: spaceModelUuid });
|
||||||
|
|
||||||
@ -219,39 +212,6 @@ export class ValidationService {
|
|||||||
return spaceModel;
|
return spaceModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFullSpaceHierarchy(
|
|
||||||
space: SpaceEntity,
|
|
||||||
): Promise<{ uuid: string; spaceName: string }[]> {
|
|
||||||
try {
|
|
||||||
// Fetch only the relevant spaces, starting with the target space
|
|
||||||
const targetSpace = await this.spaceRepository.findOne({
|
|
||||||
where: { uuid: space.uuid },
|
|
||||||
relations: ['parent', 'children'],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Fetch only the ancestors of the target space
|
|
||||||
const ancestors = await this.fetchAncestors(targetSpace);
|
|
||||||
|
|
||||||
// Optionally, fetch descendants if required
|
|
||||||
const descendants = await this.fetchDescendants(targetSpace);
|
|
||||||
|
|
||||||
const fullHierarchy = [...ancestors, targetSpace, ...descendants].map(
|
|
||||||
(space) => ({
|
|
||||||
uuid: space.uuid,
|
|
||||||
spaceName: space.spaceName,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return fullHierarchy;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching space hierarchy:', error.message);
|
|
||||||
throw new HttpException(
|
|
||||||
'Error fetching space hierarchy',
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async fetchAncestors(space: SpaceEntity): Promise<SpaceEntity[]> {
|
private async fetchAncestors(space: SpaceEntity): Promise<SpaceEntity[]> {
|
||||||
const ancestors: SpaceEntity[] = [];
|
const ancestors: SpaceEntity[] = [];
|
||||||
|
|
||||||
@ -275,27 +235,6 @@ export class ValidationService {
|
|||||||
return ancestors.reverse();
|
return ancestors.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchDescendants(space: SpaceEntity): Promise<SpaceEntity[]> {
|
|
||||||
const descendants: SpaceEntity[] = [];
|
|
||||||
|
|
||||||
// Fetch the immediate children of the current space
|
|
||||||
const children = await this.spaceRepository.find({
|
|
||||||
where: { parent: { uuid: space.uuid } },
|
|
||||||
relations: ['children'], // To continue fetching downwards
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const child of children) {
|
|
||||||
// Add the child to the descendants list
|
|
||||||
descendants.push(child);
|
|
||||||
|
|
||||||
// Recursively fetch the child's descendants
|
|
||||||
const childDescendants = await this.fetchDescendants(child);
|
|
||||||
descendants.push(...childDescendants);
|
|
||||||
}
|
|
||||||
|
|
||||||
return descendants;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getParentHierarchy(
|
async getParentHierarchy(
|
||||||
space: SpaceEntity,
|
space: SpaceEntity,
|
||||||
): Promise<{ uuid: string; spaceName: string }[]> {
|
): Promise<{ uuid: string; spaceName: string }[]> {
|
||||||
@ -323,24 +262,4 @@ export class ValidationService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOrphanSpace(project: ProjectEntity): Promise<SpaceEntity> {
|
|
||||||
const orphanSpace = await this.spaceRepository.findOne({
|
|
||||||
where: {
|
|
||||||
community: {
|
|
||||||
name: `${ORPHAN_COMMUNITY_NAME}-${project.name}`,
|
|
||||||
},
|
|
||||||
spaceName: ORPHAN_SPACE_NAME,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!orphanSpace) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Orphan space not found in community ${project.name}`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return orphanSpace;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
import {
|
||||||
|
ORPHAN_COMMUNITY_NAME,
|
||||||
|
ORPHAN_SPACE_NAME,
|
||||||
|
} from '@app/common/constants/orphan-constant';
|
||||||
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import { generateRandomString } from '@app/common/helper/randomString';
|
||||||
|
import { removeCircularReferences } from '@app/common/helper/removeCircularReferences';
|
||||||
|
import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities/space-product-allocation.entity';
|
||||||
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
|
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
||||||
import {
|
import {
|
||||||
InviteSpaceRepository,
|
InviteSpaceRepository,
|
||||||
SpaceRepository,
|
SpaceRepository,
|
||||||
@ -8,36 +19,25 @@ import {
|
|||||||
HttpStatus,
|
HttpStatus,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { CommandBus } from '@nestjs/cqrs';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
import { SpaceModelService } from 'src/space-model/services';
|
||||||
|
import { ProcessTagDto } from 'src/tags/dtos';
|
||||||
|
import { TagService } from 'src/tags/services/tags.service';
|
||||||
|
import { DataSource, In, Not, QueryRunner } from 'typeorm';
|
||||||
|
import { DisableSpaceCommand } from '../commands';
|
||||||
import {
|
import {
|
||||||
AddSpaceDto,
|
AddSpaceDto,
|
||||||
AddSubspaceDto,
|
|
||||||
CommunitySpaceParam,
|
CommunitySpaceParam,
|
||||||
GetSpaceParam,
|
GetSpaceParam,
|
||||||
UpdateSpaceDto,
|
UpdateSpaceDto,
|
||||||
} from '../dtos';
|
} from '../dtos';
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
|
||||||
import { generateRandomString } from '@app/common/helper/randomString';
|
|
||||||
import { SpaceLinkService } from './space-link';
|
|
||||||
import { SubSpaceService } from './subspace';
|
|
||||||
import { DataSource, QueryRunner } from 'typeorm';
|
|
||||||
import { ValidationService } from './space-validation.service';
|
|
||||||
import {
|
|
||||||
ORPHAN_COMMUNITY_NAME,
|
|
||||||
ORPHAN_SPACE_NAME,
|
|
||||||
} from '@app/common/constants/orphan-constant';
|
|
||||||
import { CommandBus } from '@nestjs/cqrs';
|
|
||||||
import { TagService as NewTagService } from 'src/tags/services/tags.service';
|
|
||||||
import { SpaceModelService } from 'src/space-model/services';
|
|
||||||
import { DisableSpaceCommand } from '../commands';
|
|
||||||
import { GetSpaceDto } from '../dtos/get.space.dto';
|
import { GetSpaceDto } from '../dtos/get.space.dto';
|
||||||
import { removeCircularReferences } from '@app/common/helper/removeCircularReferences';
|
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
|
||||||
import { SpaceProductAllocationService } from './space-product-allocation.service';
|
|
||||||
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
|
||||||
import { DeviceService } from 'src/device/services';
|
|
||||||
import { SpaceWithParentsDto } from '../dtos/space.parents.dto';
|
import { SpaceWithParentsDto } from '../dtos/space.parents.dto';
|
||||||
|
import { SpaceLinkService } from './space-link';
|
||||||
|
import { SpaceProductAllocationService } from './space-product-allocation.service';
|
||||||
|
import { ValidationService } from './space-validation.service';
|
||||||
|
import { SubSpaceService } from './subspace';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SpaceService {
|
export class SpaceService {
|
||||||
constructor(
|
constructor(
|
||||||
@ -47,7 +47,7 @@ export class SpaceService {
|
|||||||
private readonly spaceLinkService: SpaceLinkService,
|
private readonly spaceLinkService: SpaceLinkService,
|
||||||
private readonly subSpaceService: SubSpaceService,
|
private readonly subSpaceService: SubSpaceService,
|
||||||
private readonly validationService: ValidationService,
|
private readonly validationService: ValidationService,
|
||||||
private readonly newTagService: NewTagService,
|
private readonly tagService: TagService,
|
||||||
private readonly spaceModelService: SpaceModelService,
|
private readonly spaceModelService: SpaceModelService,
|
||||||
private readonly deviceService: DeviceService,
|
private readonly deviceService: DeviceService,
|
||||||
private commandBus: CommandBus,
|
private commandBus: CommandBus,
|
||||||
@ -62,13 +62,6 @@ export class SpaceService {
|
|||||||
addSpaceDto;
|
addSpaceDto;
|
||||||
const { communityUuid, projectUuid } = params;
|
const { communityUuid, projectUuid } = params;
|
||||||
|
|
||||||
if (addSpaceDto.spaceName === ORPHAN_SPACE_NAME) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Name ${ORPHAN_SPACE_NAME} cannot be used`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
|
|
||||||
await queryRunner.connect();
|
await queryRunner.connect();
|
||||||
@ -80,7 +73,7 @@ export class SpaceService {
|
|||||||
projectUuid,
|
projectUuid,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.validateSpaceCreation(addSpaceDto, spaceModelUuid);
|
this.validateSpaceCreationCriteria({ spaceModelUuid, subspaces, tags });
|
||||||
|
|
||||||
const parent = parentUuid
|
const parent = parentUuid
|
||||||
? await this.validationService.validateSpace(parentUuid)
|
? await this.validationService.validateSpace(parentUuid)
|
||||||
@ -99,27 +92,24 @@ export class SpaceService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const newSpace = await queryRunner.manager.save(space);
|
const newSpace = await queryRunner.manager.save(space);
|
||||||
|
|
||||||
const subspaceTags =
|
const subspaceTags =
|
||||||
this.subSpaceService.extractTagsFromSubspace(subspaces);
|
subspaces?.flatMap((subspace) => subspace.tags || []) || [];
|
||||||
const allTags = [...tags, ...subspaceTags];
|
|
||||||
this.validateUniqueTags(allTags);
|
this.checkDuplicateTags([...tags, ...subspaceTags]);
|
||||||
|
|
||||||
if (spaceModelUuid) {
|
if (spaceModelUuid) {
|
||||||
const hasDependencies = subspaces?.length > 0 || tags?.length > 0;
|
// no need to check for existing dependencies here as validateSpaceCreationCriteria
|
||||||
if (!hasDependencies) {
|
// ensures no tags or subspaces are present along with spaceModelUuid
|
||||||
await this.spaceModelService.linkToSpace(
|
await this.spaceModelService.linkToSpace(
|
||||||
newSpace,
|
newSpace,
|
||||||
spaceModel,
|
spaceModel,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
} else if (hasDependencies) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Space cannot be linked to a model because it has existing dependencies (subspaces or tags).`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
// todo: remove this logic as we are not using space links anymore
|
||||||
direction && parent
|
direction && parent
|
||||||
? this.spaceLinkService.saveSpaceLink(
|
? this.spaceLinkService.saveSpaceLink(
|
||||||
parent.uuid,
|
parent.uuid,
|
||||||
@ -129,16 +119,15 @@ export class SpaceService {
|
|||||||
)
|
)
|
||||||
: Promise.resolve(),
|
: Promise.resolve(),
|
||||||
subspaces?.length
|
subspaces?.length
|
||||||
? this.createSubspaces(
|
? this.subSpaceService.createSubspacesFromDto(
|
||||||
subspaces,
|
subspaces,
|
||||||
newSpace,
|
space,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
null,
|
|
||||||
projectUuid,
|
projectUuid,
|
||||||
)
|
)
|
||||||
: Promise.resolve(),
|
: Promise.resolve(),
|
||||||
tags?.length
|
tags?.length
|
||||||
? this.createTags(tags, projectUuid, queryRunner, newSpace)
|
? this.createAllocations(tags, projectUuid, queryRunner, newSpace)
|
||||||
: Promise.resolve(),
|
: Promise.resolve(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -160,7 +149,7 @@ export class SpaceService {
|
|||||||
await queryRunner.release();
|
await queryRunner.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private validateUniqueTags(allTags: ProcessTagDto[]) {
|
private checkDuplicateTags(allTags: ProcessTagDto[]) {
|
||||||
const tagUuidSet = new Set<string>();
|
const tagUuidSet = new Set<string>();
|
||||||
const tagNameProductSet = new Set<string>();
|
const tagNameProductSet = new Set<string>();
|
||||||
|
|
||||||
@ -213,8 +202,8 @@ export class SpaceService {
|
|||||||
{ incomingConnectionDisabled: false },
|
{ incomingConnectionDisabled: false },
|
||||||
)
|
)
|
||||||
.leftJoinAndSelect('space.productAllocations', 'productAllocations')
|
.leftJoinAndSelect('space.productAllocations', 'productAllocations')
|
||||||
// .leftJoinAndSelect('productAllocations.tags', 'tags')
|
.leftJoinAndSelect('productAllocations.tag', 'tag')
|
||||||
// .leftJoinAndSelect('productAllocations.product', 'product')
|
.leftJoinAndSelect('productAllocations.product', 'product')
|
||||||
.leftJoinAndSelect(
|
.leftJoinAndSelect(
|
||||||
'space.subspaces',
|
'space.subspaces',
|
||||||
'subspaces',
|
'subspaces',
|
||||||
@ -225,11 +214,11 @@ export class SpaceService {
|
|||||||
'subspaces.productAllocations',
|
'subspaces.productAllocations',
|
||||||
'subspaceProductAllocations',
|
'subspaceProductAllocations',
|
||||||
)
|
)
|
||||||
// .leftJoinAndSelect('subspaceProductAllocations.tags', 'subspaceTag')
|
.leftJoinAndSelect('subspaceProductAllocations.tag', 'subspaceTag')
|
||||||
// .leftJoinAndSelect(
|
.leftJoinAndSelect(
|
||||||
// 'subspaceProductAllocations.product',
|
'subspaceProductAllocations.product',
|
||||||
// 'subspaceProduct',
|
'subspaceProduct',
|
||||||
// )
|
)
|
||||||
.leftJoinAndSelect('space.spaceModel', 'spaceModel')
|
.leftJoinAndSelect('space.spaceModel', 'spaceModel')
|
||||||
.where('space.community_id = :communityUuid', { communityUuid })
|
.where('space.community_id = :communityUuid', { communityUuid })
|
||||||
.andWhere('space.spaceName != :orphanSpaceName', {
|
.andWhere('space.spaceName != :orphanSpaceName', {
|
||||||
@ -282,28 +271,7 @@ export class SpaceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private transformSpace(space) {
|
// todo refactor this method to eliminate wrong use of tags
|
||||||
const { productAllocations, subspaces, ...restSpace } = space;
|
|
||||||
|
|
||||||
const tags = productAllocations.flatMap((pa) => pa.tags);
|
|
||||||
|
|
||||||
const transformedSubspaces = subspaces.map((subspace) => {
|
|
||||||
const {
|
|
||||||
productAllocations: subspaceProductAllocations,
|
|
||||||
...restSubspace
|
|
||||||
} = subspace;
|
|
||||||
const subspaceTags = subspaceProductAllocations.flatMap((pa) => pa.tags);
|
|
||||||
return {
|
|
||||||
...restSubspace,
|
|
||||||
tags: subspaceTags,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...restSpace,
|
|
||||||
tags,
|
|
||||||
subspaces: transformedSubspaces,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
async findOne(params: GetSpaceParam): Promise<BaseResponseDto> {
|
async findOne(params: GetSpaceParam): Promise<BaseResponseDto> {
|
||||||
const { communityUuid, spaceUuid, projectUuid } = params;
|
const { communityUuid, spaceUuid, projectUuid } = params;
|
||||||
try {
|
try {
|
||||||
@ -327,13 +295,9 @@ export class SpaceService {
|
|||||||
'incomingConnections.disabled = :incomingConnectionDisabled',
|
'incomingConnections.disabled = :incomingConnectionDisabled',
|
||||||
{ incomingConnectionDisabled: false },
|
{ incomingConnectionDisabled: false },
|
||||||
)
|
)
|
||||||
// .leftJoinAndSelect(
|
.leftJoinAndSelect('space.productAllocations', 'productAllocations')
|
||||||
// 'space.tags',
|
.leftJoinAndSelect('productAllocations.tag', 'spaceTag')
|
||||||
// 'tags',
|
.leftJoinAndSelect('productAllocations.product', 'spaceProduct')
|
||||||
// 'tags.disabled = :tagDisabled',
|
|
||||||
// { tagDisabled: false },
|
|
||||||
// )
|
|
||||||
// .leftJoinAndSelect('tags.product', 'tagProduct')
|
|
||||||
.leftJoinAndSelect(
|
.leftJoinAndSelect(
|
||||||
'space.subspaces',
|
'space.subspaces',
|
||||||
'subspaces',
|
'subspaces',
|
||||||
@ -341,12 +305,14 @@ export class SpaceService {
|
|||||||
{ subspaceDisabled: false },
|
{ subspaceDisabled: false },
|
||||||
)
|
)
|
||||||
.leftJoinAndSelect(
|
.leftJoinAndSelect(
|
||||||
'subspaces.tags',
|
'subspaces.productAllocations',
|
||||||
'subspaceTags',
|
'subspaceProductAllocations',
|
||||||
'subspaceTags.disabled = :subspaceTagsDisabled',
|
)
|
||||||
{ subspaceTagsDisabled: false },
|
.leftJoinAndSelect('subspaceProductAllocations.tag', 'subspaceTag')
|
||||||
|
.leftJoinAndSelect(
|
||||||
|
'subspaceProductAllocations.product',
|
||||||
|
'subspaceProduct',
|
||||||
)
|
)
|
||||||
// .leftJoinAndSelect('subspaceTags.product', 'subspaceTagProduct')
|
|
||||||
.where('space.community_id = :communityUuid', { communityUuid })
|
.where('space.community_id = :communityUuid', { communityUuid })
|
||||||
.andWhere('space.spaceName != :orphanSpaceName', {
|
.andWhere('space.spaceName != :orphanSpaceName', {
|
||||||
orphanSpaceName: ORPHAN_SPACE_NAME,
|
orphanSpaceName: ORPHAN_SPACE_NAME,
|
||||||
@ -456,7 +422,7 @@ export class SpaceService {
|
|||||||
const { communityUuid, spaceUuid, projectUuid } = params;
|
const { communityUuid, spaceUuid, projectUuid } = params;
|
||||||
|
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
const hasSubspace = updateSpaceDto.subspace?.length > 0;
|
const hasSubspace = updateSpaceDto.subspaces?.length > 0;
|
||||||
const hasTags = updateSpaceDto.tags?.length > 0;
|
const hasTags = updateSpaceDto.tags?.length > 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -473,13 +439,6 @@ export class SpaceService {
|
|||||||
spaceUuid,
|
spaceUuid,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (space.spaceName === ORPHAN_SPACE_NAME) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Space "${ORPHAN_SPACE_NAME}" cannot be updated`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (space.spaceModel && !updateSpaceDto.spaceModelUuid) {
|
if (space.spaceModel && !updateSpaceDto.spaceModelUuid) {
|
||||||
await queryRunner.manager.update(SpaceEntity, space.uuid, {
|
await queryRunner.manager.update(SpaceEntity, space.uuid, {
|
||||||
spaceModel: null,
|
spaceModel: null,
|
||||||
@ -512,7 +471,11 @@ export class SpaceService {
|
|||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
} else if (hasDependencies) {
|
} else if (hasDependencies) {
|
||||||
await this.spaceModelService.overwriteSpace(
|
// check for uuids that didn't change,
|
||||||
|
// get their device ids and check if they has a tag in device entity,
|
||||||
|
// if so move them ot the orphan space
|
||||||
|
|
||||||
|
await this.spaceModelService.removeSpaceOldSubspacesAndAllocations(
|
||||||
space,
|
space,
|
||||||
project,
|
project,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
@ -536,23 +499,45 @@ export class SpaceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSubspace) {
|
if (updateSpaceDto.subspaces) {
|
||||||
await this.subSpaceService.modifySubSpace(
|
await this.subSpaceService.updateSubspaceInSpace(
|
||||||
updateSpaceDto.subspace,
|
updateSpaceDto.subspaces,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
space,
|
space,
|
||||||
projectUuid,
|
projectUuid,
|
||||||
updateSpaceDto.tags,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateSpaceDto.tags) {
|
if (updateSpaceDto.tags) {
|
||||||
await this.spaceProductAllocationService.updateSpaceProductAllocations(
|
await queryRunner.manager.delete(SpaceProductAllocationEntity, {
|
||||||
updateSpaceDto.tags,
|
space: { uuid: space.uuid },
|
||||||
|
tag: {
|
||||||
|
uuid: Not(
|
||||||
|
In(
|
||||||
|
updateSpaceDto.tags
|
||||||
|
.filter((tag) => tag.tagUuid)
|
||||||
|
.map((tag) => tag.tagUuid),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await this.createAllocations(
|
||||||
|
updateSpaceDto.tags.map((tag) => ({
|
||||||
|
name: tag.name,
|
||||||
|
uuid: tag.tagUuid,
|
||||||
|
productUuid: tag.productUuid,
|
||||||
|
})),
|
||||||
projectUuid,
|
projectUuid,
|
||||||
space,
|
|
||||||
queryRunner,
|
queryRunner,
|
||||||
updateSpaceDto.subspace,
|
space,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (space.devices?.length) {
|
||||||
|
await this.deviceService.addDevicesToOrphanSpace(
|
||||||
|
space,
|
||||||
|
project,
|
||||||
|
queryRunner,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,7 +621,7 @@ export class SpaceService {
|
|||||||
// Get all spaces that are children of the provided space, including the parent-child relations
|
// Get all spaces that are children of the provided space, including the parent-child relations
|
||||||
const spaces = await this.spaceRepository.find({
|
const spaces = await this.spaceRepository.find({
|
||||||
where: { parent: { uuid: spaceUuid }, disabled: false },
|
where: { parent: { uuid: spaceUuid }, disabled: false },
|
||||||
relations: ['parent', 'children'], // Include parent and children relations
|
relations: ['parent', 'children'],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Organize spaces into a hierarchical structure
|
// Organize spaces into a hierarchical structure
|
||||||
@ -715,13 +700,13 @@ export class SpaceService {
|
|||||||
return rootSpaces;
|
return rootSpaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateSpaceCreation(
|
private validateSpaceCreationCriteria({
|
||||||
addSpaceDto: AddSpaceDto,
|
spaceModelUuid,
|
||||||
spaceModelUuid?: string,
|
tags,
|
||||||
) {
|
subspaces,
|
||||||
|
}: Pick<AddSpaceDto, 'spaceModelUuid' | 'tags' | 'subspaces'>): void {
|
||||||
const hasTagsOrSubspaces =
|
const hasTagsOrSubspaces =
|
||||||
(addSpaceDto.tags && addSpaceDto.tags.length > 0) ||
|
(tags && tags.length > 0) || (subspaces && subspaces.length > 0);
|
||||||
(addSpaceDto.subspaces && addSpaceDto.subspaces.length > 0);
|
|
||||||
|
|
||||||
if (spaceModelUuid && hasTagsOrSubspaces) {
|
if (spaceModelUuid && hasTagsOrSubspaces) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
@ -731,36 +716,36 @@ export class SpaceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createSubspaces(
|
private async createAllocations(
|
||||||
subspaces: AddSubspaceDto[],
|
|
||||||
space: SpaceEntity,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
tags: ProcessTagDto[],
|
|
||||||
projectUuid: string,
|
|
||||||
): Promise<void> {
|
|
||||||
space.subspaces = await this.subSpaceService.createSubspacesFromDto(
|
|
||||||
subspaces,
|
|
||||||
space,
|
|
||||||
queryRunner,
|
|
||||||
null,
|
|
||||||
projectUuid,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async createTags(
|
|
||||||
tags: ProcessTagDto[],
|
tags: ProcessTagDto[],
|
||||||
projectUuid: string,
|
projectUuid: string,
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
space: SpaceEntity,
|
space: SpaceEntity,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const processedTags = await this.newTagService.processTags(
|
const allocationsData = await this.tagService.processTags(
|
||||||
tags,
|
tags,
|
||||||
projectUuid,
|
projectUuid,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
await this.spaceProductAllocationService.createSpaceProductAllocations(
|
|
||||||
|
// Create a mapping of created tags by UUID and name for quick lookup
|
||||||
|
const createdTagsByUUID = new Map(allocationsData.map((t) => [t.uuid, t]));
|
||||||
|
const createdTagsByName = new Map(allocationsData.map((t) => [t.name, t]));
|
||||||
|
|
||||||
|
// Create the product-tag mapping based on the processed tags
|
||||||
|
const productTagMapping = tags.map(({ uuid, name, productUuid }) => {
|
||||||
|
const inputTag = uuid
|
||||||
|
? createdTagsByUUID.get(uuid)
|
||||||
|
: createdTagsByName.get(name);
|
||||||
|
return {
|
||||||
|
tag: inputTag?.uuid,
|
||||||
|
product: productUuid,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.spaceProductAllocationService.createProductAllocations(
|
||||||
space,
|
space,
|
||||||
processedTags,
|
productTagMapping,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import { DeviceEntity } from '@app/common/modules/device/entities';
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
import { In, QueryRunner } from 'typeorm';
|
||||||
import { DeviceSubSpaceParam, GetSubSpaceParam } from '../../dtos';
|
import { DeviceSubSpaceParam, GetSubSpaceParam } from '../../dtos';
|
||||||
import { ValidationService } from '../space-validation.service';
|
import { ValidationService } from '../space-validation.service';
|
||||||
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
|
||||||
import { In, QueryRunner } from 'typeorm';
|
|
||||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
|
||||||
import { TagRepository } from '@app/common/modules/space';
|
|
||||||
import { DeviceService } from 'src/device/services';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SubspaceDeviceService {
|
export class SubspaceDeviceService {
|
||||||
@ -17,7 +16,6 @@ export class SubspaceDeviceService {
|
|||||||
private readonly deviceRepository: DeviceRepository,
|
private readonly deviceRepository: DeviceRepository,
|
||||||
private readonly deviceService: DeviceService,
|
private readonly deviceService: DeviceService,
|
||||||
private readonly validationService: ValidationService,
|
private readonly validationService: ValidationService,
|
||||||
private readonly tagRepository: TagRepository,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async listDevicesInSubspace(
|
async listDevicesInSubspace(
|
||||||
@ -202,21 +200,6 @@ export class SubspaceDeviceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findNextTag(): Promise<number> {
|
|
||||||
const tags = await this.tagRepository.find({ select: ['tag'] });
|
|
||||||
|
|
||||||
const tagNumbers = tags
|
|
||||||
.map((t) => t.tag.match(/^Tag (\d+)$/))
|
|
||||||
.filter((match) => match)
|
|
||||||
.map((match) => parseInt(match[1]))
|
|
||||||
.sort((a, b) => a - b);
|
|
||||||
|
|
||||||
const nextTagNumber = tagNumbers.length
|
|
||||||
? tagNumbers[tagNumbers.length - 1] + 1
|
|
||||||
: 1;
|
|
||||||
return nextTagNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async findDeviceWithSubspaceAndTag(deviceUuid: string) {
|
private async findDeviceWithSubspaceAndTag(deviceUuid: string) {
|
||||||
return await this.deviceRepository.findOne({
|
return await this.deviceRepository.findOne({
|
||||||
where: { uuid: deviceUuid },
|
where: { uuid: deviceUuid },
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
|
||||||
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
|
import { SpaceProductAllocationRepository } from '@app/common/modules/space';
|
||||||
import { SpaceProductAllocationEntity } from '@app/common/modules/space/entities/space-product-allocation.entity';
|
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
|
||||||
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
|
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
|
||||||
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
||||||
import { SubspaceProductAllocationRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
import { SubspaceProductAllocationRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
import { NewTagEntity } from '@app/common/modules/tag';
|
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
import { UpdateSpaceAllocationDto } from 'src/space/interfaces/update-subspace-allocation.dto';
|
||||||
import { ISingleSubspace } from 'src/space/interfaces/single-subspace.interface';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
|
||||||
import { TagService as NewTagService } from 'src/tags/services';
|
import { TagService as NewTagService } from 'src/tags/services';
|
||||||
import { In, QueryRunner } from 'typeorm';
|
import { In, Not, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SubspaceProductAllocationService {
|
export class SubspaceProductAllocationService {
|
||||||
@ -23,44 +16,38 @@ export class SubspaceProductAllocationService {
|
|||||||
private readonly subspaceProductAllocationRepository: SubspaceProductAllocationRepository,
|
private readonly subspaceProductAllocationRepository: SubspaceProductAllocationRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createSubspaceProductAllocations(
|
async createProductAllocations(
|
||||||
subspace: SubspaceEntity,
|
subspace: SubspaceEntity,
|
||||||
processedTags: NewTagEntity[],
|
allocationsData: { product: string; tag: string }[],
|
||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
spaceAllocationsToExclude?: SpaceProductAllocationEntity[],
|
// spaceAllocationsToExclude?: SpaceProductAllocationEntity[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
if (!processedTags.length) return;
|
if (!allocationsData.length) return;
|
||||||
|
|
||||||
const allocations: SubspaceProductAllocationEntity[] = [];
|
const allocations: SubspaceProductAllocationEntity[] = [];
|
||||||
|
|
||||||
for (const tag of processedTags) {
|
for (const allocationData of allocationsData) {
|
||||||
await this.validateTagWithinSubspace(
|
// await this.validateTagWithinSubspace(
|
||||||
queryRunner,
|
// queryRunner,
|
||||||
tag,
|
// allocationData.tag,
|
||||||
subspace,
|
// subspace,
|
||||||
spaceAllocationsToExclude,
|
// spaceAllocationsToExclude,
|
||||||
);
|
// );
|
||||||
|
|
||||||
let allocation = await this.getAllocationByProduct(
|
if (
|
||||||
tag.product,
|
await this.isAllocationExist(allocationData, subspace, queryRunner)
|
||||||
subspace,
|
) {
|
||||||
queryRunner,
|
continue;
|
||||||
);
|
}
|
||||||
|
|
||||||
if (!allocation) {
|
const allocation = this.createNewSubspaceAllocation(
|
||||||
allocation = this.createNewSubspaceAllocation(
|
|
||||||
subspace,
|
subspace,
|
||||||
tag,
|
allocationData,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
allocations.push(allocation);
|
allocations.push(allocation);
|
||||||
} else if (!allocation.tags.some((t) => t.uuid === tag.uuid)) {
|
|
||||||
allocation.tags.push(tag);
|
|
||||||
await this.saveAllocation(allocation, queryRunner);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (allocations.length > 0) {
|
if (allocations.length > 0) {
|
||||||
await this.saveAllocations(allocations, queryRunner);
|
await this.saveAllocations(allocations, queryRunner);
|
||||||
}
|
}
|
||||||
@ -71,307 +58,130 @@ export class SubspaceProductAllocationService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async updateSubspaceProductAllocations(
|
|
||||||
subspaces: ISingleSubspace[],
|
async updateSubspaceProductAllocationsV2(
|
||||||
|
subSpaces: UpdateSpaceAllocationDto[],
|
||||||
projectUuid: string,
|
projectUuid: string,
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
space: SpaceEntity,
|
|
||||||
spaceTagUpdateDtos?: ModifyTagDto[],
|
|
||||||
) {
|
) {
|
||||||
const spaceAllocationToExclude: SpaceProductAllocationEntity[] = [];
|
await Promise.all(
|
||||||
for (const subspace of subspaces) {
|
subSpaces.map(async (subspace) => {
|
||||||
if (!subspace.tags || subspace.tags.length === 0) continue;
|
await queryRunner.manager.delete(SubspaceProductAllocationEntity, {
|
||||||
const tagDtos = subspace.tags;
|
subspace: { uuid: subspace.uuid },
|
||||||
const tagsToAddDto: ProcessTagDto[] = tagDtos
|
tag: {
|
||||||
.filter((dto) => dto.action === ModifyAction.ADD)
|
uuid: Not(
|
||||||
.map((dto) => ({
|
In(
|
||||||
name: dto.name,
|
subspace.tags.filter((tag) => tag.uuid).map((tag) => tag.uuid),
|
||||||
productUuid: dto.productUuid,
|
),
|
||||||
uuid: dto.newTagUuid,
|
),
|
||||||
}));
|
},
|
||||||
|
});
|
||||||
const tagsToDeleteDto = tagDtos.filter(
|
const subspaceEntity = await queryRunner.manager.findOne(
|
||||||
(dto) => dto.action === ModifyAction.DELETE,
|
SubspaceEntity,
|
||||||
|
{
|
||||||
|
where: { uuid: subspace.uuid },
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (tagsToAddDto.length > 0) {
|
const processedTags = await this.tagService.processTags(
|
||||||
let processedTags = await this.tagService.processTags(
|
subspace.tags,
|
||||||
tagsToAddDto,
|
|
||||||
projectUuid,
|
projectUuid,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const subspaceDto of subspaces) {
|
const createdTagsByUUID = new Map(
|
||||||
if (
|
processedTags.map((t) => [t.uuid, t]),
|
||||||
subspaceDto !== subspace &&
|
);
|
||||||
subspaceDto.action === ModifyAction.UPDATE &&
|
const createdTagsByName = new Map(
|
||||||
subspaceDto.tags
|
processedTags.map((t) => [t.name, t]),
|
||||||
) {
|
|
||||||
const deletedTags = subspaceDto.tags.filter(
|
|
||||||
(tagDto) =>
|
|
||||||
tagDto.action === ModifyAction.DELETE &&
|
|
||||||
processedTags.some((tag) => tag.uuid === tagDto.tagUuid),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const deletedTag of deletedTags) {
|
// Create the product-tag mapping based on the processed tags
|
||||||
const allocation = await queryRunner.manager.findOne(
|
const productTagMapping = subspace.tags.map(
|
||||||
SubspaceProductAllocationEntity,
|
({ uuid, name, productUuid }) => {
|
||||||
{
|
const inputTag = uuid
|
||||||
where: {
|
? createdTagsByUUID.get(uuid)
|
||||||
subspace: { uuid: subspaceDto.subspace.uuid },
|
: createdTagsByName.get(name);
|
||||||
},
|
return {
|
||||||
relations: ['tags', 'product', 'subspace'],
|
tag: inputTag?.uuid,
|
||||||
|
product: productUuid,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const isCommonTag = allocation.tags.some(
|
await this.createProductAllocations(
|
||||||
(tag) => tag.uuid === deletedTag.tagUuid,
|
subspaceEntity,
|
||||||
);
|
productTagMapping,
|
||||||
|
|
||||||
if (allocation && isCommonTag) {
|
|
||||||
const tagEntity = allocation.tags.find(
|
|
||||||
(tag) => tag.uuid === deletedTag.tagUuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
allocation.tags = allocation.tags.filter(
|
|
||||||
(tag) => tag.uuid !== deletedTag.tagUuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
await queryRunner.manager.save(allocation);
|
|
||||||
|
|
||||||
const productAllocationExistInSubspace =
|
|
||||||
await queryRunner.manager.findOne(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
subspace: {
|
|
||||||
uuid: subspaceDto.subspace.uuid,
|
|
||||||
},
|
|
||||||
product: { uuid: allocation.product.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (productAllocationExistInSubspace) {
|
|
||||||
productAllocationExistInSubspace.tags.push(tagEntity);
|
|
||||||
await queryRunner.manager.save(
|
|
||||||
productAllocationExistInSubspace,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const newProductAllocation = queryRunner.manager.create(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
subspace: subspace.subspace,
|
|
||||||
product: allocation.product,
|
|
||||||
tags: [tagEntity],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
await queryRunner.manager.save(newProductAllocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
processedTags = processedTags.filter(
|
|
||||||
(tag) => tag.uuid !== deletedTag.tagUuid,
|
|
||||||
);
|
|
||||||
|
|
||||||
subspaceDto.tags = subspaceDto.tags.filter(
|
|
||||||
(tagDto) => tagDto.tagUuid !== deletedTag.tagUuid,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
subspaceDto !== subspace &&
|
|
||||||
subspaceDto.action === ModifyAction.DELETE
|
|
||||||
) {
|
|
||||||
const allocation = await queryRunner.manager.findOne(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
subspace: { uuid: subspaceDto.subspace.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const repeatedTags = allocation?.tags.filter((tag) =>
|
|
||||||
processedTags.some(
|
|
||||||
(processedTag) => processedTag.uuid === tag.uuid,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (repeatedTags.length > 0) {
|
|
||||||
allocation.tags = allocation.tags.filter(
|
|
||||||
(tag) =>
|
|
||||||
!repeatedTags.some(
|
|
||||||
(repeatedTag) => repeatedTag.uuid === tag.uuid,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
await queryRunner.manager.save(allocation);
|
|
||||||
|
|
||||||
const productAllocationExistInSubspace =
|
|
||||||
await queryRunner.manager.findOne(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
subspace: { uuid: subspaceDto.subspace.uuid },
|
|
||||||
product: { uuid: allocation.product.uuid },
|
|
||||||
},
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (productAllocationExistInSubspace) {
|
|
||||||
productAllocationExistInSubspace.tags.push(...repeatedTags);
|
|
||||||
await queryRunner.manager.save(
|
|
||||||
productAllocationExistInSubspace,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const newProductAllocation = queryRunner.manager.create(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
subspace: subspace.subspace,
|
|
||||||
product: allocation.product,
|
|
||||||
tags: repeatedTags,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
await queryRunner.manager.save(newProductAllocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newAllocation = queryRunner.manager.create(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
subspace: subspace.subspace,
|
|
||||||
product: allocation.product,
|
|
||||||
tags: repeatedTags,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
await queryRunner.manager.save(newAllocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (spaceTagUpdateDtos) {
|
|
||||||
const deletedSpaceTags = spaceTagUpdateDtos.filter(
|
|
||||||
(tagDto) =>
|
|
||||||
tagDto.action === ModifyAction.DELETE &&
|
|
||||||
processedTags.some((tag) => tag.uuid === tagDto.tagUuid),
|
|
||||||
);
|
|
||||||
for (const deletedTag of deletedSpaceTags) {
|
|
||||||
const allocation = await queryRunner.manager.findOne(
|
|
||||||
SpaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
space: { uuid: space.uuid },
|
|
||||||
tags: { uuid: deletedTag.tagUuid },
|
|
||||||
},
|
|
||||||
relations: ['tags', 'subspace'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
allocation &&
|
|
||||||
allocation.tags.some((tag) => tag.uuid === deletedTag.tagUuid)
|
|
||||||
) {
|
|
||||||
spaceAllocationToExclude.push(allocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.createSubspaceProductAllocations(
|
|
||||||
subspace.subspace,
|
|
||||||
processedTags,
|
|
||||||
queryRunner,
|
queryRunner,
|
||||||
spaceAllocationToExclude,
|
|
||||||
);
|
);
|
||||||
}
|
}),
|
||||||
if (tagsToDeleteDto.length > 0) {
|
|
||||||
await this.processDeleteActions(tagsToDeleteDto, queryRunner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async processDeleteActions(
|
|
||||||
dtos: ModifyTagDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
): Promise<SubspaceProductAllocationEntity[]> {
|
|
||||||
try {
|
|
||||||
if (!dtos || dtos.length === 0) {
|
|
||||||
throw new Error('No DTOs provided for deletion.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagUuidsToDelete = dtos
|
|
||||||
.filter((dto) => dto.action === ModifyAction.DELETE && dto.tagUuid)
|
|
||||||
.map((dto) => dto.tagUuid);
|
|
||||||
|
|
||||||
if (tagUuidsToDelete.length === 0) return [];
|
|
||||||
|
|
||||||
const allocationsToUpdate = await queryRunner.manager.find(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
{
|
|
||||||
where: { tags: { uuid: In(tagUuidsToDelete) } },
|
|
||||||
relations: ['tags'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!allocationsToUpdate || allocationsToUpdate.length === 0) return [];
|
|
||||||
|
|
||||||
const deletedAllocations: SubspaceProductAllocationEntity[] = [];
|
|
||||||
const allocationUpdates: SubspaceProductAllocationEntity[] = [];
|
|
||||||
|
|
||||||
for (const allocation of allocationsToUpdate) {
|
|
||||||
const updatedTags = allocation.tags.filter(
|
|
||||||
(tag) => !tagUuidsToDelete.includes(tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (updatedTags.length === allocation.tags.length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updatedTags.length === 0) {
|
|
||||||
deletedAllocations.push(allocation);
|
|
||||||
} else {
|
|
||||||
allocation.tags = updatedTags;
|
|
||||||
allocationUpdates.push(allocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allocationUpdates.length > 0) {
|
|
||||||
await queryRunner.manager.save(
|
|
||||||
SubspaceProductAllocationEntity,
|
|
||||||
allocationUpdates,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deletedAllocations.length > 0) {
|
// async processDeleteActions(dtos: ModifyTagDto[], queryRunner: QueryRunner) {
|
||||||
await queryRunner.manager.remove(
|
// // : Promise<SubspaceProductAllocationEntity[]>
|
||||||
SubspaceProductAllocationEntity,
|
// try {
|
||||||
deletedAllocations,
|
// // if (!dtos || dtos.length === 0) {
|
||||||
);
|
// // throw new Error('No DTOs provided for deletion.');
|
||||||
}
|
// // }
|
||||||
|
// // const tagUuidsToDelete = dtos
|
||||||
await queryRunner.manager
|
// // .filter((dto) => dto.action === ModifyAction.DELETE && dto.tagUuid)
|
||||||
.createQueryBuilder()
|
// // .map((dto) => dto.tagUuid);
|
||||||
.delete()
|
// // if (tagUuidsToDelete.length === 0) return [];
|
||||||
.from('subspace_product_tags')
|
// // const allocationsToUpdate = await queryRunner.manager.find(
|
||||||
.where(
|
// // SubspaceProductAllocationEntity,
|
||||||
'subspace_product_allocation_uuid NOT IN ' +
|
// // {
|
||||||
queryRunner.manager
|
// // where: { tag: In(tagUuidsToDelete) },
|
||||||
.createQueryBuilder()
|
// // },
|
||||||
.select('allocation.uuid')
|
// // );
|
||||||
.from(SubspaceProductAllocationEntity, 'allocation')
|
// // if (!allocationsToUpdate || allocationsToUpdate.length === 0) return [];
|
||||||
.getQuery() +
|
// // const deletedAllocations: SubspaceProductAllocationEntity[] = [];
|
||||||
')',
|
// // const allocationUpdates: SubspaceProductAllocationEntity[] = [];
|
||||||
)
|
// // for (const allocation of allocationsToUpdate) {
|
||||||
.execute();
|
// // const updatedTags = allocation.tags.filter(
|
||||||
|
// // (tag) => !tagUuidsToDelete.includes(tag.uuid),
|
||||||
return deletedAllocations;
|
// // );
|
||||||
} catch (error) {
|
// // if (updatedTags.length === allocation.tags.length) {
|
||||||
throw this.handleError(error, `Failed to delete tags in subspace`);
|
// // continue;
|
||||||
}
|
// // }
|
||||||
}
|
// // if (updatedTags.length === 0) {
|
||||||
|
// // deletedAllocations.push(allocation);
|
||||||
|
// // } else {
|
||||||
|
// // allocation.tags = updatedTags;
|
||||||
|
// // allocationUpdates.push(allocation);
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // if (allocationUpdates.length > 0) {
|
||||||
|
// // await queryRunner.manager.save(
|
||||||
|
// // SubspaceProductAllocationEntity,
|
||||||
|
// // allocationUpdates,
|
||||||
|
// // );
|
||||||
|
// // }
|
||||||
|
// // if (deletedAllocations.length > 0) {
|
||||||
|
// // await queryRunner.manager.remove(
|
||||||
|
// // SubspaceProductAllocationEntity,
|
||||||
|
// // deletedAllocations,
|
||||||
|
// // );
|
||||||
|
// // }
|
||||||
|
// // await queryRunner.manager
|
||||||
|
// // .createQueryBuilder()
|
||||||
|
// // .delete()
|
||||||
|
// // .from('subspace_product_tags')
|
||||||
|
// // .where(
|
||||||
|
// // 'subspace_product_allocation_uuid NOT IN ' +
|
||||||
|
// // queryRunner.manager
|
||||||
|
// // .createQueryBuilder()
|
||||||
|
// // .select('allocation.uuid')
|
||||||
|
// // .from(SubspaceProductAllocationEntity, 'allocation')
|
||||||
|
// // .getQuery() +
|
||||||
|
// // ')',
|
||||||
|
// // )
|
||||||
|
// // .execute();
|
||||||
|
// // return deletedAllocations;
|
||||||
|
// } catch (error) {
|
||||||
|
// throw this.handleError(error, `Failed to delete tags in subspace`);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
async unlinkModels(
|
async unlinkModels(
|
||||||
allocations: SubspaceProductAllocationEntity[],
|
allocations: SubspaceProductAllocationEntity[],
|
||||||
@ -395,108 +205,106 @@ export class SubspaceProductAllocationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async validateTagWithinSubspace(
|
// private async validateTagWithinSubspace(
|
||||||
queryRunner: QueryRunner | undefined,
|
// queryRunner: QueryRunner | undefined,
|
||||||
tag: NewTagEntity,
|
// tag: NewTagEntity & { product: string },
|
||||||
subspace: SubspaceEntity,
|
// subspace: SubspaceEntity,
|
||||||
spaceAllocationsToExclude?: SpaceProductAllocationEntity[],
|
// spaceAllocationsToExclude?: SpaceProductAllocationEntity[],
|
||||||
): Promise<void> {
|
// ): Promise<void> {
|
||||||
const existingTagInSpace = await (queryRunner
|
// // const existingTagInSpace = await (queryRunner
|
||||||
? queryRunner.manager.findOne(SpaceProductAllocationEntity, {
|
// // ? queryRunner.manager.findOne(SpaceProductAllocationEntity, {
|
||||||
where: {
|
// // where: {
|
||||||
product: { uuid: tag.product.uuid },
|
// // product: { uuid: tag.product },
|
||||||
space: { uuid: subspace.space.uuid },
|
// // space: { uuid: subspace.space.uuid },
|
||||||
tags: { uuid: tag.uuid },
|
// // tag: { uuid: tag.uuid },
|
||||||
},
|
// // },
|
||||||
relations: ['tags'],
|
// // })
|
||||||
})
|
// // : this.spaceProductAllocationRepository.findOne({
|
||||||
: this.spaceProductAllocationRepository.findOne({
|
// // where: {
|
||||||
where: {
|
// // product: { uuid: tag.product },
|
||||||
product: { uuid: tag.product.uuid },
|
// // space: { uuid: subspace.space.uuid },
|
||||||
space: { uuid: subspace.space.uuid },
|
// // tag: { uuid: tag.uuid },
|
||||||
tags: { uuid: tag.uuid },
|
// // },
|
||||||
},
|
// // }));
|
||||||
relations: ['tags'],
|
// // const isExcluded = spaceAllocationsToExclude?.some(
|
||||||
}));
|
// // (excludedAllocation) =>
|
||||||
|
// // excludedAllocation.product.uuid === tag.product &&
|
||||||
|
// // excludedAllocation.tags.some((t) => t.uuid === tag.uuid),
|
||||||
|
// // );
|
||||||
|
// // if (!isExcluded && existingTagInSpace) {
|
||||||
|
// // throw new HttpException(
|
||||||
|
// // `Tag ${tag.uuid} (Product: ${tag.product}) is already allocated at the space level (${subspace.space.uuid}). Cannot allocate the same tag in a subspace.`,
|
||||||
|
// // HttpStatus.BAD_REQUEST,
|
||||||
|
// // );
|
||||||
|
// // }
|
||||||
|
// // // ?: Check if the tag is already allocated in another "subspace" within the same space
|
||||||
|
// // const existingTagInSameSpace = await (queryRunner
|
||||||
|
// // ? queryRunner.manager.findOne(SubspaceProductAllocationEntity, {
|
||||||
|
// // where: {
|
||||||
|
// // product: { uuid: tag.product },
|
||||||
|
// // subspace: { space: subspace.space },
|
||||||
|
// // tag: { uuid: tag.uuid },
|
||||||
|
// // },
|
||||||
|
// // relations: ['subspace'],
|
||||||
|
// // })
|
||||||
|
// // : this.subspaceProductAllocationRepository.findOne({
|
||||||
|
// // where: {
|
||||||
|
// // product: { uuid: tag.product },
|
||||||
|
// // subspace: { space: subspace.space },
|
||||||
|
// // tag: { uuid: tag.uuid },
|
||||||
|
// // },
|
||||||
|
// // relations: ['subspace'],
|
||||||
|
// // }));
|
||||||
|
// // if (
|
||||||
|
// // existingTagInSameSpace &&
|
||||||
|
// // existingTagInSameSpace.subspace.uuid !== subspace.uuid
|
||||||
|
// // ) {
|
||||||
|
// // throw new HttpException(
|
||||||
|
// // `Tag ${tag.uuid} (Product: ${tag.product}) is already allocated in another subspace (${existingTagInSameSpace.subspace.uuid}) within the same space (${subspace.space.uuid}).`,
|
||||||
|
// // HttpStatus.BAD_REQUEST,
|
||||||
|
// // );
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
|
||||||
const isExcluded = spaceAllocationsToExclude?.some(
|
|
||||||
(excludedAllocation) =>
|
|
||||||
excludedAllocation.product.uuid === tag.product.uuid &&
|
|
||||||
excludedAllocation.tags.some((t) => t.uuid === tag.uuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isExcluded && existingTagInSpace) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag ${tag.uuid} (Product: ${tag.product.uuid}) is already allocated at the space level (${subspace.space.uuid}). Cannot allocate the same tag in a subspace.`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const existingTagInSameSpace = await (queryRunner
|
|
||||||
? queryRunner.manager.findOne(SubspaceProductAllocationEntity, {
|
|
||||||
where: {
|
|
||||||
product: { uuid: tag.product.uuid },
|
|
||||||
subspace: { space: subspace.space },
|
|
||||||
tags: { uuid: tag.uuid },
|
|
||||||
},
|
|
||||||
relations: ['subspace', 'tags'],
|
|
||||||
})
|
|
||||||
: this.subspaceProductAllocationRepository.findOne({
|
|
||||||
where: {
|
|
||||||
product: { uuid: tag.product.uuid },
|
|
||||||
subspace: { space: subspace.space },
|
|
||||||
tags: { uuid: tag.uuid },
|
|
||||||
},
|
|
||||||
relations: ['subspace', 'tags'],
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (
|
|
||||||
existingTagInSameSpace &&
|
|
||||||
existingTagInSameSpace.subspace.uuid !== subspace.uuid
|
|
||||||
) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag ${tag.uuid} (Product: ${tag.product.uuid}) is already allocated in another subspace (${existingTagInSameSpace.subspace.uuid}) within the same space (${subspace.space.uuid}).`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private createNewSubspaceAllocation(
|
private createNewSubspaceAllocation(
|
||||||
subspace: SubspaceEntity,
|
subspace: SubspaceEntity,
|
||||||
tag: NewTagEntity,
|
allocationData: { product: string; tag: string },
|
||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
): SubspaceProductAllocationEntity {
|
): SubspaceProductAllocationEntity {
|
||||||
return queryRunner
|
return queryRunner
|
||||||
? queryRunner.manager.create(SubspaceProductAllocationEntity, {
|
? queryRunner.manager.create(SubspaceProductAllocationEntity, {
|
||||||
subspace,
|
subspace,
|
||||||
product: tag.product,
|
product: { uuid: allocationData.product },
|
||||||
tags: [tag],
|
tag: { uuid: allocationData.tag },
|
||||||
})
|
})
|
||||||
: this.subspaceProductAllocationRepository.create({
|
: this.subspaceProductAllocationRepository.create({
|
||||||
subspace,
|
subspace,
|
||||||
product: tag.product,
|
product: { uuid: allocationData.product },
|
||||||
tags: [tag],
|
tag: { uuid: allocationData.tag },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private async getAllocationByProduct(
|
|
||||||
product: ProductEntity,
|
private async isAllocationExist(
|
||||||
|
allocationData: { product: string; tag: string },
|
||||||
subspace: SubspaceEntity,
|
subspace: SubspaceEntity,
|
||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
): Promise<SubspaceProductAllocationEntity | null> {
|
): Promise<boolean> {
|
||||||
return queryRunner
|
const allocation = queryRunner
|
||||||
? queryRunner.manager.findOne(SubspaceProductAllocationEntity, {
|
? await queryRunner.manager.findOne(SubspaceProductAllocationEntity, {
|
||||||
where: {
|
where: {
|
||||||
subspace: { uuid: subspace.uuid },
|
subspace: { uuid: subspace.uuid },
|
||||||
product: { uuid: product.uuid },
|
product: { uuid: allocationData.product },
|
||||||
|
tag: { uuid: allocationData.tag },
|
||||||
},
|
},
|
||||||
relations: ['tags'],
|
|
||||||
})
|
})
|
||||||
: this.subspaceProductAllocationRepository.findOne({
|
: await this.subspaceProductAllocationRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
subspace: { uuid: subspace.uuid },
|
subspace: { uuid: subspace.uuid },
|
||||||
product: { uuid: product.uuid },
|
product: { uuid: allocationData.product },
|
||||||
|
tag: { uuid: allocationData.tag },
|
||||||
},
|
},
|
||||||
relations: ['tags'],
|
|
||||||
});
|
});
|
||||||
|
return !!allocation;
|
||||||
}
|
}
|
||||||
private async saveAllocation(
|
private async saveAllocation(
|
||||||
allocation: SubspaceProductAllocationEntity,
|
allocation: SubspaceProductAllocationEntity,
|
||||||
@ -535,34 +343,9 @@ export class SubspaceProductAllocationService {
|
|||||||
}
|
}
|
||||||
async clearAllAllocations(subspaceUuids: string[], queryRunner: QueryRunner) {
|
async clearAllAllocations(subspaceUuids: string[], queryRunner: QueryRunner) {
|
||||||
try {
|
try {
|
||||||
const allocationUuids = await queryRunner.manager
|
await queryRunner.manager.delete(SubspaceProductAllocationEntity, {
|
||||||
.createQueryBuilder(SubspaceProductAllocationEntity, 'allocation')
|
subspace: { uuid: In(subspaceUuids) },
|
||||||
.select('allocation.uuid')
|
});
|
||||||
.where('allocation.subspace_uuid IN (:...subspaceUuids)', {
|
|
||||||
subspaceUuids,
|
|
||||||
})
|
|
||||||
.getRawMany()
|
|
||||||
.then((results) => results.map((r) => r.allocation_uuid));
|
|
||||||
|
|
||||||
if (allocationUuids.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.delete()
|
|
||||||
.from('subspace_product_tags')
|
|
||||||
.where('subspace_product_allocation_uuid IN (:...allocationUuids)', {
|
|
||||||
allocationUuids,
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.delete()
|
|
||||||
.from(SubspaceProductAllocationEntity)
|
|
||||||
.where('subspace_uuid IN (:...subspaceUuids)', { subspaceUuids })
|
|
||||||
.execute();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
error instanceof HttpException
|
error instanceof HttpException
|
||||||
|
@ -1,32 +1,33 @@
|
|||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import {
|
||||||
|
TypeORMCustomModel,
|
||||||
|
TypeORMCustomModelFindAllQuery,
|
||||||
|
} from '@app/common/models/typeOrmCustom.model';
|
||||||
|
import { SubspaceDto } from '@app/common/modules/space/dtos';
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
|
import { In, Not, QueryRunner } from 'typeorm';
|
||||||
import {
|
import {
|
||||||
AddSubspaceDto,
|
AddSubspaceDto,
|
||||||
GetSpaceParam,
|
GetSpaceParam,
|
||||||
GetSubSpaceParam,
|
GetSubSpaceParam,
|
||||||
ModifySubspaceDto,
|
ModifySubspaceDto,
|
||||||
} from '../../dtos';
|
} from '../../dtos';
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|
||||||
import {
|
|
||||||
TypeORMCustomModel,
|
|
||||||
TypeORMCustomModelFindAllQuery,
|
|
||||||
} from '@app/common/models/typeOrmCustom.model';
|
|
||||||
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
|
||||||
import { SubspaceDto } from '@app/common/modules/space/dtos';
|
|
||||||
import { In, QueryRunner } from 'typeorm';
|
|
||||||
|
|
||||||
import { SubspaceModelEntity } from '@app/common/modules/space-model';
|
import { SubspaceModelEntity } from '@app/common/modules/space-model';
|
||||||
import { ValidationService } from '../space-validation.service';
|
|
||||||
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
|
||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
|
||||||
import { SubspaceDeviceService } from './subspace-device.service';
|
|
||||||
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||||
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
|
||||||
import { TagService as NewTagService } from 'src/tags/services/tags.service';
|
|
||||||
import { SubspaceProductAllocationService } from './subspace-product-allocation.service';
|
|
||||||
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
|
import { SubspaceProductAllocationEntity } from '@app/common/modules/space/entities/subspace/subspace-product-allocation.entity';
|
||||||
|
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
||||||
|
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
|
import {
|
||||||
|
AllocationsOwnerType,
|
||||||
|
CreateAllocationsDto,
|
||||||
|
} from 'src/space/dtos/create-allocations.dto';
|
||||||
|
import { TagService as NewTagService } from 'src/tags/services/tags.service';
|
||||||
|
import { ValidationService } from '../space-validation.service';
|
||||||
|
import { SubspaceDeviceService } from './subspace-device.service';
|
||||||
|
import { SubspaceProductAllocationService } from './subspace-product-allocation.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SubSpaceService {
|
export class SubSpaceService {
|
||||||
@ -55,9 +56,9 @@ export class SubSpaceService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const subspaces = subspaceData.map((data) =>
|
const subspaces = subspaceData.map((data) =>
|
||||||
queryRunner.manager.create(this.subspaceRepository.target, data),
|
queryRunner.manager.create(SubspaceEntity, data),
|
||||||
);
|
);
|
||||||
return await queryRunner.manager.save(subspaces);
|
return queryRunner.manager.save(subspaces);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
`An unexpected error occurred while creating subspaces. ${error}`,
|
`An unexpected error occurred while creating subspaces. ${error}`,
|
||||||
@ -91,42 +92,30 @@ export class SubSpaceService {
|
|||||||
addSubspaceDtos: AddSubspaceDto[],
|
addSubspaceDtos: AddSubspaceDto[],
|
||||||
space: SpaceEntity,
|
space: SpaceEntity,
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
otherTags?: ProcessTagDto[],
|
|
||||||
projectUuid?: string,
|
projectUuid?: string,
|
||||||
): Promise<SubspaceEntity[]> {
|
): Promise<SubspaceEntity[]> {
|
||||||
try {
|
try {
|
||||||
this.checkForDuplicateNames(
|
const createdSubspaces = await this.createSubspaces(
|
||||||
addSubspaceDtos.map(({ subspaceName }) => subspaceName),
|
addSubspaceDtos.map((dto) => ({
|
||||||
);
|
|
||||||
|
|
||||||
const subspaceData = addSubspaceDtos.map((dto) => ({
|
|
||||||
subspaceName: dto.subspaceName,
|
subspaceName: dto.subspaceName,
|
||||||
space,
|
space,
|
||||||
}));
|
})),
|
||||||
|
queryRunner,
|
||||||
const subspaces = await this.createSubspaces(subspaceData, queryRunner);
|
);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
addSubspaceDtos.map(async (dto, index) => {
|
addSubspaceDtos.map(async ({ tags }, index) => {
|
||||||
const subspace = subspaces[index];
|
// map the dto to the corresponding subspace
|
||||||
|
const subspace = createdSubspaces[index];
|
||||||
const allTags = [...(dto.tags || []), ...(otherTags || [])];
|
await this.createAllocations({
|
||||||
|
|
||||||
if (allTags.length) {
|
|
||||||
const processedTags = await this.newTagService.processTags(
|
|
||||||
allTags,
|
|
||||||
projectUuid,
|
projectUuid,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
);
|
tags,
|
||||||
|
type: AllocationsOwnerType.SUBSPACE,
|
||||||
await this.subspaceProductAllocationService.createSubspaceProductAllocations(
|
|
||||||
subspace,
|
subspace,
|
||||||
processedTags,
|
});
|
||||||
queryRunner,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return subspaces;
|
return createdSubspaces;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof HttpException) {
|
if (error instanceof HttpException) {
|
||||||
throw error;
|
throw error;
|
||||||
@ -315,62 +304,59 @@ export class SubSpaceService {
|
|||||||
return deleteResults;
|
return deleteResults;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
async modifySubSpace(
|
async updateSubspaceInSpace(
|
||||||
subspaceDtos: ModifySubspaceDto[],
|
subspaceDtos: ModifySubspaceDto[],
|
||||||
queryRunner: QueryRunner,
|
queryRunner: QueryRunner,
|
||||||
space?: SpaceEntity,
|
space: SpaceEntity,
|
||||||
projectUuid?: string,
|
projectUuid: string,
|
||||||
spaceTagUpdateDtos?: ModifyTagDto[],
|
|
||||||
) {
|
) {
|
||||||
if (!subspaceDtos || subspaceDtos.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const addedSubspaces = [];
|
// disable subspaces that are not in the provided list & delte their allocations
|
||||||
const updatedSubspaces = [];
|
await queryRunner.manager.update(
|
||||||
|
SubspaceEntity,
|
||||||
for (const subspace of subspaceDtos) {
|
{
|
||||||
switch (subspace.action) {
|
uuid: Not(
|
||||||
case ModifyAction.ADD:
|
In(subspaceDtos.filter(({ uuid }) => uuid).map(({ uuid }) => uuid)),
|
||||||
const addedSubspace = await this.handleAddAction(
|
),
|
||||||
subspace,
|
space: { uuid: space.uuid },
|
||||||
space,
|
},
|
||||||
queryRunner,
|
{
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
if (addedSubspace) addedSubspaces.push(addedSubspace);
|
|
||||||
|
|
||||||
break;
|
await queryRunner.manager.delete(SubspaceProductAllocationEntity, {
|
||||||
case ModifyAction.UPDATE:
|
subspace: { uuid: Not(In(subspaceDtos.map((dto) => dto.uuid))) },
|
||||||
const updatedSubspace = await this.handleUpdateAction(
|
});
|
||||||
subspace,
|
|
||||||
queryRunner,
|
// create or update subspaces provided in the list
|
||||||
|
const newSubspaces = this.subspaceRepository.create(
|
||||||
|
subspaceDtos.filter((dto) => !dto.uuid),
|
||||||
);
|
);
|
||||||
if (updatedSubspace) {
|
|
||||||
updatedSubspaces.push(updatedSubspace);
|
const updatedSubspaces: SubspaceEntity[] = await queryRunner.manager.save(
|
||||||
|
SubspaceEntity,
|
||||||
|
[...newSubspaces, ...subspaceDtos.filter((dto) => dto.uuid)].map(
|
||||||
|
(subspace) => ({ ...subspace, space }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// create or update allocations for the subspaces
|
||||||
|
if (updatedSubspaces.length > 0) {
|
||||||
|
await this.subspaceProductAllocationService.updateSubspaceProductAllocationsV2(
|
||||||
|
subspaceDtos.map((dto) => {
|
||||||
|
if (!dto.uuid) {
|
||||||
|
dto.uuid = updatedSubspaces.find(
|
||||||
|
(subspace) => subspace.subspaceName === dto.subspaceName,
|
||||||
|
)?.uuid;
|
||||||
}
|
}
|
||||||
break;
|
return {
|
||||||
case ModifyAction.DELETE:
|
tags: dto.tags || [],
|
||||||
await this.handleDeleteAction(subspace, queryRunner);
|
uuid: dto.uuid,
|
||||||
break;
|
};
|
||||||
default:
|
}),
|
||||||
throw new HttpException(
|
|
||||||
`Invalid action "${subspace.action}".`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const combinedSubspaces = [...addedSubspaces, ...updatedSubspaces].filter(
|
|
||||||
(subspace) => subspace !== undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (combinedSubspaces.length > 0) {
|
|
||||||
await this.subspaceProductAllocationService.updateSubspaceProductAllocations(
|
|
||||||
combinedSubspaces,
|
|
||||||
projectUuid,
|
projectUuid,
|
||||||
queryRunner,
|
queryRunner,
|
||||||
space,
|
|
||||||
spaceTagUpdateDtos,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -427,70 +413,10 @@ export class SubSpaceService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleAddAction(
|
|
||||||
subspace: ModifySubspaceDto,
|
|
||||||
space: SpaceEntity,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
): Promise<SubspaceEntity> {
|
|
||||||
const createTagDtos: ProcessTagDto[] =
|
|
||||||
subspace.tags?.map((tag) => ({
|
|
||||||
name: tag.name as string,
|
|
||||||
uuid: tag.tagUuid,
|
|
||||||
productUuid: tag.productUuid as string,
|
|
||||||
})) || [];
|
|
||||||
const subSpace = await this.createSubspacesFromDto(
|
|
||||||
[{ subspaceName: subspace.subspaceName, tags: createTagDtos }],
|
|
||||||
space,
|
|
||||||
queryRunner,
|
|
||||||
);
|
|
||||||
return subSpace[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
private async handleUpdateAction(
|
|
||||||
modifyDto: ModifySubspaceDto,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
): Promise<SubspaceEntity> {
|
|
||||||
const subspace = await this.findOne(modifyDto.uuid);
|
|
||||||
const updatedSubspace = await this.update(
|
|
||||||
queryRunner,
|
|
||||||
subspace,
|
|
||||||
modifyDto.subspaceName,
|
|
||||||
);
|
|
||||||
return updatedSubspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
async update(
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
subspace: SubspaceEntity,
|
|
||||||
subspaceName?: string,
|
|
||||||
) {
|
|
||||||
return await this.updateSubspaceName(queryRunner, subspace, subspaceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleDeleteAction(
|
|
||||||
modifyDto: ModifySubspaceDto,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
): Promise<void> {
|
|
||||||
const subspace = await this.findOne(modifyDto.uuid);
|
|
||||||
|
|
||||||
await queryRunner.manager.update(
|
|
||||||
this.subspaceRepository.target,
|
|
||||||
{ uuid: subspace.uuid },
|
|
||||||
{ disabled: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
if (subspace.devices.length > 0) {
|
|
||||||
await this.deviceService.deleteSubspaceDevices(
|
|
||||||
subspace.devices,
|
|
||||||
queryRunner,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async findOne(subspaceUuid: string): Promise<SubspaceEntity> {
|
private async findOne(subspaceUuid: string): Promise<SubspaceEntity> {
|
||||||
const subspace = await this.subspaceRepository.findOne({
|
const subspace = await this.subspaceRepository.findOne({
|
||||||
where: { uuid: subspaceUuid, disabled: false },
|
where: { uuid: subspaceUuid, disabled: false },
|
||||||
relations: ['tags', 'space', 'devices', 'tags.product', 'tags.device'],
|
relations: ['space', 'devices'],
|
||||||
});
|
});
|
||||||
if (!subspace) {
|
if (!subspace) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
@ -501,36 +427,6 @@ export class SubSpaceService {
|
|||||||
return subspace;
|
return subspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateSubspaceName(
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
subSpace: SubspaceEntity,
|
|
||||||
subspaceName?: string,
|
|
||||||
): Promise<SubspaceEntity> {
|
|
||||||
if (subspaceName) {
|
|
||||||
subSpace.subspaceName = subspaceName;
|
|
||||||
return await queryRunner.manager.save(subSpace);
|
|
||||||
}
|
|
||||||
return subSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async checkForDuplicateNames(names: string[]): Promise<void> {
|
|
||||||
const seenNames = new Set<string>();
|
|
||||||
const duplicateNames = new Set<string>();
|
|
||||||
|
|
||||||
for (const name of names) {
|
|
||||||
if (!seenNames.add(name)) {
|
|
||||||
duplicateNames.add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duplicateNames.size > 0) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Duplicate subspace names found: ${[...duplicateNames].join(', ')}`,
|
|
||||||
HttpStatus.CONFLICT,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async checkExistingNamesInSpace(
|
private async checkExistingNamesInSpace(
|
||||||
names: string[],
|
names: string[],
|
||||||
space: SpaceEntity,
|
space: SpaceEntity,
|
||||||
@ -557,16 +453,6 @@ export class SubSpaceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async validateName(
|
|
||||||
names: string[],
|
|
||||||
space: SpaceEntity,
|
|
||||||
): Promise<void> {
|
|
||||||
await this.checkForDuplicateNames(names);
|
|
||||||
await this.checkExistingNamesInSpace(names, space);
|
|
||||||
}
|
|
||||||
extractTagsFromSubspace(addSubspaceDto: AddSubspaceDto[]): ProcessTagDto[] {
|
|
||||||
return addSubspaceDto.flatMap((subspace) => subspace.tags || []);
|
|
||||||
}
|
|
||||||
async clearSubspaces(subspaceUuids: string[], queryRunner: QueryRunner) {
|
async clearSubspaces(subspaceUuids: string[], queryRunner: QueryRunner) {
|
||||||
try {
|
try {
|
||||||
await queryRunner.manager.update(
|
await queryRunner.manager.update(
|
||||||
@ -590,4 +476,40 @@ export class SubSpaceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createAllocations(dto: CreateAllocationsDto): Promise<void> {
|
||||||
|
const { projectUuid, queryRunner, tags, type } = dto;
|
||||||
|
|
||||||
|
const allocationsData = await this.newTagService.processTags(
|
||||||
|
tags,
|
||||||
|
projectUuid,
|
||||||
|
queryRunner,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a mapping of created tags by UUID and name for quick lookup
|
||||||
|
const createdTagsByUUID = new Map(allocationsData.map((t) => [t.uuid, t]));
|
||||||
|
const createdTagsByName = new Map(allocationsData.map((t) => [t.name, t]));
|
||||||
|
|
||||||
|
// Create the product-tag mapping based on the processed tags
|
||||||
|
const productTagMapping = tags.map(({ uuid, name, productUuid }) => {
|
||||||
|
const inputTag = uuid
|
||||||
|
? createdTagsByUUID.get(uuid)
|
||||||
|
: createdTagsByName.get(name);
|
||||||
|
return {
|
||||||
|
tag: inputTag?.uuid,
|
||||||
|
product: productUuid,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case AllocationsOwnerType.SUBSPACE: {
|
||||||
|
await this.subspaceProductAllocationService.createProductAllocations(
|
||||||
|
dto.subspace,
|
||||||
|
productTagMapping,
|
||||||
|
queryRunner,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,597 +1,8 @@
|
|||||||
import { ModifyAction } from '@app/common/constants/modify-action.enum';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { TagRepository } from '@app/common/modules/space';
|
|
||||||
import { TagModel } from '@app/common/modules/space-model';
|
|
||||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
|
||||||
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
|
|
||||||
import { TagEntity } from '@app/common/modules/space/entities/tag.entity';
|
|
||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|
||||||
import { ProductService } from 'src/product/services';
|
|
||||||
import { ModifySubspaceDto } from 'src/space/dtos';
|
|
||||||
import { ModifyTagDto } from 'src/space/dtos/tag/modify-tag.dto';
|
|
||||||
import { ProcessTagDto } from 'src/tags/dtos';
|
|
||||||
import { QueryRunner } from 'typeorm';
|
|
||||||
|
|
||||||
|
// todo: find out why we need to import this
|
||||||
|
// in community module in order for the whole system to work
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TagService {
|
export class TagService {
|
||||||
constructor(
|
constructor() {}
|
||||||
private readonly tagRepository: TagRepository,
|
|
||||||
private readonly productService: ProductService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async createTags(
|
|
||||||
tags: ProcessTagDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
space?: SpaceEntity,
|
|
||||||
subspace?: SubspaceEntity,
|
|
||||||
additionalTags?: ProcessTagDto[],
|
|
||||||
tagsToDelete?: ModifyTagDto[],
|
|
||||||
): Promise<TagEntity[]> {
|
|
||||||
this.validateTagsInput(tags);
|
|
||||||
|
|
||||||
const combinedTags = this.combineTags(tags, additionalTags);
|
|
||||||
this.ensureNoDuplicateTags(combinedTags);
|
|
||||||
|
|
||||||
const tagEntitiesToCreate = tags.filter((tagDto) => !tagDto.uuid);
|
|
||||||
const tagEntitiesToUpdate = tags.filter((tagDto) => !!tagDto.uuid);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const createdTags = await this.bulkSaveTags(
|
|
||||||
tagEntitiesToCreate,
|
|
||||||
queryRunner,
|
|
||||||
space,
|
|
||||||
subspace,
|
|
||||||
tagsToDelete,
|
|
||||||
);
|
|
||||||
const updatedTags = await this.moveTags(
|
|
||||||
tagEntitiesToUpdate,
|
|
||||||
queryRunner,
|
|
||||||
space,
|
|
||||||
subspace,
|
|
||||||
);
|
|
||||||
|
|
||||||
return [...createdTags, ...updatedTags];
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleUnexpectedError('Failed to save tags', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async bulkSaveTags(
|
|
||||||
tags: ProcessTagDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
space?: SpaceEntity,
|
|
||||||
subspace?: SubspaceEntity,
|
|
||||||
tagsToDelete?: ModifyTagDto[],
|
|
||||||
): Promise<TagEntity[]> {
|
|
||||||
if (!tags.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagEntities = await Promise.all(
|
|
||||||
tags.map((tagDto) =>
|
|
||||||
this.prepareTagEntity(
|
|
||||||
tagDto,
|
|
||||||
queryRunner,
|
|
||||||
space,
|
|
||||||
subspace,
|
|
||||||
tagsToDelete,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await queryRunner.manager.save(tagEntities);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new HttpException(
|
|
||||||
`Failed to save tag models due to an unexpected error: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async moveTags(
|
|
||||||
tags: ProcessTagDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
space?: SpaceEntity,
|
|
||||||
subspace?: SubspaceEntity,
|
|
||||||
): Promise<TagEntity[]> {
|
|
||||||
if (!tags.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await Promise.all(
|
|
||||||
tags.map(async (tagDto) => {
|
|
||||||
try {
|
|
||||||
const tag = await this.getTagByUuid(tagDto.uuid);
|
|
||||||
if (!tag) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag with UUID ${tagDto.uuid} not found.`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subspace && subspace.space) {
|
|
||||||
await queryRunner.manager.update(
|
|
||||||
this.tagRepository.target,
|
|
||||||
{ uuid: tag.uuid },
|
|
||||||
{ subspace },
|
|
||||||
);
|
|
||||||
tag.subspace = subspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!subspace && space) {
|
|
||||||
await queryRunner.manager.update(
|
|
||||||
this.tagRepository.target,
|
|
||||||
{ uuid: tag.uuid },
|
|
||||||
{ subspace: null },
|
|
||||||
);
|
|
||||||
tag.subspace = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tag;
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Failed to move tags due to an unexpected error: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async createTagsFromModel(
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
tagModels: TagModel[],
|
|
||||||
space?: SpaceEntity,
|
|
||||||
subspace?: SubspaceEntity,
|
|
||||||
): Promise<void> {
|
|
||||||
if (!tagModels?.length) return;
|
|
||||||
|
|
||||||
const tags = tagModels.map((model) =>
|
|
||||||
queryRunner.manager.create(this.tagRepository.target, {
|
|
||||||
tag: model.tag,
|
|
||||||
space: space || undefined,
|
|
||||||
subspace: subspace || undefined,
|
|
||||||
product: model.product,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
await queryRunner.manager.save(tags);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateTag(
|
|
||||||
tag: ModifyTagDto,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
space?: SpaceEntity,
|
|
||||||
subspace?: SubspaceEntity,
|
|
||||||
): Promise<TagEntity> {
|
|
||||||
try {
|
|
||||||
const existingTag = await this.getTagByUuid(tag.tagUuid);
|
|
||||||
|
|
||||||
const contextSpace = space ?? subspace?.space;
|
|
||||||
|
|
||||||
if (contextSpace && tag.name !== existingTag.tag) {
|
|
||||||
await this.checkTagReuse(
|
|
||||||
tag.name,
|
|
||||||
existingTag.product.uuid,
|
|
||||||
contextSpace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await queryRunner.manager.save(
|
|
||||||
Object.assign(existingTag, { tag: tag.name }),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleUnexpectedError('Failed to update tags', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateTagsFromModel(
|
|
||||||
model: TagModel,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
|
||||||
const tags = await this.tagRepository.find({
|
|
||||||
where: {
|
|
||||||
model: {
|
|
||||||
uuid: model.uuid,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!tags.length) return;
|
|
||||||
|
|
||||||
await queryRunner.manager.update(
|
|
||||||
this.tagRepository.target,
|
|
||||||
{ model: { uuid: model.uuid } },
|
|
||||||
{ tag: model.tag },
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new HttpException(
|
|
||||||
`Failed to update tags for model with UUID: ${model.uuid}. Reason: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteTags(tagUuids: string[], queryRunner: QueryRunner) {
|
|
||||||
if (!tagUuids?.length) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await Promise.all(
|
|
||||||
tagUuids.map((id) =>
|
|
||||||
queryRunner.manager.update(
|
|
||||||
this.tagRepository.target,
|
|
||||||
{ uuid: id },
|
|
||||||
{ disabled: true, device: null },
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return { message: 'Tags deleted successfully', tagUuids };
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleUnexpectedError('Failed to delete tags', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteTagFromModel(modelUuid: string, queryRunner: QueryRunner) {
|
|
||||||
try {
|
|
||||||
const tags = await this.tagRepository.find({
|
|
||||||
where: {
|
|
||||||
model: {
|
|
||||||
uuid: modelUuid,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!tags.length) return;
|
|
||||||
|
|
||||||
await queryRunner.manager.update(
|
|
||||||
this.tagRepository.target,
|
|
||||||
{ model: { uuid: modelUuid } },
|
|
||||||
{ disabled: true, device: null },
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new HttpException(
|
|
||||||
`Failed to update tags for model with UUID: ${modelUuid}. Reason: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async modifyTags(
|
|
||||||
tags: ModifyTagDto[],
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
space?: SpaceEntity,
|
|
||||||
subspace?: SubspaceEntity,
|
|
||||||
): Promise<void> {
|
|
||||||
if (!tags?.length) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const tagsToDelete = tags.filter(
|
|
||||||
(tag) => tag.action === ModifyAction.DELETE,
|
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
tags.map(async (tag) => {
|
|
||||||
switch (tag.action) {
|
|
||||||
case ModifyAction.ADD:
|
|
||||||
await this.createTags(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
name: tag.name,
|
|
||||||
productUuid: tag.productUuid,
|
|
||||||
uuid: tag.tagUuid,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
queryRunner,
|
|
||||||
space,
|
|
||||||
subspace,
|
|
||||||
null,
|
|
||||||
tagsToDelete,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case ModifyAction.UPDATE:
|
|
||||||
await this.updateTag(tag, queryRunner, space, subspace);
|
|
||||||
break;
|
|
||||||
case ModifyAction.DELETE:
|
|
||||||
await this.deleteTags([tag.tagUuid], queryRunner);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new HttpException(
|
|
||||||
`Invalid action "${tag.action}" provided.`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleUnexpectedError('Failed to modify tags', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async unlinkModels(tags: TagEntity[], queryRunner: QueryRunner) {
|
|
||||||
if (!tags?.length) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
tags.forEach((tag) => {
|
|
||||||
tag.model = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
await queryRunner.manager.save(tags);
|
|
||||||
} catch (error) {
|
|
||||||
throw this.handleUnexpectedError('Failed to unlink tag models', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private findDuplicateTags(tags: ProcessTagDto[]): string[] {
|
|
||||||
const seen = new Map<string, boolean>();
|
|
||||||
const duplicates: string[] = [];
|
|
||||||
|
|
||||||
tags.forEach((tagDto) => {
|
|
||||||
const key = `${tagDto.productUuid}-${tagDto.name}`;
|
|
||||||
if (seen.has(key)) {
|
|
||||||
duplicates.push(`${tagDto.name} for Product: ${tagDto.productUuid}`);
|
|
||||||
} else {
|
|
||||||
seen.set(key, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return duplicates;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async checkTagReuse(
|
|
||||||
tag: string,
|
|
||||||
productUuid: string,
|
|
||||||
space: SpaceEntity,
|
|
||||||
tagsToDelete?: ModifyTagDto[],
|
|
||||||
): Promise<void> {
|
|
||||||
const { uuid: spaceUuid } = space;
|
|
||||||
|
|
||||||
const tagExists = await this.tagRepository.find({
|
|
||||||
where: [
|
|
||||||
{
|
|
||||||
tag,
|
|
||||||
product: { uuid: productUuid },
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tag,
|
|
||||||
subspace: { space: { uuid: spaceUuid } },
|
|
||||||
product: { uuid: productUuid },
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const filteredTagExists = tagExists.filter(
|
|
||||||
(existingTag) =>
|
|
||||||
!tagsToDelete?.some(
|
|
||||||
(deleteTag) => deleteTag.tagUuid === existingTag.uuid,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (filteredTagExists.length > 0) {
|
|
||||||
throw new HttpException(`Tag can't be reused`, HttpStatus.CONFLICT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async prepareTagEntity(
|
|
||||||
tagDto: ProcessTagDto,
|
|
||||||
queryRunner: QueryRunner,
|
|
||||||
space?: SpaceEntity,
|
|
||||||
subspace?: SubspaceEntity,
|
|
||||||
tagsToDelete?: ModifyTagDto[],
|
|
||||||
): Promise<TagEntity> {
|
|
||||||
try {
|
|
||||||
const product = await this.productService.findOne(tagDto.productUuid);
|
|
||||||
|
|
||||||
if (!product) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Product with UUID ${tagDto.productUuid} not found.`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (space) {
|
|
||||||
await this.checkTagReuse(
|
|
||||||
tagDto.name,
|
|
||||||
tagDto.productUuid,
|
|
||||||
space,
|
|
||||||
tagsToDelete,
|
|
||||||
);
|
|
||||||
} else if (subspace && subspace.space) {
|
|
||||||
await this.checkTagReuse(
|
|
||||||
tagDto.name,
|
|
||||||
tagDto.productUuid,
|
|
||||||
subspace.space,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw new HttpException(
|
|
||||||
`Invalid subspace or space provided.`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return queryRunner.manager.create(TagEntity, {
|
|
||||||
tag: tagDto.name,
|
|
||||||
product: product.data,
|
|
||||||
space: space,
|
|
||||||
subspace: subspace,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HttpException) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
throw new HttpException(
|
|
||||||
`An error occurred while preparing the tag entity: ${error.message}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getTagByUuid(uuid: string): Promise<TagEntity> {
|
|
||||||
const tag = await this.tagRepository.findOne({
|
|
||||||
where: { uuid },
|
|
||||||
relations: ['product'],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!tag) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag with ID ${uuid} not found.`,
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleUnexpectedError(
|
|
||||||
message: string,
|
|
||||||
error: unknown,
|
|
||||||
): HttpException {
|
|
||||||
if (error instanceof HttpException) throw error;
|
|
||||||
return new HttpException(
|
|
||||||
`${message}: ${(error as Error)?.message || 'Unknown error'}`,
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private combineTags(
|
|
||||||
primaryTags: ProcessTagDto[],
|
|
||||||
additionalTags?: ProcessTagDto[],
|
|
||||||
): ProcessTagDto[] {
|
|
||||||
return additionalTags ? [...primaryTags, ...additionalTags] : primaryTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ensureNoDuplicateTags(tags: ProcessTagDto[]): void {
|
|
||||||
const duplicates = this.findDuplicateTags(tags);
|
|
||||||
|
|
||||||
if (duplicates.length > 0) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Duplicate tags found: ${duplicates.join(', ')}`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private validateTagsInput(tags: ProcessTagDto[]): void {
|
|
||||||
if (!tags?.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getSubspaceTagsToBeAdded(
|
|
||||||
spaceTags?: ModifyTagDto[],
|
|
||||||
subspaceModels?: ModifySubspaceDto[],
|
|
||||||
): ModifyTagDto[] {
|
|
||||||
if (!subspaceModels || subspaceModels.length === 0) {
|
|
||||||
return spaceTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spaceTagsToDelete = spaceTags?.filter(
|
|
||||||
(tag) => tag.action === 'delete',
|
|
||||||
);
|
|
||||||
|
|
||||||
const tagsToAdd = subspaceModels.flatMap(
|
|
||||||
(subspace) => subspace.tags?.filter((tag) => tag.action === 'add') || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
const commonTagUuids = new Set(
|
|
||||||
tagsToAdd
|
|
||||||
.filter((tagToAdd) =>
|
|
||||||
spaceTagsToDelete.some(
|
|
||||||
(tagToDelete) => tagToAdd.tagUuid === tagToDelete.tagUuid,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map((tag) => tag.tagUuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
const remainingTags = spaceTags.filter(
|
|
||||||
(tag) => !commonTagUuids.has(tag.tagUuid), // Exclude tags in commonTagUuids
|
|
||||||
);
|
|
||||||
|
|
||||||
return remainingTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
getModifiedSubspaces(
|
|
||||||
spaceTags?: ModifyTagDto[],
|
|
||||||
subspaceModels?: ModifySubspaceDto[],
|
|
||||||
): ModifySubspaceDto[] {
|
|
||||||
if (!subspaceModels || subspaceModels.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract tags marked for addition in spaceTags
|
|
||||||
const spaceTagsToAdd = spaceTags?.filter((tag) => tag.action === 'add');
|
|
||||||
|
|
||||||
const subspaceTagsToAdd = subspaceModels.flatMap(
|
|
||||||
(subspace) => subspace.tags?.filter((tag) => tag.action === 'add') || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
const subspaceTagsToDelete = subspaceModels.flatMap(
|
|
||||||
(subspace) =>
|
|
||||||
subspace.tags?.filter((tag) => tag.action === 'delete') || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
const subspaceTagsToDeleteUuids = new Set(
|
|
||||||
subspaceTagsToDelete.map((tag) => tag.tagUuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
const commonTagsInSubspaces = subspaceTagsToAdd.filter((tag) =>
|
|
||||||
subspaceTagsToDeleteUuids.has(tag.tagUuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find UUIDs of tags that are common between spaceTagsToAdd and subspace tags marked for deletion
|
|
||||||
const commonTagUuids = new Set(
|
|
||||||
spaceTagsToAdd
|
|
||||||
.flatMap((tagToAdd) =>
|
|
||||||
subspaceModels.flatMap(
|
|
||||||
(subspace) =>
|
|
||||||
subspace.tags?.filter(
|
|
||||||
(tagToDelete) =>
|
|
||||||
tagToDelete.action === 'delete' &&
|
|
||||||
tagToAdd.tagUuid === tagToDelete.tagUuid,
|
|
||||||
) || [],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map((tag) => tag.tagUuid),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Modify subspaceModels by removing tags with UUIDs present in commonTagUuids
|
|
||||||
let modifiedSubspaces = subspaceModels.map((subspace) => ({
|
|
||||||
...subspace,
|
|
||||||
tags:
|
|
||||||
subspace.tags?.filter((tag) => !commonTagUuids.has(tag.tagUuid)) || [],
|
|
||||||
}));
|
|
||||||
|
|
||||||
modifiedSubspaces = modifiedSubspaces.map((subspace) => ({
|
|
||||||
...subspace,
|
|
||||||
tags:
|
|
||||||
subspace.tags?.filter(
|
|
||||||
(tag) =>
|
|
||||||
!(
|
|
||||||
tag.action === 'delete' &&
|
|
||||||
commonTagsInSubspaces.some(
|
|
||||||
(commonTag) => commonTag.tagUuid === tag.tagUuid,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
) || [],
|
|
||||||
}));
|
|
||||||
|
|
||||||
return modifiedSubspaces;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,82 @@
|
|||||||
|
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
||||||
|
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
||||||
|
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||||
|
import {
|
||||||
|
InviteUserRepository,
|
||||||
|
InviteUserSpaceRepository,
|
||||||
|
} from '@app/common/modules/Invite-user/repositiories';
|
||||||
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
|
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
||||||
|
import {
|
||||||
|
DeviceRepository,
|
||||||
|
DeviceUserPermissionRepository,
|
||||||
|
} from '@app/common/modules/device/repositories';
|
||||||
|
import { PermissionTypeRepository } from '@app/common/modules/permission/repositories';
|
||||||
|
import {
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||||
|
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||||
|
import {
|
||||||
|
SceneIconRepository,
|
||||||
|
SceneRepository,
|
||||||
|
} from '@app/common/modules/scene/repositories';
|
||||||
|
import {
|
||||||
|
SpaceModelProductAllocationRepoitory,
|
||||||
|
SpaceModelRepository,
|
||||||
|
SubspaceModelProductAllocationRepoitory,
|
||||||
|
SubspaceModelRepository,
|
||||||
|
} from '@app/common/modules/space-model';
|
||||||
|
import {
|
||||||
|
InviteSpaceRepository,
|
||||||
|
SpaceLinkRepository,
|
||||||
|
SpaceProductAllocationRepository,
|
||||||
|
SpaceRepository,
|
||||||
|
} from '@app/common/modules/space/repositories';
|
||||||
|
import {
|
||||||
|
SubspaceProductAllocationRepository,
|
||||||
|
SubspaceRepository,
|
||||||
|
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
import { SpaceRepositoryModule } from '@app/common/modules/space/space.repository.module';
|
import { SpaceRepositoryModule } from '@app/common/modules/space/space.repository.module';
|
||||||
|
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
||||||
|
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||||
|
import {
|
||||||
|
UserRepository,
|
||||||
|
UserSpaceRepository,
|
||||||
|
} from '@app/common/modules/user/repositories';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { CqrsModule } from '@nestjs/cqrs';
|
||||||
|
import { CommunityModule } from 'src/community/community.module';
|
||||||
|
import { DeviceService } from 'src/device/services';
|
||||||
|
import {
|
||||||
|
SpaceModelService,
|
||||||
|
SubSpaceModelService,
|
||||||
|
} from 'src/space-model/services';
|
||||||
|
import { SpaceModelProductAllocationService } from 'src/space-model/services/space-model-product-allocation.service';
|
||||||
|
import { SubspaceModelProductAllocationService } from 'src/space-model/services/subspace/subspace-model-product-allocation.service';
|
||||||
|
import { TagService as NewTagService } from 'src/tags/services/tags.service';
|
||||||
|
import { UserDevicePermissionService } from 'src/user-device-permission/services';
|
||||||
|
import { UserService, UserSpaceService } from 'src/users/services';
|
||||||
|
import { SceneService } from '../scene/services';
|
||||||
import {
|
import {
|
||||||
SpaceController,
|
SpaceController,
|
||||||
SpaceDeviceController,
|
SpaceDeviceController,
|
||||||
|
SpaceSceneController,
|
||||||
SpaceUserController,
|
SpaceUserController,
|
||||||
SubSpaceController,
|
SubSpaceController,
|
||||||
SubSpaceDeviceController,
|
SubSpaceDeviceController,
|
||||||
SpaceSceneController,
|
|
||||||
} from './controllers';
|
} from './controllers';
|
||||||
|
import { SpaceValidationController } from './controllers/space-validation.controller';
|
||||||
|
import { DisableSpaceHandler } from './handlers';
|
||||||
import {
|
import {
|
||||||
SpaceDeviceService,
|
SpaceDeviceService,
|
||||||
SpaceLinkService,
|
SpaceLinkService,
|
||||||
@ -17,81 +85,10 @@ import {
|
|||||||
SpaceUserService,
|
SpaceUserService,
|
||||||
SubspaceDeviceService,
|
SubspaceDeviceService,
|
||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
|
ValidationService,
|
||||||
} from './services';
|
} from './services';
|
||||||
import {
|
|
||||||
SpaceRepository,
|
|
||||||
SpaceLinkRepository,
|
|
||||||
TagRepository,
|
|
||||||
InviteSpaceRepository,
|
|
||||||
SpaceProductAllocationRepository,
|
|
||||||
} from '@app/common/modules/space/repositories';
|
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
|
||||||
import {
|
|
||||||
UserRepository,
|
|
||||||
UserSpaceRepository,
|
|
||||||
} from '@app/common/modules/user/repositories';
|
|
||||||
import {
|
|
||||||
DeviceRepository,
|
|
||||||
DeviceUserPermissionRepository,
|
|
||||||
} from '@app/common/modules/device/repositories';
|
|
||||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
|
||||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
|
||||||
import { SceneService } from '../scene/services';
|
|
||||||
import {
|
|
||||||
SceneIconRepository,
|
|
||||||
SceneRepository,
|
|
||||||
} from '@app/common/modules/scene/repositories';
|
|
||||||
import { DeviceService } from 'src/device/services';
|
|
||||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
|
||||||
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
|
||||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|
||||||
import {
|
|
||||||
SpaceModelProductAllocationRepoitory,
|
|
||||||
SpaceModelRepository,
|
|
||||||
SubspaceModelProductAllocationRepoitory,
|
|
||||||
SubspaceModelRepository,
|
|
||||||
TagModelRepository,
|
|
||||||
} from '@app/common/modules/space-model';
|
|
||||||
import { CommunityModule } from 'src/community/community.module';
|
|
||||||
import { ValidationService } from './services';
|
|
||||||
import {
|
|
||||||
SubspaceProductAllocationRepository,
|
|
||||||
SubspaceRepository,
|
|
||||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
|
||||||
import { TagService } from './services/tag';
|
|
||||||
import {
|
|
||||||
SpaceModelService,
|
|
||||||
SubSpaceModelService,
|
|
||||||
} from 'src/space-model/services';
|
|
||||||
import { UserService, UserSpaceService } from 'src/users/services';
|
|
||||||
import { UserDevicePermissionService } from 'src/user-device-permission/services';
|
|
||||||
import { PermissionTypeRepository } from '@app/common/modules/permission/repositories';
|
|
||||||
import { CqrsModule } from '@nestjs/cqrs';
|
|
||||||
import { DisableSpaceHandler } from './handlers';
|
|
||||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
|
||||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
|
||||||
import {
|
|
||||||
InviteUserRepository,
|
|
||||||
InviteUserSpaceRepository,
|
|
||||||
} from '@app/common/modules/Invite-user/repositiories';
|
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
|
||||||
import { TagService as NewTagService } from 'src/tags/services/tags.service';
|
|
||||||
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
|
||||||
import { SpaceModelProductAllocationService } from 'src/space-model/services/space-model-product-allocation.service';
|
|
||||||
import { SubspaceModelProductAllocationService } from 'src/space-model/services/subspace/subspace-model-product-allocation.service';
|
|
||||||
import { SpaceProductAllocationService } from './services/space-product-allocation.service';
|
import { SpaceProductAllocationService } from './services/space-product-allocation.service';
|
||||||
import { SubspaceProductAllocationService } from './services/subspace/subspace-product-allocation.service';
|
import { SubspaceProductAllocationService } from './services/subspace/subspace-product-allocation.service';
|
||||||
import { SpaceValidationController } from './controllers/space-validation.controller';
|
|
||||||
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
|
||||||
import {
|
|
||||||
PowerClampHourlyRepository,
|
|
||||||
PowerClampDailyRepository,
|
|
||||||
PowerClampMonthlyRepository,
|
|
||||||
} from '@app/common/modules/power-clamp/repositories';
|
|
||||||
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
|
||||||
import { OccupancyService } from '@app/common/helper/services/occupancy.service';
|
|
||||||
import { AqiDataService } from '@app/common/helper/services/aqi.data.service';
|
|
||||||
|
|
||||||
export const CommandHandlers = [DisableSpaceHandler];
|
export const CommandHandlers = [DisableSpaceHandler];
|
||||||
|
|
||||||
@ -108,11 +105,8 @@ export const CommandHandlers = [DisableSpaceHandler];
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ValidationService,
|
ValidationService,
|
||||||
TagModelRepository,
|
|
||||||
TagRepository,
|
|
||||||
SpaceService,
|
SpaceService,
|
||||||
TuyaService,
|
TuyaService,
|
||||||
TagService,
|
|
||||||
ProductRepository,
|
ProductRepository,
|
||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
SpaceDeviceService,
|
SpaceDeviceService,
|
||||||
@ -152,7 +146,6 @@ export const CommandHandlers = [DisableSpaceHandler];
|
|||||||
InviteUserRepository,
|
InviteUserRepository,
|
||||||
InviteUserSpaceRepository,
|
InviteUserSpaceRepository,
|
||||||
AutomationRepository,
|
AutomationRepository,
|
||||||
TagService,
|
|
||||||
NewTagService,
|
NewTagService,
|
||||||
SpaceModelProductAllocationRepoitory,
|
SpaceModelProductAllocationRepoitory,
|
||||||
SubspaceModelProductAllocationRepoitory,
|
SubspaceModelProductAllocationRepoitory,
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { ProjectParam } from '@app/common/dto/project-param.dto';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
import { ProductEntity } from '@app/common/modules/product/entities';
|
||||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
|
import { ProjectEntity } from '@app/common/modules/project/entities';
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { NewTagEntity } from '@app/common/modules/tag';
|
||||||
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
import { NewTagRepository } from '@app/common/modules/tag/repositories/tag-repository';
|
||||||
import {
|
import {
|
||||||
Injectable,
|
|
||||||
ConflictException,
|
ConflictException,
|
||||||
NotFoundException,
|
|
||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
|
Injectable,
|
||||||
|
NotFoundException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { CreateTagDto } from '../dtos/tags.dto';
|
|
||||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
|
||||||
import { ProjectEntity } from '@app/common/modules/project/entities';
|
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
|
||||||
import { NewTagEntity } from '@app/common/modules/tag';
|
|
||||||
import { BulkCreateTagsDto, ProcessTagDto } from '../dtos';
|
|
||||||
import { In, QueryRunner } from 'typeorm';
|
import { In, QueryRunner } from 'typeorm';
|
||||||
import { ProjectParam } from '@app/common/dto/project-param.dto';
|
import { ProcessTagDto } from '../dtos';
|
||||||
|
import { CreateTagDto } from '../dtos/tags.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TagService {
|
export class TagService {
|
||||||
@ -32,7 +32,7 @@ export class TagService {
|
|||||||
|
|
||||||
const tags = await this.tagRepository.find({
|
const tags = await this.tagRepository.find({
|
||||||
where: { project: { uuid: projectUuid } },
|
where: { project: { uuid: projectUuid } },
|
||||||
relations: ['product', 'project'],
|
relations: ['project'],
|
||||||
});
|
});
|
||||||
|
|
||||||
return new SuccessResponseDto({
|
return new SuccessResponseDto({
|
||||||
@ -66,74 +66,65 @@ export class TagService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes an array of tag DTOs, creating or updating tags in the database.
|
||||||
|
* @param tagDtos - The array of tag DTOs to process.
|
||||||
|
* @param projectUuid - The UUID of the project to associate the tags with.
|
||||||
|
* @param queryRunner - Optional TypeORM query runner for transaction management.
|
||||||
|
* @returns An array of the processed tag entities.
|
||||||
|
*/
|
||||||
async processTags(
|
async processTags(
|
||||||
tagDtos: ProcessTagDto[],
|
tagDtos: ProcessTagDto[],
|
||||||
projectUuid: string,
|
projectUuid: string,
|
||||||
queryRunner?: QueryRunner,
|
queryRunner?: QueryRunner,
|
||||||
): Promise<NewTagEntity[]> {
|
): Promise<NewTagEntity[]> {
|
||||||
try {
|
try {
|
||||||
|
const dbManager = queryRunner
|
||||||
|
? queryRunner.manager
|
||||||
|
: this.tagRepository.manager;
|
||||||
if (!tagDtos || tagDtos.length === 0) {
|
if (!tagDtos || tagDtos.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const newTagDtos: CreateTagDto[] = [];
|
const [tagsWithUuid, tagsWithoutUuid]: [
|
||||||
const existingTagUuids: string[] = [];
|
Pick<ProcessTagDto, 'uuid' | 'productUuid'>[],
|
||||||
let fetchedExistingTags: NewTagEntity[] = [];
|
Omit<ProcessTagDto, 'uuid'>[],
|
||||||
const directlyFetchedTags: NewTagEntity[] = [];
|
] = this.splitTagsByUuid(tagDtos);
|
||||||
|
|
||||||
// Separate existing tag UUIDs and new tag DTOs
|
// create a set of unique existing tag names for the project
|
||||||
for (const tagDto of tagDtos) {
|
const upsertedTagsByNameResult = await dbManager.upsert(
|
||||||
if (tagDto.uuid) {
|
NewTagEntity,
|
||||||
existingTagUuids.push(tagDto.uuid);
|
Array.from(
|
||||||
} else {
|
new Set<string>(tagsWithoutUuid.map((tag) => tag.name)).values(),
|
||||||
if (!tagDto.name || !tagDto.productUuid) {
|
).map((name) => ({
|
||||||
throw new HttpException(
|
name,
|
||||||
`Tag name or product UUID is missing`,
|
|
||||||
HttpStatus.BAD_REQUEST,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const existingTag = await queryRunner.manager.findOne(NewTagEntity, {
|
|
||||||
where: {
|
|
||||||
name: tagDto.name,
|
|
||||||
product: { uuid: tagDto.productUuid },
|
|
||||||
project: { uuid: projectUuid },
|
project: { uuid: projectUuid },
|
||||||
|
})),
|
||||||
|
['name', 'project'],
|
||||||
|
);
|
||||||
|
|
||||||
|
const createdTagsByName = await dbManager.find(NewTagEntity, {
|
||||||
|
where: {
|
||||||
|
uuid: In(upsertedTagsByNameResult.identifiers.map((id) => id.uuid)),
|
||||||
},
|
},
|
||||||
relations: ['product'],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!existingTag) {
|
let foundByUuidTags: NewTagEntity[] = [];
|
||||||
newTagDtos.push(tagDto);
|
|
||||||
} else {
|
|
||||||
directlyFetchedTags.push(existingTag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch existing tags using UUIDs
|
// Fetch existing tags using UUIDs
|
||||||
if (existingTagUuids.length > 0) {
|
if (tagsWithUuid.length) {
|
||||||
fetchedExistingTags = await (queryRunner
|
foundByUuidTags = await dbManager.find(NewTagEntity, {
|
||||||
? queryRunner.manager.find(NewTagEntity, {
|
|
||||||
where: {
|
where: {
|
||||||
uuid: In(existingTagUuids),
|
uuid: In([...tagsWithUuid.map((tag) => tag.uuid)]),
|
||||||
project: { uuid: projectUuid },
|
project: { uuid: projectUuid },
|
||||||
},
|
},
|
||||||
relations: ['product'],
|
});
|
||||||
})
|
|
||||||
: this.tagRepository.find({
|
|
||||||
where: {
|
|
||||||
uuid: In(existingTagUuids),
|
|
||||||
project: { uuid: projectUuid },
|
|
||||||
},
|
|
||||||
relations: ['product'],
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure all provided UUIDs exist in the database
|
// Ensure all provided UUIDs exist in the database
|
||||||
if (fetchedExistingTags.length !== existingTagUuids.length) {
|
if (foundByUuidTags.length !== tagsWithUuid.length) {
|
||||||
const foundUuids = new Set(fetchedExistingTags.map((tag) => tag.uuid));
|
const foundUuids = new Set(foundByUuidTags.map((tag) => tag.uuid));
|
||||||
const missingUuids = existingTagUuids.filter(
|
const missingUuids = tagsWithUuid.filter(
|
||||||
(uuid) => !foundUuids.has(uuid),
|
({ uuid }) => !foundUuids.has(uuid),
|
||||||
);
|
);
|
||||||
|
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
@ -142,23 +133,7 @@ export class TagService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let newlyCreatedTags: NewTagEntity[] = [];
|
return [...foundByUuidTags, ...createdTagsByName];
|
||||||
|
|
||||||
if (newTagDtos.length > 0) {
|
|
||||||
newlyCreatedTags = await this.bulkCreateTags(
|
|
||||||
{ projectUuid, tags: newTagDtos },
|
|
||||||
queryRunner,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine all found and created tags
|
|
||||||
const allTags = [
|
|
||||||
...fetchedExistingTags,
|
|
||||||
...newlyCreatedTags,
|
|
||||||
...directlyFetchedTags,
|
|
||||||
];
|
|
||||||
|
|
||||||
return allTags;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
@ -172,79 +147,6 @@ export class TagService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async bulkCreateTags(
|
|
||||||
dto: BulkCreateTagsDto,
|
|
||||||
queryRunner?: QueryRunner,
|
|
||||||
): Promise<NewTagEntity[]> {
|
|
||||||
try {
|
|
||||||
const { projectUuid, tags } = dto;
|
|
||||||
const newTags: NewTagEntity[] = [];
|
|
||||||
|
|
||||||
const project = await this.getProjectByUuid(projectUuid);
|
|
||||||
|
|
||||||
// Extract unique product UUIDs
|
|
||||||
const productUuids = Array.from(
|
|
||||||
new Set(tags.map((tag) => tag.productUuid)),
|
|
||||||
);
|
|
||||||
|
|
||||||
const productMap = await this.getProductMap(productUuids);
|
|
||||||
|
|
||||||
// Fetch existing tag names for this project
|
|
||||||
const existingTags = await this.tagRepository.find({
|
|
||||||
where: { project: { uuid: projectUuid } },
|
|
||||||
relations: ['product'],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Convert existing tags into a Map for quick lookup
|
|
||||||
const existingTagMap = new Map<string, string | null>();
|
|
||||||
existingTags.forEach((tag) => {
|
|
||||||
existingTagMap.set(tag.name, tag.product?.uuid || null);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const tag of tags) {
|
|
||||||
const existingProductUuid = existingTagMap.get(tag.name);
|
|
||||||
|
|
||||||
if (existingProductUuid) {
|
|
||||||
if (existingProductUuid !== tag.productUuid) {
|
|
||||||
throw new HttpException(
|
|
||||||
`Tag "${tag.name}" already exists but is associated with a different product.`,
|
|
||||||
HttpStatus.CONFLICT,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newTags.push(
|
|
||||||
this.tagRepository.create({
|
|
||||||
name: tag.name,
|
|
||||||
product: productMap.get(tag.productUuid),
|
|
||||||
project,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newTags.length > 0) {
|
|
||||||
if (queryRunner) {
|
|
||||||
await queryRunner.manager.save(NewTagEntity, newTags);
|
|
||||||
} else {
|
|
||||||
await this.tagRepository.save(newTags);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
|
|
||||||
return newTags;
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
throw new HttpException(
|
|
||||||
error instanceof HttpException
|
|
||||||
? error.message
|
|
||||||
: 'An unexpected error occurred while creating tags',
|
|
||||||
error instanceof HttpException
|
|
||||||
? error.getStatus()
|
|
||||||
: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getProductByUuid(uuid: string): Promise<ProductEntity> {
|
private async getProductByUuid(uuid: string): Promise<ProductEntity> {
|
||||||
const product = await this.productRepository.findOne({ where: { uuid } });
|
const product = await this.productRepository.findOne({ where: { uuid } });
|
||||||
if (!product) {
|
if (!product) {
|
||||||
@ -276,30 +178,25 @@ export class TagService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getProductMap(
|
private splitTagsByUuid(
|
||||||
uuids: string[],
|
tagDtos: ProcessTagDto[],
|
||||||
): Promise<Map<string, ProductEntity>> {
|
): [ProcessTagDto[], ProcessTagDto[]] {
|
||||||
const products = await this.productRepository.find({
|
return tagDtos.reduce<[ProcessTagDto[], ProcessTagDto[]]>(
|
||||||
where: { uuid: In(uuids) },
|
([withUuid, withoutUuid], tag) => {
|
||||||
});
|
if (tag.uuid) {
|
||||||
|
withUuid.push(tag);
|
||||||
if (products.length !== uuids.length) {
|
} else {
|
||||||
const foundUuids = new Set(products.map((p) => p.uuid));
|
if (!tag.name || !tag.productUuid) {
|
||||||
const missingUuids = uuids.filter((id) => !foundUuids.has(id));
|
throw new HttpException(
|
||||||
throw new NotFoundException(
|
`Tag name or product UUID is missing`,
|
||||||
`Products not found for UUIDs: ${missingUuids.join(', ')}`,
|
HttpStatus.BAD_REQUEST,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
withoutUuid.push(tag);
|
||||||
return new Map(products.map((product) => [product.uuid, product]));
|
|
||||||
}
|
}
|
||||||
|
return [withUuid, withoutUuid];
|
||||||
private async getExistingTagNames(projectUuid: string): Promise<Set<string>> {
|
},
|
||||||
const tags = await this.tagRepository.find({
|
[[], []],
|
||||||
where: { project: { uuid: projectUuid } },
|
);
|
||||||
select: ['name'],
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Set(tags.map((tag) => tag.name));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user