Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 27 additions & 27 deletions src/controllers/admin-controller/application.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,33 +85,6 @@ export class ApplicationController {
return await this.getApplicationsForNonGlobalAdmin(req, query);
}

private async getApplicationsForNonGlobalAdmin(req: AuthenticatedRequest, query: ListAllApplicationsDto) {
if (query?.organizationId) {
checkIfUserHasAccessToOrganization(req, query.organizationId, OrganizationAccessScope.ApplicationRead);
return await this.getApplicationsInOrganization(req, query);
}

const allFromOrg = req.user.permissions.getAllOrganizationsWithApplicationAdmin();
const allowedApplications = req.user.permissions.getAllApplicationsWithAtLeastRead();
const applications = await this.applicationService.findAndCountApplicationInWhitelistOrOrganization(
query,
allowedApplications,
query.organizationId ? [query.organizationId] : allFromOrg
);
return applications;
}

private async getApplicationsInOrganization(req: AuthenticatedRequest, query: ListAllApplicationsDto) {
// User admins have access to all applications in the organization
const allFromOrg = req.user.permissions.getAllOrganizationsWithUserAdmin();
if (allFromOrg.some(x => x === query?.organizationId)) {
return await this.applicationService.findAndCountWithPagination(query, [query.organizationId]);
}

const allowedApplications = req.user.permissions.getAllApplicationsWithAtLeastRead();
return await this.applicationService.findAndCountInList(query, allowedApplications, [query.organizationId]);
}

@Read()
@Get(":id")
@ApiOperation({ summary: "Find one Application by id" })
Expand Down Expand Up @@ -221,4 +194,31 @@ export class ApplicationController {
throw new NotFoundException(err);
}
}

private async getApplicationsForNonGlobalAdmin(req: AuthenticatedRequest, query: ListAllApplicationsDto) {
if (query?.organizationId) {
checkIfUserHasAccessToOrganization(req, query.organizationId, OrganizationAccessScope.ApplicationRead);
return await this.getApplicationsInOrganization(req, query);
}

const allFromOrg = req.user.permissions.getAllOrganizationsWithApplicationAdmin();
const allowedApplications = req.user.permissions.getAllApplicationsWithAtLeastRead();
const applications = await this.applicationService.findAndCountApplicationInWhitelistOrOrganization(
query,
allowedApplications,
query.organizationId ? [query.organizationId] : allFromOrg
);
return applications;
}

private async getApplicationsInOrganization(req: AuthenticatedRequest, query: ListAllApplicationsDto) {
// User admins have access to all applications in the organization
const allFromOrg = req.user.permissions.getAllOrganizationsWithUserAdmin();
if (allFromOrg.some(x => x === query?.organizationId)) {
return await this.applicationService.findAndCountWithPagination(query, [query.organizationId]);
}

const allowedApplications = req.user.permissions.getAllApplicationsWithAtLeastRead();
return await this.applicationService.findAndCountInList(query, allowedApplications, [query.organizationId]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { GatewayAdmin, Read } from "@auth/roles.decorator";
import { RolesGuard } from "@auth/roles.guard";
import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto";
import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto";
import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto";
import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-response.dto";
import { UpdateGatewayDto } from "@dto/chirpstack/update-gateway.dto";
import { ErrorCodes } from "@enum/error-codes.enum";
Expand All @@ -27,9 +26,10 @@ import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@he
import { AuthenticatedRequest } from "@dto/internal/authenticated-request";
import { AuditLog } from "@services/audit-log.service";
import { ActionType } from "@entities/audit-log-entry";
import { ChirpstackGetAll } from "@dto/chirpstack/chirpstack-get-all.dto";
import { ComposeAuthGuard } from "@auth/compose-auth.guard";
import { ApiAuth } from "@auth/swagger-auth-decorator";
import { ListAllGatewaysDto } from "@dto/chirpstack/list-all-gateways.dto";
import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways-response.dto";

@ApiTags("Chirpstack")
@Controller("chirpstack/gateway")
Expand Down Expand Up @@ -75,8 +75,8 @@ export class ChirpstackGatewayController {
@ApiProduces("application/json")
@ApiOperation({ summary: "List all Chirpstack gateways" })
@Read()
async getAll(@Query() query?: ChirpstackGetAll): Promise<ListAllGatewaysResponseDto> {
return await this.chirpstackGatewayService.getAll(query.organizationId);
async getAll(@Query() query?: ListAllGatewaysDto): Promise<ListAllGatewaysResponseDto> {
return await this.chirpstackGatewayService.getWithPaginationAndSorting(query, query.organizationId);
}

@Get(":gatewayId")
Expand Down
6 changes: 0 additions & 6 deletions src/entities/dto/chirpstack/chirpstack-get-all.dto.ts

This file was deleted.

11 changes: 11 additions & 0 deletions src/entities/dto/chirpstack/list-all-gateways-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ChirpstackGatewayResponseDto, GatewayResponseDto } from "./gateway-response.dto";

export class ListAllGatewaysResponseDto {
totalCount: number;
resultList: GatewayResponseDto[];
}

export class ListAllChirpstackGatewaysResponseDto {
totalCount: number;
resultList: ChirpstackGatewayResponseDto[];
}
31 changes: 23 additions & 8 deletions src/entities/dto/chirpstack/list-all-gateways.dto.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { ChirpstackGatewayResponseDto, GatewayResponseDto } from "./gateway-response.dto";
import { ApiProperty, OmitType, PickType } from "@nestjs/swagger";
import { ChirpstackPaginatedListDto } from "./chirpstack-paginated-list.dto";
import { ListAllEntitiesDto } from "@dto/list-all-entities.dto";
import { IsSwaggerOptional } from "@helpers/optional-validator";
import { NullableStringToNumber, StringToNumber } from "@helpers/string-to-number-validator";
import { IsNumber, IsOptional } from "class-validator";
import { Transform } from "class-transformer";
import { DefaultLimit, DefaultOffset } from "@config/constants/pagination-constants";

export class ListAllGatewaysResponseDto {
totalCount: number;
resultList: GatewayResponseDto[];
}
export class ListAllGatewaysDto extends OmitType(ListAllEntitiesDto, ["limit", "offset"]) {
@IsSwaggerOptional({ description: "Filter to one organization" })
@StringToNumber()
organizationId?: number;

@ApiProperty({ type: Number, required: false })
@IsOptional()
@IsNumber()
@Transform(({ value }) => NullableStringToNumber(value))
limit? = DefaultLimit;

export class ListAllChirpstackGatewaysResponseDto {
totalCount: number;
resultList: ChirpstackGatewayResponseDto[];
@ApiProperty({ type: Number, required: false })
@IsOptional()
@IsNumber()
@Transform(({ value }) => NullableStringToNumber(value))
offset? = DefaultOffset;
}
3 changes: 2 additions & 1 deletion src/entities/dto/list-all-entities.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ export class ListAllEntitiesDto {
| "openDataDkEnabled"
| "deviceModel"
| "devices"
| "dataTargets";
| "dataTargets"
| "organizationName";
}
62 changes: 56 additions & 6 deletions src/services/chirpstack/chirpstack-gateway.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ import { ChirpstackErrorResponseDto } from "@dto/chirpstack/chirpstack-error-res
import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto";
import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto";
import { GatewayStatsElementDto } from "@dto/chirpstack/gateway-stats.response.dto";
import {
ListAllChirpstackGatewaysResponseDto,
ListAllGatewaysResponseDto,
} from "@dto/chirpstack/list-all-gateways.dto";
import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-response.dto";
import { UpdateGatewayContentsDto, UpdateGatewayDto } from "@dto/chirpstack/update-gateway.dto";
import { ErrorCodes } from "@enum/error-codes.enum";
Expand All @@ -33,13 +29,19 @@ import {
GetGatewayMetricsResponse,
GetGatewayResponse,
ListGatewaysRequest,
UpdateGatewayRequest,
ListGatewaysResponse,
UpdateGatewayRequest,
} from "@chirpstack/chirpstack-api/api/gateway_pb";
import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb";
import { Aggregation, Location } from "@chirpstack/chirpstack-api/common/common_pb";
import { dateToTimestamp, timestampToDate } from "@helpers/date.helper";
import { ChirpstackGatewayResponseDto, GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto";
import { ListAllEntitiesDto } from "@dto/list-all-entities.dto";
import {
ListAllChirpstackGatewaysResponseDto,
ListAllGatewaysResponseDto,
} from "@dto/chirpstack/list-all-gateways-response.dto";

@Injectable()
export class ChirpstackGatewayService extends GenericChirpstackConfigurationService {
constructor(
Expand Down Expand Up @@ -148,6 +150,32 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
};
}

public async getWithPaginationAndSorting(
queryParams?: ListAllEntitiesDto,
organizationId?: number
): Promise<ListAllGatewaysResponseDto> {
const orderByColumn = this.getSortingForGateways(queryParams);
const direction = queryParams?.sort?.toUpperCase() === "DESC" ? "DESC" : "ASC";

let query = this.gatewayRepository
.createQueryBuilder("gateway")
.innerJoinAndSelect("gateway.organization", "organization")
.skip(queryParams?.offset ? +queryParams.offset : 0)
.take(queryParams.limit ? +queryParams.limit : 100)
.orderBy(orderByColumn, direction);

if (organizationId) {
query = query.where('"organizationId" = :organizationId', { organizationId });
}

const [gateways, count] = await query.getManyAndCount();

return {
resultList: gateways.map(this.mapGatewayToResponseDto),
totalCount: count,
};
}

async getOne(gatewayId: string): Promise<SingleGatewayResponseDto> {
if (gatewayId?.length != 16) {
throw new BadRequestException("Invalid gateway id");
Expand Down Expand Up @@ -294,9 +322,13 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
gatewayId: string,
rxPacketsReceived: number,
txPacketsEmitted: number,
updatedAt: Date,
lastSeenAt: Date | undefined
) {
await this.gatewayRepository.update({ gatewayId }, { rxPacketsReceived, txPacketsEmitted, lastSeenAt });
await this.gatewayRepository.update(
{ gatewayId },
{ rxPacketsReceived, txPacketsEmitted, lastSeenAt, updatedAt }
);
}

async ensureOrganizationIdIsSet(
Expand Down Expand Up @@ -454,4 +486,22 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
};
return responseList;
}

private getSortingForGateways(query: ListAllEntitiesDto) {
let orderBy = "gateway.id";

if (query.orderOn == null) {
return orderBy;
}

if (query.orderOn === "organizationName") {
orderBy = "organization.name";
} else if (query.orderOn === "status") {
orderBy = "gateway.lastSeenAt";
} else {
orderBy = `gateway.${query.orderOn}`;
}

return orderBy;
}
}
2 changes: 1 addition & 1 deletion src/services/chirpstack/gateway-boostrapper.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto";
import { GatewayStatusHistory } from "@entities/gateway-status-history.entity";
import { Inject, InternalServerErrorException, Logger, OnApplicationBootstrap } from "@nestjs/common";
import { ChirpstackGatewayService } from "./chirpstack-gateway.service";
import { GatewayStatusHistoryService } from "./gateway-status-history.service";
import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways-response.dto";

/**
* Verify if any gateways exist on chirpstack and haven't been loaded into the database.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export class LorawanDeviceDatabaseEnrichJob {
gateway.gatewayId,
stats.rxPacketsReceived,
stats.txPacketsEmitted,
gateway.updatedAt,
chirpstackGateway.lastSeenAt ? timestampToDate(chirpstackGateway.lastSeenAt) : undefined
);
} catch (err) {
Expand Down