Skip to content

Commit 5cd1e4e

Browse files
Feature/iot 1416 (#211)
* Added missing packages to package lock * Create .licrc for licensebat scan * Deleting licensebat file as it is obsolete * IOT-1416: Minor changes for supporting the front-end-changes for having OpenDataDK datatargets more separate from HTTP-Push.. * Finished implementing new flow for sending ODDK-registration-mails directly from OS2IoT, instead of having to go through users mail-client.. * Renamed the new entity for OpenDataDK datatargets, to match naming-convention of other ODDK-files.. --------- Co-authored-by: Frederik Christ Vestergaard <[email protected]>
1 parent cf9da7f commit 5cd1e4e

18 files changed

+326
-93
lines changed

src/config/configuration.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ export default (): any => {
3939
email: {
4040
host: process.env.EMAIL_HOST || "smtp.ethereal.email",
4141
port: process.env.EMAIL_PORT || 587,
42-
user: process.env.EMAIL_USER || "ara.kertzmann8@ethereal.email",
43-
pass: process.env.EMAIL_PASS || "KzRSyYReEygpFPPZdd",
42+
user: process.env.EMAIL_USER || "tremayne38@ethereal.email",
43+
pass: process.env.EMAIL_PASS || "UjbMtRZNkrUcVJsvTM",
4444
/**
4545
* Can be formatted to show a user-friendly name before the e-mail.
4646
* E.g. "OS2iot <[email protected]>"
4747
*/
4848
from: process.env.EMAIL_FROM
4949
? formatEmail(process.env.EMAIL_FROM)
50-
: "OS2iot ara.kertzmann8@ethereal.email",
50+
: "OS2iot tremayne38@ethereal.email",
5151
},
5252
frontend: {
5353
baseurl: process.env.FRONTEND_BASEURL || "http://localhost:8081",

src/controllers/admin-controller/data-target.controller.ts

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ import {
1313
Req,
1414
UseGuards,
1515
} from "@nestjs/common";
16-
import { UnauthorizedException } from "@nestjs/common";
1716
import {
1817
ApiBadRequestResponse,
1918
ApiBearerAuth,
2019
ApiForbiddenResponse,
20+
ApiNotFoundResponse,
2121
ApiOperation,
2222
ApiTags,
2323
ApiUnauthorizedResponse,
2424
} from "@nestjs/swagger";
2525

26-
import { ComposeAuthGuard } from '@auth/compose-auth.guard';
26+
import { ComposeAuthGuard } from "@auth/compose-auth.guard";
2727
import { Read, ApplicationAdmin } from "@auth/roles.decorator";
2828
import { RolesGuard } from "@auth/roles.guard";
2929
import { CreateDataTargetDto } from "@dto/create-data-target.dto";
@@ -41,6 +41,8 @@ import {
4141
import { DataTargetService } from "@services/data-targets/data-target.service";
4242
import { AuditLog } from "@services/audit-log.service";
4343
import { ActionType } from "@entities/audit-log-entry";
44+
import { OrganizationService } from "@services/user-management/organization.service";
45+
import { OddkMailInfo } from "@dto/oddk-mail-info.dto";
4446

4547
@ApiTags("Data Target")
4648
@Controller("data-target")
@@ -50,7 +52,10 @@ import { ActionType } from "@entities/audit-log-entry";
5052
@ApiForbiddenResponse()
5153
@ApiUnauthorizedResponse()
5254
export class DataTargetController {
53-
constructor(private dataTargetService: DataTargetService) {}
55+
constructor(
56+
private dataTargetService: DataTargetService,
57+
private organizationService: OrganizationService
58+
) {}
5459

5560
@Get()
5661
@ApiOperation({ summary: "Find all DataTargets" })
@@ -65,7 +70,11 @@ export class DataTargetController {
6570
query.applicationId = +query.applicationId;
6671
}
6772

68-
checkIfUserHasAccessToApplication(req, query.applicationId, ApplicationAccessScope.Read);
73+
checkIfUserHasAccessToApplication(
74+
req,
75+
query.applicationId,
76+
ApplicationAccessScope.Read
77+
);
6978
const allowed = req.user.permissions.getAllApplicationsWithAtLeastRead();
7079

7180
return await this.dataTargetService.findAndCountAllWithPagination(
@@ -83,7 +92,11 @@ export class DataTargetController {
8392
): Promise<DataTarget> {
8493
try {
8594
const dataTarget = await this.dataTargetService.findOne(id);
86-
checkIfUserHasAccessToApplication(req, dataTarget.application.id, ApplicationAccessScope.Read);
95+
checkIfUserHasAccessToApplication(
96+
req,
97+
dataTarget.application.id,
98+
ApplicationAccessScope.Read
99+
);
87100
return dataTarget;
88101
} catch (err) {
89102
throw new NotFoundException(ErrorCodes.IdDoesNotExists);
@@ -132,9 +145,17 @@ export class DataTargetController {
132145
): Promise<DataTarget> {
133146
const oldDataTarget = await this.dataTargetService.findOne(id);
134147
try {
135-
checkIfUserHasAccessToApplication(req, oldDataTarget.application.id, ApplicationAccessScope.Write);
148+
checkIfUserHasAccessToApplication(
149+
req,
150+
oldDataTarget.application.id,
151+
ApplicationAccessScope.Write
152+
);
136153
if (oldDataTarget.application.id !== updateDto.applicationId) {
137-
checkIfUserHasAccessToApplication(req, updateDto.applicationId, ApplicationAccessScope.Write);
154+
checkIfUserHasAccessToApplication(
155+
req,
156+
updateDto.applicationId,
157+
ApplicationAccessScope.Write
158+
);
138159
}
139160
} catch (err) {
140161
AuditLog.fail(
@@ -172,7 +193,11 @@ export class DataTargetController {
172193
): Promise<DeleteResponseDto> {
173194
try {
174195
const dt = await this.dataTargetService.findOne(id);
175-
checkIfUserHasAccessToApplication(req, dt.application.id, ApplicationAccessScope.Write);
196+
checkIfUserHasAccessToApplication(
197+
req,
198+
dt.application.id,
199+
ApplicationAccessScope.Write
200+
);
176201
const result = await this.dataTargetService.delete(id);
177202

178203
if (result.affected === 0) {
@@ -188,4 +213,47 @@ export class DataTargetController {
188213
throw new NotFoundException(err);
189214
}
190215
}
216+
217+
@Get("getOpenDataDkRegistered/:organizationId")
218+
@ApiOperation({ summary: "Get OpenDataDkRegistered-status for given OrganizationId" })
219+
@ApiNotFoundResponse()
220+
@Read()
221+
async getOpenDataDkRegistered(@Param("organizationId", new ParseIntPipe()) organizationId: number): Promise<boolean> {
222+
try {
223+
return (await this.organizationService.findById(organizationId))?.openDataDkRegistered;
224+
} catch (err) {
225+
throw new NotFoundException(ErrorCodes.IdDoesNotExists);
226+
}
227+
}
228+
229+
@Put("updateOpenDataDkRegistered/:organizationId")
230+
@ApiOperation({
231+
summary: "Update the OpenDataDkRegistered to true, for the given OrganizationId - to stop showing the dialog for sending ODDK-mail on creation of new datatargets",
232+
})
233+
@ApiNotFoundResponse()
234+
async updateOpenDataDkRegistered(
235+
@Req() req: AuthenticatedRequest,
236+
@Param("organizationId", new ParseIntPipe()) organizationId: number
237+
): Promise<boolean> {
238+
try {
239+
await this.organizationService.updateOpenDataDkRegistered(organizationId, req.user.userId);
240+
return true;
241+
} catch (err) {
242+
if (err.name == "EntityNotFound") {
243+
throw new NotFoundException();
244+
}
245+
throw err;
246+
}
247+
}
248+
249+
@Post("sendOpenDataDkMail")
250+
@ApiOperation({summary: "Send mail for registering datatargets to Open Data DK, for the given OrganizationId"})
251+
async sendOpenDataDkMail(
252+
@Req() req: AuthenticatedRequest,
253+
@Body() mailInfoDto: OddkMailInfo
254+
): Promise<boolean> {
255+
await this.dataTargetService.sendOpenDataDkMail(mailInfoDto, req.user.userId);
256+
await this.organizationService.updateOpenDataDkRegistered(mailInfoDto.organizationId, req.user.userId);
257+
return true;
258+
}
191259
}

src/controllers/admin-controller/open-data-dk-sharing.controller.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { ErrorCodes } from "@enum/error-codes.enum";
33
import { Controller, Get, NotFoundException, Param, ParseIntPipe } from "@nestjs/common";
44
import { ApiTags } from "@nestjs/swagger";
55
import { OpenDataDkSharingService } from "@services/data-management/open-data-dk-sharing.service";
6-
import { DataTargetService } from "@services/data-targets/data-target.service";
76
import { OrganizationService } from "@services/user-management/organization.service";
87

98
@ApiTags("OpenData.dk")

src/entities/dto/create-data-target.dto.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export class CreateDataTargetDto {
4040
@ApiProperty({ required: true })
4141
type: DataTargetType;
4242

43+
@ValidateIf((obj: CreateDataTargetDto) => obj.type !== DataTargetType.OpenDataDK)
4344
@ApiProperty({ required: true, example: "https://example.com/endpoint" })
4445
@IsString()
4546
@MaxLength(1024)
@@ -51,6 +52,7 @@ export class CreateDataTargetDto {
5152
})
5253
url: string;
5354

55+
@ValidateIf((obj: CreateDataTargetDto) => obj.type !== DataTargetType.OpenDataDK)
5456
@ApiProperty({ required: true, example: 30000 })
5557
@IsInt()
5658
timeout: number;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ApiProperty } from "@nestjs/swagger";
2+
import { IsNumber, IsString, IsUrl, MaxLength } from "class-validator";
3+
4+
export class OddkMailInfo {
5+
@ApiProperty({ required: true })
6+
@IsNumber()
7+
organizationId: number;
8+
9+
@ApiProperty({ required: true })
10+
@IsString()
11+
organizationOddkAlias: string;
12+
13+
@ApiProperty({ required: false })
14+
comment?: string;
15+
16+
@ApiProperty({ required: true })
17+
@IsString()
18+
@MaxLength(1024)
19+
@IsUrl({
20+
require_tld: false,
21+
})
22+
sharingUrl: string;
23+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { FiwareDataTarget } from "@entities/fiware-data-target.entity";
22
import { HttpPushDataTarget } from "@entities/http-push-data-target.entity";
33
import { MqttDataTarget } from "@entities/mqtt-data-target.entity";
4+
import { OpenDataDkDataTarget } from "@entities/open-data-dk-push-data-target.entity";
45
import { DataTargetType } from "@enum/data-target-type.enum";
56

67
export const dataTargetTypeMap = {
78
[DataTargetType.HttpPush]: HttpPushDataTarget,
89
[DataTargetType.Fiware]: FiwareDataTarget,
910
[DataTargetType.MQTT]: MqttDataTarget,
11+
[DataTargetType.OpenDataDK]: OpenDataDkDataTarget,
1012
};

src/entities/enum/data-target-type.enum.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export enum DataTargetType {
22
HttpPush = "HTTP_PUSH",
33
Fiware = "FIWARE",
44
MQTT = "MQTT",
5+
OpenDataDK = "OPENDATADK",
56
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { DataTarget } from "@entities/data-target.entity";
2+
import { DataTargetType } from "@enum/data-target-type.enum";
3+
import { BeforeInsert, ChildEntity } from "typeorm";
4+
5+
@ChildEntity(DataTargetType.OpenDataDK)
6+
export class OpenDataDkDataTarget extends DataTarget {
7+
@BeforeInsert()
8+
private beforeInsert() {
9+
this.type = DataTargetType.OpenDataDK;
10+
}
11+
}

src/entities/organization.entity.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export class Organization extends DbBaseEntity {
1515
@Column({ unique: true })
1616
name: string;
1717

18+
@Column({ default: false })
19+
openDataDkRegistered: boolean;
20+
1821
@OneToMany(
1922
// eslint-disable-next-line @typescript-eslint/no-unused-vars
2023
type => Application,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class openDataDkDataTarget1681915516234 implements MigrationInterface {
4+
name = 'openDataDkDataTarget1681915516234'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`ALTER TYPE "public"."data_target_type_enum" RENAME TO "data_target_type_enum_old"`);
8+
await queryRunner.query(`CREATE TYPE "public"."data_target_type_enum" AS ENUM('HTTP_PUSH', 'FIWARE', 'MQTT', 'OPENDATADK')`);
9+
await queryRunner.query(`ALTER TABLE "data_target" ALTER COLUMN "type" TYPE "public"."data_target_type_enum" USING "type"::"text"::"public"."data_target_type_enum"`);
10+
await queryRunner.query(`DROP TYPE "public"."data_target_type_enum_old"`);
11+
}
12+
13+
public async down(queryRunner: QueryRunner): Promise<void> {
14+
await queryRunner.query(`CREATE TYPE "public"."data_target_type_enum_old" AS ENUM('HTTP_PUSH', 'FIWARE', 'MQTT')`);
15+
await queryRunner.query(`ALTER TABLE "data_target" ALTER COLUMN "type" TYPE "public"."data_target_type_enum_old" USING "type"::"text"::"public"."data_target_type_enum_old"`);
16+
await queryRunner.query(`DROP TYPE "public"."data_target_type_enum"`);
17+
await queryRunner.query(`ALTER TYPE "public"."data_target_type_enum_old" RENAME TO "data_target_type_enum"`);
18+
}
19+
20+
}

0 commit comments

Comments
 (0)