diff --git a/src/entities/dto/list-all-entities.dto.ts b/src/entities/dto/list-all-entities.dto.ts index d5f1cff7..5d9f7956 100644 --- a/src/entities/dto/list-all-entities.dto.ts +++ b/src/entities/dto/list-all-entities.dto.ts @@ -30,5 +30,12 @@ export class ListAllEntitiesDto { | "active" | "groupName" | "rssi" - | "snr"; + | "snr" + | "status" + | "startDate" + | "endDate" + | "owner" + | "contactPerson" + | "personalData" + | "openDataDkEnabled"; } diff --git a/src/services/device-management/application.service.ts b/src/services/device-management/application.service.ts index ed7152d2..7aff9754 100644 --- a/src/services/device-management/application.service.ts +++ b/src/services/device-management/application.service.ts @@ -12,11 +12,7 @@ import { ControlledProperty } from "@entities/controlled-property.entity"; import { IoTDevice } from "@entities/iot-device.entity"; import { LoRaWANDevice } from "@entities/lorawan-device.entity"; import { ControlledPropertyTypes } from "@enum/controlled-property.enum"; -import { - ApplicationDeviceTypes, - ApplicationDeviceTypeUnion, - IoTDeviceType, -} from "@enum/device-type.enum"; +import { ApplicationDeviceTypes, ApplicationDeviceTypeUnion, IoTDeviceType } from "@enum/device-type.enum"; import { ErrorCodes } from "@enum/error-codes.enum"; import { findValuesInRecord } from "@helpers/record.helper"; import { nameof } from "@helpers/type-helper"; @@ -28,6 +24,7 @@ import { PermissionService } from "@services/user-management/permission.service" import { DeleteResult, In, Repository } from "typeorm"; import { MulticastService } from "./multicast.service"; import { DataTargetService } from "@services/data-targets/data-target.service"; +import { DataTargetType } from "@enum/data-target-type.enum"; @Injectable() export class ApplicationService { @@ -53,9 +50,7 @@ export class ApplicationService { ): Promise { const sorting = this.getSortingForApplications(query); const orgCondition = - allFromOrgs != null - ? { id: In(whitelist), belongsTo: In(allFromOrgs) } - : { id: In(whitelist) }; + allFromOrgs != null ? { id: In(whitelist), belongsTo: In(allFromOrgs) } : { id: In(whitelist) }; const [result, total] = await this.applicationRepository.findAndCount({ where: orgCondition, take: query.limit, @@ -98,16 +93,23 @@ export class ApplicationService { ): Promise { const sorting = this.getSortingForApplications(query); const [result, total] = await this.applicationRepository.findAndCount({ - where: - allowedOrganisations != null - ? { belongsTo: In(allowedOrganisations) } - : {}, + where: allowedOrganisations != null ? { belongsTo: In(allowedOrganisations) } : {}, take: +query.limit, skip: +query.offset, - relations: ["iotDevices"], + relations: ["iotDevices", "dataTargets", "controlledProperties", "deviceTypes"], order: sorting, }); + // Since openDataDkEnabled is not a database attribute sorting has to be done manually after reading + if (query.orderOn === "openDataDkEnabled") { + result.sort( + (a, b) => + (query.sort.toLowerCase() === "asc" ? -1 : 1) * + (Number(!!a.dataTargets.find(t => t.type === DataTargetType.OpenDataDK)) - + Number(!!b.dataTargets.find(t => t.type === DataTargetType.OpenDataDK))) + ); + } + return { data: result, count: total, @@ -121,14 +123,11 @@ export class ApplicationService { let orderBy = `application.id`; if ( query.orderOn != null && - (query.orderOn == "id" || - query.orderOn == "name" || - query.orderOn == "updatedAt") + (query.orderOn === "id" || query.orderOn === "name" || query.orderOn === "updatedAt") ) { orderBy = `application.${query.orderOn}`; } - const order: "DESC" | "ASC" = - query?.sort?.toLocaleUpperCase() == "DESC" ? "DESC" : "ASC"; + const order: "DESC" | "ASC" = query?.sort?.toLocaleUpperCase() === "DESC" ? "DESC" : "ASC"; const [result, total] = await this.applicationRepository .createQueryBuilder("application") .innerJoin("application.permissions", "perm") @@ -180,7 +179,7 @@ export class ApplicationService { relations: ["createdBy", "updatedBy"], }, }); - if (app.iotDevices.some(x => x.type == IoTDeviceType.LoRaWAN)) { + if (app.iotDevices.some(x => x.type === IoTDeviceType.LoRaWAN)) { await this.matchWithChirpstackStatusData(app); } @@ -190,40 +189,29 @@ export class ApplicationService { private async matchWithChirpstackStatusData(app: Application) { const allFromChirpstack = await this.chirpstackDeviceService.getAllDevicesStatus(); app.iotDevices.forEach(x => { - if (x.type == IoTDeviceType.LoRaWAN) { + if (x.type === IoTDeviceType.LoRaWAN) { const loraDevice = x as LoRaWANDeviceWithChirpstackDataDto; - const matchingDevice = allFromChirpstack.result.find( - cs => cs.devEUI == loraDevice.deviceEUI - ); + const matchingDevice = allFromChirpstack.result.find(cs => cs.devEUI === loraDevice.deviceEUI); if (matchingDevice) { loraDevice.lorawanSettings = new CreateLoRaWANSettingsDto(); - loraDevice.lorawanSettings.deviceStatusBattery = - matchingDevice.deviceStatusBattery; - loraDevice.lorawanSettings.deviceStatusMargin = - matchingDevice.deviceStatusMargin; + loraDevice.lorawanSettings.deviceStatusBattery = matchingDevice.deviceStatusBattery; + loraDevice.lorawanSettings.deviceStatusMargin = matchingDevice.deviceStatusMargin; } } }); } async findManyByIds(ids: number[]): Promise { - if (ids == null || ids?.length == 0) { + if (ids === null || ids?.length === 0) { return []; } return await this.applicationRepository.findBy({ id: In(ids) }); } - async create( - createApplicationDto: CreateApplicationDto, - userId: number - ): Promise { + async create(createApplicationDto: CreateApplicationDto, userId: number): Promise { const application = new Application(); - const mappedApplication = await this.mapApplicationDtoToApplication( - createApplicationDto, - application, - userId - ); + const mappedApplication = await this.mapApplicationDtoToApplication(createApplicationDto, application, userId); mappedApplication.iotDevices = []; mappedApplication.dataTargets = []; mappedApplication.multicasts = []; @@ -237,11 +225,7 @@ export class ApplicationService { return app; } - async update( - id: number, - updateApplicationDto: UpdateApplicationDto, - userId: number - ): Promise { + async update(id: number, updateApplicationDto: UpdateApplicationDto, userId: number): Promise { const existingApplication = await this.applicationRepository.findOneOrFail({ where: { id }, relations: [ @@ -271,7 +255,7 @@ export class ApplicationService { // Don't allow delete if this application contains any sigfox devices. if ( application.iotDevices.some(iotDevice => { - return iotDevice.type == IoTDeviceType.SigFox; + return iotDevice.type === IoTDeviceType.SigFox; }) ) { throw new ConflictException(ErrorCodes.DeleteNotAllowedHasSigfoxDevice); @@ -282,9 +266,7 @@ export class ApplicationService { } // Delete all LoRaWAN devices in ChirpStack - const loRaWANDevices = application.iotDevices.filter( - device => device.type === IoTDeviceType.LoRaWAN - ); + const loRaWANDevices = application.iotDevices.filter(device => device.type === IoTDeviceType.LoRaWAN); for (const device of loRaWANDevices) { const lwDevice = device as LoRaWANDevice; @@ -312,10 +294,10 @@ export class ApplicationService { if (id) { // If id is given then this id is allowed to have the name already (i.e. it's being changed) return applicationsWithName.every(app => { - return app.id == id; + return app.id === id; }); } else { - return applicationsWithName.length == 0; + return applicationsWithName.length === 0; } } @@ -329,9 +311,7 @@ export class ApplicationService { ): Promise { application.name = applicationDto.name; application.description = applicationDto.description; - application.belongsTo = await this.organizationService.findById( - applicationDto.organizationId - ); + application.belongsTo = await this.organizationService.findById(applicationDto.organizationId); application.status = applicationDto.status; // Setting a date to 'undefined' will set it to today in the database application.startDate = applicationDto.startDate ?? null; @@ -343,9 +323,7 @@ export class ApplicationService { application.contactPhone = applicationDto.contactPhone; application.personalData = applicationDto.personalData; application.hardware = applicationDto.hardware; - application.permissions = await this.permissionService.findManyByIds( - applicationDto.permissionIds - ); + application.permissions = await this.permissionService.findManyByIds(applicationDto.permissionIds); // Set metadata dependencies application.controlledProperties = applicationDto.controlledProperties @@ -371,12 +349,7 @@ export class ApplicationService { buildControlledPropertyDeviceType< T extends Record, Entity extends ControlledProperty | ApplicationDeviceType - >( - validKeys: T, - clientTypes: string[], - userId: number, - entity: { new (): Entity } - ): Entity[] { + >(validKeys: T, clientTypes: string[], userId: number, entity: { new (): Entity }): Entity[] { // Filter out invalid client values const matchingValues = findValuesInRecord(validKeys, clientTypes); @@ -390,12 +363,9 @@ export class ApplicationService { }); } - async findDevicesForApplication( - appId: number, - query: ListAllEntitiesDto - ): Promise { + async findDevicesForApplication(appId: number, query: ListAllEntitiesDto): Promise { const orderByColumn = this.getSortingForIoTDevices(query); - const direction = query?.sort?.toUpperCase() == "DESC" ? "DESC" : "ASC"; + const direction = query?.sort?.toUpperCase() === "DESC" ? "DESC" : "ASC"; const [data, count] = await this.iotDeviceRepository .createQueryBuilder("iot_device") @@ -412,16 +382,11 @@ export class ApplicationService { const loraDevices = data.filter( device => device.type === IoTDeviceType.LoRaWAN ) as LoRaWANDeviceWithChirpstackDataDto[]; - const applications = await this.chirpstackDeviceService.getLoRaWANApplications( - loraDevices - ); + const applications = await this.chirpstackDeviceService.getLoRaWANApplications(loraDevices); const loraApplications = applications.map(app => app.application); for (const device of loraDevices) { - await this.chirpstackDeviceService.enrichLoRaWANDevice( - device, - loraApplications - ); + await this.chirpstackDeviceService.enrichLoRaWANDevice(device, loraApplications); } return { @@ -450,15 +415,20 @@ export class ApplicationService { return orderBy; } - private getSortingForApplications( - query: ListAllEntitiesDto - ): Record { + private getSortingForApplications(query: ListAllEntitiesDto): Record { const sorting: Record = {}; if ( + // TODO: Make this nicer query.orderOn != null && - (query.orderOn == "id" || - query.orderOn == "name" || - query.orderOn == "updatedAt") + (query.orderOn === "id" || + query.orderOn === "name" || + query.orderOn === "updatedAt" || + query.orderOn === "status" || + query.orderOn === "startDate" || + query.orderOn === "endDate" || + query.orderOn === "owner" || + query.orderOn === "contactPerson" || + query.orderOn === "personalData") ) { sorting[query.orderOn] = query.sort.toLocaleUpperCase(); } else {