Skip to content

Commit b320ac5

Browse files
Lauest-IteratorAugustHA-Iteratorfcv-iteratorIt
authored
44001: Applications overview update
* added filter endpoint on application.controller * updated endpoint for getting all applications. 24 hour statusCheck needs testing * added endpoint for application dashboard data * change from pr * pr changes * changes from pr * added device sort back in * Fix minor pr things --------- Co-authored-by: August Andersen <[email protected]> Co-authored-by: Frederik Christ Vestergaard <[email protected]>
1 parent 6b95d03 commit b320ac5

File tree

8 files changed

+388
-41
lines changed

8 files changed

+388
-41
lines changed

src/controllers/admin-controller/application.controller.ts

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,21 @@ import { ComposeAuthGuard } from "@auth/compose-auth.guard";
3030
import { ApplicationAdmin, Read } from "@auth/roles.decorator";
3131
import { RolesGuard } from "@auth/roles.guard";
3232
import { ApiAuth } from "@auth/swagger-auth-decorator";
33+
import { ApplicationDashboardResponseDto } from "@dto/applications-dashboard-responses";
3334
import { CreateApplicationDto } from "@dto/create-application.dto";
3435
import { DeleteResponseDto } from "@dto/delete-application-response.dto";
3536
import { ListAllApplicationsResponseDto } from "@dto/list-all-applications-response.dto";
3637
import { ListAllApplicationsDto } from "@dto/list-all-applications.dto";
3738
import { ListAllEntitiesDto } from "@dto/list-all-entities.dto";
3839
import { ListAllIoTDevicesResponseDto } from "@dto/list-all-iot-devices-response.dto";
3940
import { IoTDevicesListToMapResponseDto } from "@dto/list-all-iot-devices-to-map-response.dto";
41+
import { ListAllIotDevicesDto } from "@dto/list-all-iot-devices.dto";
4042
import { UpdateApplicationOrganizationDto } from "@dto/update-application-organization.dto";
4143
import { UpdateApplicationDto } from "@dto/update-application.dto";
4244
import { Application } from "@entities/application.entity";
4345
import { ActionType } from "@entities/audit-log-entry";
4446
import { AuthenticatedRequest } from "@entities/dto/internal/authenticated-request";
47+
import { IoTDevice } from "@entities/iot-device.entity";
4548
import { ErrorCodes } from "@enum/error-codes.enum";
4649
import {
4750
ApplicationAccessScope,
@@ -78,15 +81,61 @@ export class ApplicationController {
7881
@Query() query?: ListAllApplicationsDto
7982
): Promise<ListAllApplicationsResponseDto> {
8083
if (req.user.permissions.isGlobalAdmin) {
81-
return this.applicationService.findAndCountWithPagination(
82-
query,
83-
query.organizationId ? [+query.organizationId] : null
84-
);
84+
return this.applicationService.findAndCountInList(query);
8585
}
8686

8787
return await this.getApplicationsForNonGlobalAdmin(req, query);
8888
}
8989

90+
@Read()
91+
@Get(":id/filter-information")
92+
@ApiProduces("application/json")
93+
@ApiOperation({ summary: "returns filter information for application" })
94+
@ApiNotFoundResponse()
95+
async findFilterInformation(
96+
@Req() req: AuthenticatedRequest,
97+
@Param("id", new ParseIntPipe()) id: number
98+
): Promise<string[]> {
99+
try {
100+
const allOrgs = req.user.permissions.getAllOrganizationsWithUserAdmin();
101+
102+
return await this.applicationService.getFilterInformationInOrganization(
103+
allOrgs,
104+
id,
105+
req.user.permissions.isGlobalAdmin
106+
);
107+
} catch (err) {
108+
throw new NotFoundException(ErrorCodes.IdDoesNotExists);
109+
}
110+
}
111+
112+
@Read()
113+
@Get(":id/application-dashboard-data")
114+
@ApiProduces("application/json")
115+
@ApiOperation({ summary: "returns applications dashboard data" })
116+
@ApiNotFoundResponse()
117+
async countApplicationWithError(
118+
@Req() req: AuthenticatedRequest,
119+
@Param("id", new ParseIntPipe()) id: number
120+
): Promise<ApplicationDashboardResponseDto> {
121+
try {
122+
const allOrgs = req.user.permissions.getAllOrganizationsWithUserAdmin();
123+
124+
return {
125+
...(await this.applicationService.countApplicationsWithError(
126+
id,
127+
req.user.permissions.isGlobalAdmin ? "admin" : allOrgs
128+
)),
129+
totalDevices: await this.applicationService.countAllDevices(
130+
id,
131+
req.user.permissions.isGlobalAdmin ? "admin" : allOrgs
132+
),
133+
};
134+
} catch (err) {
135+
throw new NotFoundException(ErrorCodes.IdDoesNotExists);
136+
}
137+
}
138+
90139
@Read()
91140
@Get(":id")
92141
@ApiOperation({ summary: "Find one Application by id" })
@@ -119,6 +168,27 @@ export class ApplicationController {
119168
}
120169
}
121170

171+
@Read()
172+
@Get(":id/iot-devices-org")
173+
@ApiOperation({ summary: "Find the IoTDevice of an organization" })
174+
@ApiNotFoundResponse()
175+
async findIoTDevicesForOrganization(
176+
@Req() req: AuthenticatedRequest,
177+
@Param("id", new ParseIntPipe()) organizationId: number,
178+
@Query() query?: ListAllIotDevicesDto
179+
): Promise<IoTDevice[]> {
180+
try {
181+
const allOrgs = req.user.permissions.getAllOrganizationsWithUserAdmin();
182+
return await this.applicationService.getAllDevices(
183+
organizationId,
184+
query,
185+
req.user.permissions.isGlobalAdmin ? "admin" : allOrgs
186+
);
187+
} catch (err) {
188+
throw new NotFoundException(ErrorCodes.IdDoesNotExists);
189+
}
190+
}
191+
122192
@Read()
123193
@Get(":id/iot-devices-map")
124194
@ApiOperation({ summary: "Find the IoTDevices of an Application" })
@@ -257,10 +327,10 @@ export class ApplicationController {
257327
// User admins have access to all applications in the organization
258328
const allFromOrg = req.user.permissions.getAllOrganizationsWithUserAdmin();
259329
if (allFromOrg.some(x => x === query?.organizationId)) {
260-
return await this.applicationService.findAndCountWithPagination(query, [query.organizationId]);
330+
return await this.applicationService.findAndCountInList(query, null);
261331
}
262332

263333
const allowedApplications = req.user.permissions.getAllApplicationsWithAtLeastRead();
264-
return await this.applicationService.findAndCountInList(query, allowedApplications, [query.organizationId]);
334+
return await this.applicationService.findAndCountInList(query, allowedApplications);
265335
}
266336
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export type ApplicationsWithErrorsResponseDto = {
2+
total: number;
3+
withError: number;
4+
};
5+
6+
export type ApplicationDashboardResponseDto = {
7+
total: number;
8+
withError: number;
9+
totalDevices: number;
10+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { ListAllEntitiesResponseDto } from "@dto/list-all-entities-response.dto";
22
import { Application } from "@entities/application.entity";
33

4+
export type ApplicationWithStatus = Application & { statusCheck?: "stable" | "alert" };
5+
6+
export class ListAllApplicationsWithStatusResponseDto extends ListAllEntitiesResponseDto<ApplicationWithStatus> {}
47
export class ListAllApplicationsResponseDto extends ListAllEntitiesResponseDto<Application> {}

src/entities/dto/list-all-applications.dto.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import { DefaultLimit, DefaultOffset } from "@config/constants/pagination-constants";
22
import { ListAllEntitiesDto } from "@dto/list-all-entities.dto";
3+
import { ApplicationStatus } from "@enum/application-status.enum";
34
import { IsSwaggerOptional } from "@helpers/optional-validator";
4-
import { NullableStringToNumber, StringToNumber } from "@helpers/string-to-number-validator";
5+
import {
6+
NullableApplicationStatus,
7+
NullableString,
8+
NullableStringToNumber,
9+
StringToNumber,
10+
} from "@helpers/string-to-number-validator";
511
import { ApiProperty, OmitType } from "@nestjs/swagger";
612
import { Transform } from "class-transformer";
7-
import { IsOptional, IsNumber } from "class-validator";
13+
import { IsNumber, IsOptional, IsString } from "class-validator";
814

915
export class ListAllApplicationsDto extends OmitType(ListAllEntitiesDto, ["limit", "offset"]) {
1016
@IsSwaggerOptional({ description: "Filter to one organization" })
@@ -22,4 +28,22 @@ export class ListAllApplicationsDto extends OmitType(ListAllEntitiesDto, ["limit
2228
@IsNumber()
2329
@Transform(({ value }) => NullableStringToNumber(value))
2430
offset? = DefaultOffset;
31+
32+
@ApiProperty({ type: Number, required: false })
33+
@IsOptional()
34+
@IsString()
35+
@Transform(({ value }) => NullableApplicationStatus(value))
36+
status?: ApplicationStatus | undefined;
37+
38+
@ApiProperty({ type: String, required: false })
39+
@IsOptional()
40+
@IsString()
41+
@Transform(({ value }) => NullableString(value))
42+
statusCheck?: "stable" | "alert" | null;
43+
44+
@ApiProperty({ type: Number, required: false })
45+
@IsOptional()
46+
@IsString()
47+
@Transform(({ value }) => NullableString(value))
48+
owner?: string | null;
2549
}

src/entities/dto/list-all-entities.dto.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,6 @@ export class ListAllEntitiesDto {
4242
| "devices"
4343
| "dataTargets"
4444
| "organizationName"
45-
| "commentOnLocation";
45+
| "commentOnLocation"
46+
| "statusCheck";
4647
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ApplicationStatus } from "@enum/application-status.enum";
2+
import { NullableApplicationStatus, NullableString } from "@helpers/string-to-number-validator";
3+
import { ApiProperty } from "@nestjs/swagger";
4+
import { Transform } from "class-transformer";
5+
import { IsOptional, IsString } from "class-validator";
6+
7+
export class ListAllIotDevicesDto {
8+
@ApiProperty({ type: Number, required: false })
9+
@IsOptional()
10+
@IsString()
11+
@Transform(({ value }) => NullableApplicationStatus(value))
12+
status?: ApplicationStatus | undefined;
13+
14+
@ApiProperty({ type: String, required: false })
15+
@IsOptional()
16+
@IsString()
17+
@Transform(({ value }) => NullableString(value))
18+
statusCheck?: "stable" | "alert" | null;
19+
20+
@ApiProperty({ type: Number, required: false })
21+
@IsOptional()
22+
@IsString()
23+
@Transform(({ value }) => NullableString(value))
24+
owner?: string | null;
25+
}

src/helpers/string-to-number-validator.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ApplicationStatus } from "@enum/application-status.enum";
12
import { Type } from "class-transformer";
23
import { IsNumber } from "class-validator";
34

@@ -26,3 +27,19 @@ export const NullableStringToNumber = (value: unknown): number | null => {
2627

2728
return Number(value);
2829
};
30+
31+
export const NullableString = (value: unknown): string | null => {
32+
if (value === null || value === "null") {
33+
return null;
34+
}
35+
36+
return value as string;
37+
};
38+
39+
export const NullableApplicationStatus = (value: unknown): ApplicationStatus | null => {
40+
if (value === null || value === "null") {
41+
return null;
42+
}
43+
44+
return value as ApplicationStatus;
45+
};

0 commit comments

Comments
 (0)