@solidstarters/solid-core 1.2.48 → 1.2.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllers/security-rule.controller.d.ts +41 -0
- package/dist/controllers/security-rule.controller.d.ts.map +1 -0
- package/dist/controllers/security-rule.controller.js +179 -0
- package/dist/controllers/security-rule.controller.js.map +1 -0
- package/dist/dtos/create-model-metadata.dto.d.ts +3 -0
- package/dist/dtos/create-model-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-model-metadata.dto.js +18 -1
- package/dist/dtos/create-model-metadata.dto.js.map +1 -1
- package/dist/dtos/create-security-rule.dto.d.ts +10 -0
- package/dist/dtos/create-security-rule.dto.d.ts.map +1 -0
- package/dist/dtos/create-security-rule.dto.js +65 -0
- package/dist/dtos/create-security-rule.dto.js.map +1 -0
- package/dist/dtos/security-rule-config.dto.d.ts +4 -0
- package/dist/dtos/security-rule-config.dto.d.ts.map +1 -0
- package/dist/dtos/security-rule-config.dto.js +4 -0
- package/dist/dtos/security-rule-config.dto.js.map +1 -0
- package/dist/dtos/update-security-rule.dto.d.ts +11 -0
- package/dist/dtos/update-security-rule.dto.d.ts.map +1 -0
- package/dist/dtos/update-security-rule.dto.js +72 -0
- package/dist/dtos/update-security-rule.dto.js.map +1 -0
- package/dist/entities/email-template.entity.js +1 -1
- package/dist/entities/email-template.entity.js.map +1 -1
- package/dist/entities/model-metadata.entity.d.ts +2 -0
- package/dist/entities/model-metadata.entity.d.ts.map +1 -1
- package/dist/entities/model-metadata.entity.js +9 -1
- package/dist/entities/model-metadata.entity.js.map +1 -1
- package/dist/entities/security-rule.entity.d.ts +11 -0
- package/dist/entities/security-rule.entity.d.ts.map +1 -0
- package/dist/entities/security-rule.entity.js +53 -0
- package/dist/entities/security-rule.entity.js.map +1 -0
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +2 -1
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/helpers/solid-registry.d.ts +22 -1
- package/dist/helpers/solid-registry.d.ts.map +1 -1
- package/dist/helpers/solid-registry.js +29 -0
- package/dist/helpers/solid-registry.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +2 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/repository/security-rule.repository.d.ts +20 -0
- package/dist/repository/security-rule.repository.d.ts.map +1 -0
- package/dist/repository/security-rule.repository.js +128 -0
- package/dist/repository/security-rule.repository.js.map +1 -0
- package/dist/repository/solid-base.repository.d.ts +14 -0
- package/dist/repository/solid-base.repository.d.ts.map +1 -0
- package/dist/repository/solid-base.repository.js +26 -0
- package/dist/repository/solid-base.repository.js.map +1 -0
- package/dist/seeders/module-metadata-seeder.service.d.ts +5 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +22 -2
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +263 -0
- package/dist/services/field-metadata.service.d.ts.map +1 -1
- package/dist/services/field-metadata.service.js +1 -0
- package/dist/services/field-metadata.service.js.map +1 -1
- package/dist/services/module-metadata.service.d.ts.map +1 -1
- package/dist/services/module-metadata.service.js +1 -0
- package/dist/services/module-metadata.service.js.map +1 -1
- package/dist/services/request-context.service.d.ts +7 -0
- package/dist/services/request-context.service.d.ts.map +1 -0
- package/dist/services/request-context.service.js +33 -0
- package/dist/services/request-context.service.js.map +1 -0
- package/dist/services/security-rule.service.d.ts +27 -0
- package/dist/services/security-rule.service.d.ts.map +1 -0
- package/dist/services/security-rule.service.js +71 -0
- package/dist/services/security-rule.service.js.map +1 -0
- package/dist/services/view-metadata.service.d.ts +1 -0
- package/dist/services/view-metadata.service.d.ts.map +1 -1
- package/dist/services/view-metadata.service.js +22 -7
- package/dist/services/view-metadata.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +15 -1
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/security-rule.subscriber.d.ts +16 -0
- package/dist/subscribers/security-rule.subscriber.d.ts.map +1 -0
- package/dist/subscribers/security-rule.subscriber.js +123 -0
- package/dist/subscribers/security-rule.subscriber.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/controllers/security-rule.controller.ts +93 -0
- package/src/dtos/create-model-metadata.dto.ts +14 -0
- package/src/dtos/create-security-rule.dto.ts +34 -0
- package/src/dtos/security-rule-config.dto.ts +5 -0
- package/src/dtos/update-security-rule.dto.ts +39 -0
- package/src/entities/email-template.entity.ts +1 -1
- package/src/entities/model-metadata.entity.ts +6 -0
- package/src/entities/security-rule.entity.ts +25 -0
- package/src/entities/user.entity.ts +2 -1
- package/src/helpers/solid-registry.ts +34 -0
- package/src/index.ts +9 -0
- package/src/interfaces.ts +2 -0
- package/src/repository/security-rule.repository.ts +135 -0
- package/src/repository/solid-base.repository.ts +45 -0
- package/src/seeders/module-metadata-seeder.service.ts +28 -1
- package/src/seeders/seed-data/solid-core-metadata.json +264 -0
- package/src/seeders/seed-data/solid-core-metadata.json.bkp +6638 -0
- package/src/services/field-metadata.service.ts +1 -0
- package/src/services/module-metadata.service.ts +1 -0
- package/src/services/request-context.service.ts +16 -0
- package/src/services/security-rule.service.ts +54 -0
- package/src/services/view-metadata.service.ts +26 -7
- package/src/solid-core.module.ts +15 -1
- package/src/subscribers/security-rule.subscriber.ts +78 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidstarters/solid-core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.50",
|
|
4
4
|
"description": "This module is a NestJS module containing all the required core providers required by a Solid application",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Controller, Post, Body, Param, UploadedFiles, UseInterceptors, Put, Get, Query, Delete, Patch } from '@nestjs/common';
|
|
2
|
+
import { AnyFilesInterceptor } from "@nestjs/platform-express";
|
|
3
|
+
import { ApiBearerAuth, ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
4
|
+
import { SecurityRuleService } from '../services/security-rule.service';
|
|
5
|
+
import { CreateSecurityRuleDto } from '../dtos/create-security-rule.dto';
|
|
6
|
+
import { UpdateSecurityRuleDto } from '../dtos/update-security-rule.dto';
|
|
7
|
+
|
|
8
|
+
enum ShowSoftDeleted {
|
|
9
|
+
INCLUSIVE = "inclusive",
|
|
10
|
+
EXCLUSIVE = "exclusive",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@ApiTags('Solid Core')
|
|
14
|
+
@Controller('security-rule')
|
|
15
|
+
export class SecurityRuleController {
|
|
16
|
+
constructor(private readonly service: SecurityRuleService) {}
|
|
17
|
+
|
|
18
|
+
@ApiBearerAuth("jwt")
|
|
19
|
+
@Post()
|
|
20
|
+
@UseInterceptors(AnyFilesInterceptor())
|
|
21
|
+
create(@Body() createDto: CreateSecurityRuleDto, @UploadedFiles() files: Array<Express.Multer.File>) {
|
|
22
|
+
return this.service.create(createDto, files);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@ApiBearerAuth("jwt")
|
|
26
|
+
@Post('/bulk')
|
|
27
|
+
@UseInterceptors(AnyFilesInterceptor())
|
|
28
|
+
insertMany(@Body() createDtos: CreateSecurityRuleDto[], @UploadedFiles() filesArray: Express.Multer.File[][] = []) {
|
|
29
|
+
return this.service.insertMany(createDtos, filesArray);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@ApiBearerAuth("jwt")
|
|
34
|
+
@Put(':id')
|
|
35
|
+
@UseInterceptors(AnyFilesInterceptor())
|
|
36
|
+
update(@Param('id') id: number, @Body() updateDto: UpdateSecurityRuleDto, @UploadedFiles() files: Array<Express.Multer.File>) {
|
|
37
|
+
return this.service.update(id, updateDto, files);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@ApiBearerAuth("jwt")
|
|
41
|
+
@Patch(':id')
|
|
42
|
+
@UseInterceptors(AnyFilesInterceptor())
|
|
43
|
+
partialUpdate(@Param('id') id: number, @Body() updateDto: UpdateSecurityRuleDto, @UploadedFiles() files: Array<Express.Multer.File>) {
|
|
44
|
+
return this.service.update(id, updateDto, files, true);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@ApiBearerAuth("jwt")
|
|
48
|
+
@Post('/bulk-recover')
|
|
49
|
+
async recoverMany(@Body() ids: number[]) {
|
|
50
|
+
return this.service.recoverMany(ids);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@ApiBearerAuth("jwt")
|
|
54
|
+
@Get('/recover/:id')
|
|
55
|
+
async recover(@Param('id') id: number) {
|
|
56
|
+
return this.service.recover(id);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@ApiBearerAuth("jwt")
|
|
60
|
+
@ApiQuery({ name: 'showSoftDeleted', required: false, enum: ShowSoftDeleted })
|
|
61
|
+
@ApiQuery({ name: 'limit', required: false, type: Number })
|
|
62
|
+
@ApiQuery({ name: 'offset', required: false, type: Number })
|
|
63
|
+
@ApiQuery({ name: 'fields', required: false, type: Array })
|
|
64
|
+
@ApiQuery({ name: 'sort', required: false, type: Array })
|
|
65
|
+
@ApiQuery({ name: 'groupBy', required: false, type: Array })
|
|
66
|
+
@ApiQuery({ name: 'populate', required: false, type: Array })
|
|
67
|
+
@ApiQuery({ name: 'populateMedia', required: false, type: Array })
|
|
68
|
+
@ApiQuery({ name: 'filters', required: false, type: Array })
|
|
69
|
+
@Get()
|
|
70
|
+
async findMany(@Query() query: any) {
|
|
71
|
+
return this.service.find(query);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@ApiBearerAuth("jwt")
|
|
75
|
+
@Get(':id')
|
|
76
|
+
async findOne(@Param('id') id: string, @Query() query: any) {
|
|
77
|
+
return this.service.findOne(+id, query);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@ApiBearerAuth("jwt")
|
|
81
|
+
@Delete('/bulk')
|
|
82
|
+
async deleteMany(@Body() ids: number[]) {
|
|
83
|
+
return this.service.deleteMany(ids);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@ApiBearerAuth("jwt")
|
|
87
|
+
@Delete(':id')
|
|
88
|
+
async delete(@Param('id') id: number) {
|
|
89
|
+
return this.service.delete(id);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
}
|
|
@@ -94,4 +94,18 @@ export class CreateModelMetadataDto {
|
|
|
94
94
|
@ApiProperty({ description: 'System models are not included in the code generation, the assumption being that system models have manually written code.', })
|
|
95
95
|
@IsBoolean()
|
|
96
96
|
isSystem: boolean;
|
|
97
|
+
|
|
98
|
+
@ApiProperty({ description: 'Child models are not included in the code generation, the assumption being that child models have manually written code.', })
|
|
99
|
+
@IsBoolean()
|
|
100
|
+
isChild: boolean;
|
|
101
|
+
|
|
102
|
+
@ApiProperty({ description: 'Parent model id' })
|
|
103
|
+
@IsInt()
|
|
104
|
+
@IsOptional()
|
|
105
|
+
parentModelId: number;
|
|
106
|
+
|
|
107
|
+
@ApiProperty({ description: 'Parent model user key' })
|
|
108
|
+
@IsString()
|
|
109
|
+
@IsOptional()
|
|
110
|
+
parentModelUserKey: string;
|
|
97
111
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ApiProperty } from '@nestjs/swagger';
|
|
2
|
+
import { IsString } from 'class-validator';
|
|
3
|
+
import { IsNotEmpty, IsInt, IsOptional, IsJSON } from 'class-validator';
|
|
4
|
+
|
|
5
|
+
export class CreateSecurityRuleDto {
|
|
6
|
+
@IsNotEmpty()
|
|
7
|
+
@IsString()
|
|
8
|
+
@ApiProperty()
|
|
9
|
+
name: string;
|
|
10
|
+
@IsNotEmpty()
|
|
11
|
+
@IsString()
|
|
12
|
+
@ApiProperty()
|
|
13
|
+
description: string;
|
|
14
|
+
@IsOptional()
|
|
15
|
+
@IsInt()
|
|
16
|
+
@ApiProperty()
|
|
17
|
+
roleId: number;
|
|
18
|
+
@IsString()
|
|
19
|
+
@IsOptional()
|
|
20
|
+
@ApiProperty()
|
|
21
|
+
roleUserKey: string;
|
|
22
|
+
@IsOptional()
|
|
23
|
+
@IsInt()
|
|
24
|
+
@ApiProperty()
|
|
25
|
+
modelMetadataId: number;
|
|
26
|
+
@IsString()
|
|
27
|
+
@IsOptional()
|
|
28
|
+
@ApiProperty()
|
|
29
|
+
modelMetadataUserKey: string;
|
|
30
|
+
@IsNotEmpty()
|
|
31
|
+
@IsJSON()
|
|
32
|
+
@ApiProperty()
|
|
33
|
+
securityRuleConfig: any;
|
|
34
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { IsInt,IsOptional, IsString, IsNotEmpty, IsJSON } from 'class-validator';
|
|
2
|
+
import { ApiProperty } from '@nestjs/swagger';
|
|
3
|
+
|
|
4
|
+
export class UpdateSecurityRuleDto {
|
|
5
|
+
@IsOptional()
|
|
6
|
+
@IsInt()
|
|
7
|
+
id: number;
|
|
8
|
+
@IsNotEmpty()
|
|
9
|
+
@IsOptional()
|
|
10
|
+
@IsString()
|
|
11
|
+
@ApiProperty()
|
|
12
|
+
name: string;
|
|
13
|
+
@IsNotEmpty()
|
|
14
|
+
@IsOptional()
|
|
15
|
+
@IsString()
|
|
16
|
+
@ApiProperty()
|
|
17
|
+
description: string;
|
|
18
|
+
@IsOptional()
|
|
19
|
+
@IsInt()
|
|
20
|
+
@ApiProperty()
|
|
21
|
+
roleId: number;
|
|
22
|
+
@IsString()
|
|
23
|
+
@IsOptional()
|
|
24
|
+
@ApiProperty()
|
|
25
|
+
roleUserKey: string;
|
|
26
|
+
@IsOptional()
|
|
27
|
+
@IsInt()
|
|
28
|
+
@ApiProperty()
|
|
29
|
+
modelMetadataId: number;
|
|
30
|
+
@IsString()
|
|
31
|
+
@IsOptional()
|
|
32
|
+
@ApiProperty()
|
|
33
|
+
modelMetadataUserKey: string;
|
|
34
|
+
@IsNotEmpty()
|
|
35
|
+
@IsOptional()
|
|
36
|
+
@IsJSON()
|
|
37
|
+
@ApiProperty()
|
|
38
|
+
securityRuleConfig: any;
|
|
39
|
+
}
|
|
@@ -9,7 +9,7 @@ export class EmailTemplate extends CommonEntity {
|
|
|
9
9
|
name: string;
|
|
10
10
|
@Column({ name: "display_name", type: "varchar" })
|
|
11
11
|
displayName: string;
|
|
12
|
-
@Column({ name: "body", type: "varchar" })
|
|
12
|
+
@Column({ name: "body", type: "varchar", default: '' })
|
|
13
13
|
body: string;
|
|
14
14
|
@Column({ name: "subject", type: "varchar", default: "{}" })
|
|
15
15
|
subject: string = "{}";
|
|
@@ -56,4 +56,10 @@ export class ModelMetadata extends CommonEntity {
|
|
|
56
56
|
|
|
57
57
|
@Column({ default: false })
|
|
58
58
|
isSystem: boolean;
|
|
59
|
+
|
|
60
|
+
@Column({ default: false })
|
|
61
|
+
isChild: boolean;
|
|
62
|
+
|
|
63
|
+
@ManyToOne(() => ModelMetadata, { onDelete: 'CASCADE' })
|
|
64
|
+
parentModel: ModelMetadata;
|
|
59
65
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CommonEntity } from 'src/entities/common.entity';
|
|
2
|
+
import { ModelMetadata } from 'src/entities/model-metadata.entity';
|
|
3
|
+
import { RoleMetadata } from 'src/entities/role-metadata.entity';
|
|
4
|
+
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
|
5
|
+
|
|
6
|
+
@Entity("ss_security_rule")
|
|
7
|
+
export class SecurityRule extends CommonEntity {
|
|
8
|
+
@Index({ unique: true })
|
|
9
|
+
@Column({ type: "varchar" })
|
|
10
|
+
name: string;
|
|
11
|
+
@Index({ unique: true })
|
|
12
|
+
@Column({ type: "varchar" })
|
|
13
|
+
description: string;
|
|
14
|
+
@Index()
|
|
15
|
+
@ManyToOne(() => RoleMetadata, { onDelete: "CASCADE", nullable: false })
|
|
16
|
+
@JoinColumn()
|
|
17
|
+
role: RoleMetadata;
|
|
18
|
+
@Index()
|
|
19
|
+
@ManyToOne(() => ModelMetadata, { onDelete: "CASCADE", nullable: false })
|
|
20
|
+
@JoinColumn()
|
|
21
|
+
modelMetadata: ModelMetadata;
|
|
22
|
+
@Column({ type: "text" })
|
|
23
|
+
securityRuleConfig: any;
|
|
24
|
+
|
|
25
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { CommonEntity } from "src/entities/common.entity"
|
|
2
|
-
import { Entity, Column, Index, JoinTable, ManyToMany, OneToMany } from "typeorm";
|
|
2
|
+
import { Entity, Column, Index, JoinTable, ManyToMany, OneToMany, TableInheritance } from "typeorm";
|
|
3
3
|
import { RoleMetadata } from 'src/entities/role-metadata.entity';
|
|
4
4
|
import { UserViewMetadata } from 'src/entities/user-view-metadata.entity'
|
|
5
5
|
|
|
6
6
|
@Entity("ss_user")
|
|
7
|
+
@TableInheritance({ column: { type: "varchar", name: "type", default: "User" } })
|
|
7
8
|
export class User extends CommonEntity {
|
|
8
9
|
@Column({ type: "varchar", nullable: true })
|
|
9
10
|
fullName: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
2
|
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
|
|
3
3
|
import { ISelectionProvider, ISelectionProviderContext } from "../interfaces";
|
|
4
|
+
import { SecurityRule } from 'src/entities/security-rule.entity';
|
|
4
5
|
|
|
5
6
|
type ControllerMetadata = {
|
|
6
7
|
name: string;
|
|
@@ -14,6 +15,23 @@ export enum RESERVED_SOLID_KEYWORDS {
|
|
|
14
15
|
dataSource = "dataSource",
|
|
15
16
|
repository = "repository",
|
|
16
17
|
entityManager = "entityManager",
|
|
18
|
+
actionMetadata = "actionMetadata",
|
|
19
|
+
emailAttachment = "emailAttachment",
|
|
20
|
+
emailTemplate = "emailTemplate",
|
|
21
|
+
listOfValues = "listOfValues",
|
|
22
|
+
mediaStorageProvider = "mediaStorageProvider",
|
|
23
|
+
media = "media",
|
|
24
|
+
menuItemMetadata = "menuItemMetadata",
|
|
25
|
+
mqMessageQueue = "mqMessageQueue",
|
|
26
|
+
mqMessage = "mqMessage",
|
|
27
|
+
permissionMetadata = "permissionMetadata",
|
|
28
|
+
roleMetadata = "roleMetadata",
|
|
29
|
+
securityRule = "securityRule",
|
|
30
|
+
setting = "setting",
|
|
31
|
+
smsTemplate = "smsTemplate",
|
|
32
|
+
userPasswordHistory = "userPasswordHistory",
|
|
33
|
+
userMetadata = "userMetadata",
|
|
34
|
+
user = "user",
|
|
17
35
|
}
|
|
18
36
|
|
|
19
37
|
@Injectable()
|
|
@@ -24,6 +42,7 @@ export class SolidRegistry {
|
|
|
24
42
|
private solidDatabaseModules: Set<InstanceWrapper> = new Set();
|
|
25
43
|
private controllers: Set<ControllerMetadata> = new Set();
|
|
26
44
|
private modules : Set<InstanceWrapper> = new Set();
|
|
45
|
+
private securityRules: SecurityRule[] = [];
|
|
27
46
|
|
|
28
47
|
registerController(name: string, methodNames: string[]): void {
|
|
29
48
|
this.controllers.add({ name: name, methods: methodNames });
|
|
@@ -92,4 +111,19 @@ export class SolidRegistry {
|
|
|
92
111
|
const module = this.getModules().filter((module) => module.name === name).pop();
|
|
93
112
|
return module
|
|
94
113
|
}
|
|
114
|
+
|
|
115
|
+
registerSecurityRules(securityRules: SecurityRule[]) {
|
|
116
|
+
this.securityRules = securityRules;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
getSecurityRules(modelSingularName:string, roleNames: string[] = []): SecurityRule[] {
|
|
120
|
+
// If no role is provided, return all security rules for the model
|
|
121
|
+
if (roleNames.length === 0) {
|
|
122
|
+
return this.securityRules.filter((rule) => rule.modelMetadata.singularName === modelSingularName);
|
|
123
|
+
}
|
|
124
|
+
// If roles are provided, filter the security rules by model and roles
|
|
125
|
+
return this.securityRules.filter((rule) => {
|
|
126
|
+
return rule.modelMetadata.singularName === modelSingularName && roleNames.includes(rule.role.name);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
95
129
|
}
|
package/src/index.ts
CHANGED
|
@@ -78,6 +78,8 @@ export * from './dtos/update-user.dto'
|
|
|
78
78
|
export * from './dtos/update-view-metadata.dto'
|
|
79
79
|
export * from './dtos/create-setting.dto'
|
|
80
80
|
export * from './dtos/update-setting.dto'
|
|
81
|
+
export * from './dtos/create-security-rule.dto'
|
|
82
|
+
export * from './dtos/update-security-rule.dto'
|
|
81
83
|
|
|
82
84
|
|
|
83
85
|
export * from './entities/action-metadata.entity'
|
|
@@ -101,6 +103,7 @@ export * from './entities/user.entity'
|
|
|
101
103
|
export * from './entities/view-metadata.entity'
|
|
102
104
|
export * from './entities/setting.entity'
|
|
103
105
|
export * from './entities/user-view-metadata.entity'
|
|
106
|
+
export * from './entities/security-rule.entity'
|
|
104
107
|
|
|
105
108
|
export * from './enums/auth-type.enum'
|
|
106
109
|
|
|
@@ -214,6 +217,12 @@ export * from './services/user.service'
|
|
|
214
217
|
export * from './services/view-metadata.service'
|
|
215
218
|
export * from './services/whatsapp/Msg91WhatsappService' //rename
|
|
216
219
|
export * from './services/setting.service'
|
|
220
|
+
export * from './services/security-rule.service'
|
|
221
|
+
export * from './services/request-context.service'
|
|
222
|
+
|
|
223
|
+
// Repositories
|
|
224
|
+
export * from './repository/solid-base.repository'
|
|
225
|
+
export * from './repository/security-rule.repository'
|
|
217
226
|
|
|
218
227
|
|
|
219
228
|
//softDeleteAwareEventSubscriber.subscriber.ts
|
package/src/interfaces.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { CreateRoleMetadataDto } from './dtos/create-role-metadata.dto';
|
|
|
10
10
|
import { CreateViewMetadataDto } from './dtos/create-view-metadata.dto';
|
|
11
11
|
import { FieldMetadata } from './entities/field-metadata.entity';
|
|
12
12
|
import { Media } from './entities/media.entity';
|
|
13
|
+
import { CreateSecurityRuleDto } from './dtos/create-security-rule.dto';
|
|
13
14
|
|
|
14
15
|
export interface FieldCrudManager {
|
|
15
16
|
// fieldMetadata: FieldMetadata;
|
|
@@ -46,6 +47,7 @@ export interface ModuleMetadataConfiguration {
|
|
|
46
47
|
emailTemplates?: CreateEmailTemplateDto[],
|
|
47
48
|
smsTemplates?: CreateSmsTemplateDto[],
|
|
48
49
|
mediaStorageProviders?: CreateMediaStorageProviderMetadataDto[]
|
|
50
|
+
securityRules?: CreateSecurityRuleDto[],
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
export interface CodeGenerationOptions {
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
+
import { CreateSecurityRuleDto } from 'src/dtos/create-security-rule.dto';
|
|
3
|
+
import { SecurityRuleConfig } from 'src/dtos/security-rule-config.dto';
|
|
4
|
+
import { UpdateSecurityRuleDto } from 'src/dtos/update-security-rule.dto';
|
|
5
|
+
import { CommonEntity } from 'src/entities/common.entity';
|
|
6
|
+
import { ModelMetadata } from 'src/entities/model-metadata.entity';
|
|
7
|
+
import { RoleMetadata } from 'src/entities/role-metadata.entity';
|
|
8
|
+
import { SecurityRule } from 'src/entities/security-rule.entity';
|
|
9
|
+
import { SolidRegistry } from 'src/helpers/solid-registry';
|
|
10
|
+
import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
|
|
11
|
+
import { CrudHelperService } from 'src/services/crud-helper.service';
|
|
12
|
+
import { DataSource, Repository, SelectQueryBuilder } from 'typeorm';
|
|
13
|
+
|
|
14
|
+
@Injectable()
|
|
15
|
+
export class SecurityRuleRepository extends Repository<SecurityRule> {
|
|
16
|
+
private readonly logger = new Logger(SecurityRuleRepository.name);
|
|
17
|
+
constructor(
|
|
18
|
+
private dataSource: DataSource,
|
|
19
|
+
private readonly solidRegistry: SolidRegistry,
|
|
20
|
+
private readonly crudHelperService: CrudHelperService,
|
|
21
|
+
) {
|
|
22
|
+
super(SecurityRule, dataSource.createEntityManager());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
applySecurityRules<T extends CommonEntity>(qb: SelectQueryBuilder<T>, modelSingularName: string, activeUser: ActiveUserData,): SelectQueryBuilder<T> {
|
|
26
|
+
// Fetch the security rules for the model and roles
|
|
27
|
+
const securityRules = this.solidRegistry.getSecurityRules(modelSingularName, activeUser.roles);
|
|
28
|
+
|
|
29
|
+
// Loop through the security rules and add only rules that are json parseable and have a rule
|
|
30
|
+
securityRules.forEach((rule: SecurityRule) => {
|
|
31
|
+
try {
|
|
32
|
+
// Parse the security rule and call the buildFilter method to build the query from the security rule
|
|
33
|
+
const parsedRule = JSON.parse(this.resolveSecurityRuleConfig(rule.securityRuleConfig, activeUser)) as SecurityRuleConfig;
|
|
34
|
+
if (parsedRule && parsedRule.filters) {
|
|
35
|
+
this.crudHelperService.buildFilterQuery(qb, parsedRule, qb.alias);
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
this.logger.warn(`Error parsing security rule: ${rule.securityRuleConfig}`, error);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return qb;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
private resolveSecurityRuleConfig(configString: string, activeUser: ActiveUserData) {
|
|
47
|
+
return configString.replace('$activeUserId', activeUser.sub.toString());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async toDto(securityRule: SecurityRule): Promise<UpdateSecurityRuleDto> {
|
|
51
|
+
// load the role and model relations for the security rule
|
|
52
|
+
let populatedSecurityRule: SecurityRule = securityRule;
|
|
53
|
+
// If the security rule does not have the role and model relations loaded, load them
|
|
54
|
+
if (!securityRule.role || !securityRule.modelMetadata) {
|
|
55
|
+
populatedSecurityRule = await this.findOne({
|
|
56
|
+
where: {
|
|
57
|
+
id: securityRule.id,
|
|
58
|
+
},
|
|
59
|
+
relations: {
|
|
60
|
+
role: true,
|
|
61
|
+
modelMetadata: true,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
id: populatedSecurityRule.id,
|
|
68
|
+
name: populatedSecurityRule.name,
|
|
69
|
+
description: populatedSecurityRule.description,
|
|
70
|
+
roleId: populatedSecurityRule.role.id,
|
|
71
|
+
roleUserKey: populatedSecurityRule.role.name,
|
|
72
|
+
modelMetadataId: populatedSecurityRule.modelMetadata.id,
|
|
73
|
+
modelMetadataUserKey: populatedSecurityRule.modelMetadata.singularName,
|
|
74
|
+
securityRuleConfig: populatedSecurityRule.securityRuleConfig,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async upsertWithDto(createDto: CreateSecurityRuleDto) {
|
|
79
|
+
// Populate the role from roleId or roleUserKey
|
|
80
|
+
const roleRepository = this.dataSource.getRepository(RoleMetadata);
|
|
81
|
+
if (!createDto.roleId) {
|
|
82
|
+
const role = await roleRepository.findOne({
|
|
83
|
+
where: {
|
|
84
|
+
id: createDto.roleId,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
createDto['role'] = role;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (createDto.roleUserKey) {
|
|
91
|
+
const role = await roleRepository.findOne({
|
|
92
|
+
where: {
|
|
93
|
+
name: createDto.roleUserKey,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
createDto['role'] = role;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Populate the model from modelMetadataId or modelMetadataUserKey
|
|
100
|
+
const modelMetadataRepository = this.dataSource.getRepository(ModelMetadata);
|
|
101
|
+
if (!createDto.modelMetadataId) {
|
|
102
|
+
const modelMetadata = await modelMetadataRepository.findOne({
|
|
103
|
+
where: {
|
|
104
|
+
id: createDto.modelMetadataId,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
createDto['modelMetadata'] = modelMetadata;
|
|
108
|
+
}
|
|
109
|
+
if (createDto.modelMetadataUserKey) {
|
|
110
|
+
const modelMetadata = await modelMetadataRepository.findOne({
|
|
111
|
+
where: {
|
|
112
|
+
singularName: createDto.modelMetadataUserKey,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
createDto['modelMetadata'] = modelMetadata;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// First check if module already exists using name
|
|
119
|
+
const existingSecurityRule = await this.findOne({
|
|
120
|
+
where: {
|
|
121
|
+
name: createDto.name,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (existingSecurityRule) {
|
|
126
|
+
const updatedSecurityRule = this.merge(existingSecurityRule, createDto);
|
|
127
|
+
return this.save(updatedSecurityRule);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const securityRule = this.create(createDto);
|
|
131
|
+
return this.save(securityRule);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { camelize } from '@angular-devkit/core/src/utils/strings';
|
|
2
|
+
import { Logger } from '@nestjs/common';
|
|
3
|
+
import { CommonEntity } from 'src/entities/common.entity';
|
|
4
|
+
import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
|
|
5
|
+
import { RequestContextService } from 'src/services/request-context.service';
|
|
6
|
+
import {
|
|
7
|
+
DataSource,
|
|
8
|
+
EntityTarget,
|
|
9
|
+
QueryRunner,
|
|
10
|
+
Repository,
|
|
11
|
+
SelectQueryBuilder
|
|
12
|
+
} from 'typeorm';
|
|
13
|
+
import { SecurityRuleRepository } from './security-rule.repository';
|
|
14
|
+
|
|
15
|
+
export class SolidBaseRepository<T extends CommonEntity> extends Repository<T> {
|
|
16
|
+
protected readonly logger: Logger;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
entity: EntityTarget<T>,
|
|
20
|
+
dataSource: DataSource,
|
|
21
|
+
protected readonly requestContextService: RequestContextService,
|
|
22
|
+
protected readonly securityRuleRepository: SecurityRuleRepository
|
|
23
|
+
) {
|
|
24
|
+
super(entity, dataSource.createEntityManager());
|
|
25
|
+
this.logger = new Logger(this.constructor.name);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
modelSingularName(): string {
|
|
29
|
+
return camelize(this.metadata.name);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
createQueryBuilder(alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder<T> {
|
|
33
|
+
const activeUserOrUndefined = this.requestContextService.getActiveUser();
|
|
34
|
+
const qb = super.createQueryBuilder(alias, queryRunner);
|
|
35
|
+
if (!activeUserOrUndefined) return qb;
|
|
36
|
+
|
|
37
|
+
return this.securityRuleRepository.applySecurityRules(
|
|
38
|
+
qb,
|
|
39
|
+
this.modelSingularName(),
|
|
40
|
+
activeUserOrUndefined as ActiveUserData
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
}
|
|
@@ -32,6 +32,8 @@ import commonConfig from 'src/config/common.config';
|
|
|
32
32
|
import { CreateSettingDto } from 'src/dtos/create-setting.dto';
|
|
33
33
|
import { SettingService } from 'src/services/setting.service';
|
|
34
34
|
import { Setting } from 'src/entities/setting.entity';
|
|
35
|
+
import { CreateSecurityRuleDto } from 'src/dtos/create-security-rule.dto';
|
|
36
|
+
import { SecurityRuleRepository } from 'src/repository/security-rule.repository';
|
|
35
37
|
|
|
36
38
|
@Injectable()
|
|
37
39
|
export class ModuleMetadataSeederService {
|
|
@@ -62,6 +64,7 @@ export class ModuleMetadataSeederService {
|
|
|
62
64
|
private readonly service: SettingService,
|
|
63
65
|
@InjectRepository(Setting, 'default')
|
|
64
66
|
readonly settingsRepo: Repository<Setting>,
|
|
67
|
+
readonly securityRuleRepo: SecurityRuleRepository,
|
|
65
68
|
) { }
|
|
66
69
|
|
|
67
70
|
async seed() {
|
|
@@ -190,11 +193,17 @@ export class ModuleMetadataSeederService {
|
|
|
190
193
|
await this.seedSmsTemplates(smsTemplates);
|
|
191
194
|
this.logger.debug(`[End] Processing sms templates for ${moduleMetadata.name}`);
|
|
192
195
|
|
|
193
|
-
//
|
|
196
|
+
// Settings
|
|
194
197
|
this.logger.debug(`[Start] Processing settings for ${moduleMetadata.name}`);
|
|
195
198
|
await this.seedSettings(settingsSeederData);
|
|
196
199
|
this.logger.debug(`[End] Processing settings for ${moduleMetadata.name}`);
|
|
197
200
|
|
|
201
|
+
// Security rules
|
|
202
|
+
this.logger.debug(`[Start] Processing security rules for ${moduleMetadata.name}`);
|
|
203
|
+
const securityRules: CreateSecurityRuleDto[] = overallMetadata.securityRules;
|
|
204
|
+
await this.seedSecurityRules(securityRules);
|
|
205
|
+
this.logger.debug(`[End] Processing security rules for ${moduleMetadata.name}`);
|
|
206
|
+
|
|
198
207
|
this.logger.debug(`[End] module seed data: ${overallMetadata}`);
|
|
199
208
|
|
|
200
209
|
}
|
|
@@ -449,6 +458,13 @@ export class ModuleMetadataSeederService {
|
|
|
449
458
|
// const fieldsMetadata = modelMetdata.fields;
|
|
450
459
|
// delete modelMetdata['fields'];
|
|
451
460
|
const { fields: fieldsMetadata, ...modelMetaDataWithoutFields } = modelMetadata;
|
|
461
|
+
|
|
462
|
+
// Load and set the parent model if it exists.
|
|
463
|
+
if (modelMetadata.isChild && modelMetadata.parentModelUserKey) {
|
|
464
|
+
const parentModel = await this.modelMetadataService.findOneByUserKey(modelMetadata.parentModelUserKey);
|
|
465
|
+
modelMetaDataWithoutFields['parentModel'] = parentModel;
|
|
466
|
+
}
|
|
467
|
+
|
|
452
468
|
await this.modelMetadataService.upsert(modelMetaDataWithoutFields);
|
|
453
469
|
const model = await this.modelMetadataService.findOneBySingularName(modelMetadata.singularName)
|
|
454
470
|
|
|
@@ -486,4 +502,15 @@ export class ModuleMetadataSeederService {
|
|
|
486
502
|
this.service.create(createDto);
|
|
487
503
|
}
|
|
488
504
|
}
|
|
505
|
+
|
|
506
|
+
async seedSecurityRules(rulesDto: CreateSecurityRuleDto[]) {
|
|
507
|
+
if (!rulesDto || rulesDto.length === 0) {
|
|
508
|
+
this.logger.debug(`No security rules found to seed`);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
for (const dto of rulesDto) {
|
|
512
|
+
await this.securityRuleRepo.upsertWithDto({...dto, securityRuleConfig: JSON.stringify(dto.securityRuleConfig)});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
489
516
|
}
|