@smartsoft001/nestjs 1.1.91 → 2.60.0

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.
Files changed (62) hide show
  1. package/.eslintrc.json +30 -0
  2. package/README.md +345 -4
  3. package/jest.config.ts +10 -0
  4. package/package.json +12 -46
  5. package/project.json +37 -0
  6. package/src/{index.d.ts → index.ts} +3 -3
  7. package/src/lib/auth/{index.d.ts → index.ts} +1 -0
  8. package/src/lib/auth/jwt.strategy.ts +24 -0
  9. package/src/lib/auth/permission.service.spec.ts +61 -0
  10. package/src/lib/auth/permission.service.ts +34 -0
  11. package/src/lib/decorators/user/user.decorator.ts +26 -0
  12. package/src/lib/filters/execution/exception.filter.ts +89 -0
  13. package/src/lib/filters/execution/execution.filter.spec.ts +107 -0
  14. package/src/lib/filters/index.ts +1 -0
  15. package/src/lib/shared.config.ts +21 -0
  16. package/src/lib/shared.module.ts +55 -0
  17. package/tsconfig.json +22 -0
  18. package/tsconfig.lib.json +10 -0
  19. package/tsconfig.spec.json +15 -0
  20. package/src/index.js +0 -9
  21. package/src/index.js.map +0 -1
  22. package/src/lib/auth/index.js +0 -5
  23. package/src/lib/auth/index.js.map +0 -1
  24. package/src/lib/auth/jwt.strategy.d.ts +0 -8
  25. package/src/lib/auth/jwt.strategy.js +0 -30
  26. package/src/lib/auth/jwt.strategy.js.map +0 -1
  27. package/src/lib/auth/permission.service.d.ts +0 -7
  28. package/src/lib/auth/permission.service.js +0 -28
  29. package/src/lib/auth/permission.service.js.map +0 -1
  30. package/src/lib/controllers/health/health.controller.d.ts +0 -10
  31. package/src/lib/controllers/health/health.controller.js +0 -37
  32. package/src/lib/controllers/health/health.controller.js.map +0 -1
  33. package/src/lib/controllers/index.d.ts +0 -2
  34. package/src/lib/controllers/index.js +0 -8
  35. package/src/lib/controllers/index.js.map +0 -1
  36. package/src/lib/decorators/index.js +0 -5
  37. package/src/lib/decorators/index.js.map +0 -1
  38. package/src/lib/decorators/user/user.decorator.d.ts +0 -1
  39. package/src/lib/decorators/user/user.decorator.js +0 -9
  40. package/src/lib/decorators/user/user.decorator.js.map +0 -1
  41. package/src/lib/filters/exception/exception.filter.d.ts +0 -4
  42. package/src/lib/filters/exception/exception.filter.js +0 -49
  43. package/src/lib/filters/exception/exception.filter.js.map +0 -1
  44. package/src/lib/filters/index.d.ts +0 -1
  45. package/src/lib/filters/index.js +0 -5
  46. package/src/lib/filters/index.js.map +0 -1
  47. package/src/lib/services/health-db/health-db.service.d.ts +0 -7
  48. package/src/lib/services/health-db/health-db.service.js +0 -39
  49. package/src/lib/services/health-db/health-db.service.js.map +0 -1
  50. package/src/lib/services/index.d.ts +0 -3
  51. package/src/lib/services/index.js +0 -10
  52. package/src/lib/services/index.js.map +0 -1
  53. package/src/lib/shared.config.d.ts +0 -15
  54. package/src/lib/shared.config.js +0 -11
  55. package/src/lib/shared.config.js.map +0 -1
  56. package/src/lib/shared.module.d.ts +0 -14
  57. package/src/lib/shared.module.js +0 -49
  58. package/src/lib/shared.module.js.map +0 -1
  59. package/test-setup.d.ts +0 -0
  60. package/test-setup.js +0 -1
  61. package/test-setup.js.map +0 -1
  62. /package/src/lib/decorators/{index.d.ts → index.ts} +0 -0
package/.eslintrc.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "extends": ["../../../.eslintrc.json"],
3
+ "ignorePatterns": ["!**/*"],
4
+ "overrides": [
5
+ {
6
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7
+ "rules": {}
8
+ },
9
+ {
10
+ "files": ["*.ts", "*.tsx"],
11
+ "rules": {}
12
+ },
13
+ {
14
+ "files": ["*.js", "*.jsx"],
15
+ "rules": {}
16
+ },
17
+ {
18
+ "files": ["*.json"],
19
+ "parser": "jsonc-eslint-parser",
20
+ "rules": {
21
+ "@nx/dependency-checks": [
22
+ "error",
23
+ {
24
+ "ignoredFiles": ["{projectRoot}/eslint.config.{js,cjs,mjs}"]
25
+ }
26
+ ]
27
+ }
28
+ }
29
+ ]
30
+ }
package/README.md CHANGED
@@ -1,7 +1,348 @@
1
- # shared-nestjs
1
+ # 📦 @smartsoft001/nestjs npm downloads
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ ![npm](https://img.shields.io/npm/v/@smartsoft001/nestjs) ![downloads](https://img.shields.io/npm/dm/@smartsoft001/nestjs)
4
4
 
5
- ## Running unit tests
5
+ ## 🚀 Usage
6
6
 
7
- Run `ng test shared-nestjs` to execute the unit tests via [Jest](https://jestjs.io).
7
+ ```bash
8
+ npm install @smartsoft001/nestjs
9
+ ```
10
+
11
+ ## ⚙️ Configuration
12
+
13
+ The library uses the `SharedConfig` class for authentication and permissions configuration:
14
+
15
+ ### Token Configuration
16
+
17
+ | Field | Type | Description |
18
+ | -------------------------------- | -------- | ---------------------------------------- |
19
+ | `tokenConfig.secretOrPrivateKey` | `string` | Secret or private key for signing tokens |
20
+ | `tokenConfig.expiredIn` | `number` | Token expiration time in seconds |
21
+
22
+ ### Permissions Configuration
23
+
24
+ | Field | Type | Description |
25
+ | -------------------- | --------------- | ----------------------------------------- |
26
+ | `permissions.create` | `Array<string>` | List of permissions for create operations |
27
+ | `permissions.read` | `Array<string>` | List of permissions for read operations |
28
+ | `permissions.update` | `Array<string>` | List of permissions for update operations |
29
+ | `permissions.delete` | `Array<string>` | List of permissions for delete operations |
30
+ | `permissions.[key]` | `Array<string>` | Any additional custom permissions |
31
+
32
+ ## Types
33
+
34
+ ```typescript
35
+ export type PermissionType = 'create' | 'read' | 'update' | 'delete' | string;
36
+ ```
37
+
38
+ # Modules
39
+
40
+ ## SharedModule
41
+
42
+ The `SharedModule` is a dynamic NestJS module that provides shared configuration and services across the application. It offers two static methods for configuration: `forFeature()` and `forRoot()`.
43
+
44
+ ---
45
+
46
+ ### forFeature() Method
47
+
48
+ The `forFeature()` method configures the module's core functionalities:
49
+
50
+ ```typescript
51
+ static forFeature(config: SharedConfig): DynamicModule
52
+ ```
53
+
54
+ #### Parameters:
55
+
56
+ - `config`: An object of type `SharedConfig` containing the module's configuration.
57
+
58
+ #### Returns:
59
+
60
+ A `DynamicModule` object with the following elements:
61
+
62
+ - Providers: `SharedConfig`, `JwtStrategy`, `PermissionService`
63
+ - Exports: `SharedConfig`, `PermissionService`, `JwtStrategy`
64
+
65
+ #### Example Usage:
66
+
67
+ ```typescript
68
+ import { SharedModule, SharedConfig } from '@smartsoft001/nestjs';
69
+
70
+ @Module({
71
+ imports: [
72
+ SharedModule.forFeature({
73
+ tokenConfig: {
74
+ secretOrPrivateKey: 'secret_key',
75
+ expiredIn: 3600,
76
+ },
77
+ permissions: {
78
+ create: ['admin'],
79
+ read: ['user', 'admin'],
80
+ update: ['admin'],
81
+ delete: ['admin'],
82
+ },
83
+ }),
84
+ ],
85
+ })
86
+ export class AppModule {}
87
+ ```
88
+
89
+ ---
90
+
91
+ ### forRoot() Method
92
+
93
+ The `forRoot()` method extends the `forFeature()` configuration by adding database settings:
94
+
95
+ ```typescript
96
+ static forRoot(config: SharedConfig & {
97
+ db: {
98
+ host: string;
99
+ port: number;
100
+ database: string;
101
+ username?: string;
102
+ password?: string;
103
+ };
104
+ }): DynamicModule
105
+ ```
106
+
107
+ #### Parameters:
108
+
109
+ - `config`: An extended `SharedConfig` object that includes additional database settings.
110
+
111
+ #### Returns:
112
+
113
+ A `DynamicModule` object that imports and exports the `forFeature()` configuration.
114
+
115
+ #### Example Usage:
116
+
117
+ ```typescript
118
+ import { SharedModule, SharedConfig } from '@smartsoft001/nestjs';
119
+
120
+ @Module({
121
+ imports: [
122
+ SharedModule.forRoot({
123
+ tokenConfig: {
124
+ secretOrPrivateKey: 'secret_key',
125
+ expiredIn: 3600,
126
+ },
127
+ permissions: {
128
+ create: ['admin'],
129
+ read: ['user', 'admin'],
130
+ update: ['admin'],
131
+ delete: ['admin'],
132
+ },
133
+ db: {
134
+ host: 'localhost',
135
+ port: 5432,
136
+ database: 'my_database',
137
+ username: 'user',
138
+ password: 'password',
139
+ },
140
+ }),
141
+ ],
142
+ })
143
+ export class AppModule {}
144
+ ```
145
+
146
+ ---
147
+
148
+ ### Summary
149
+
150
+ The `SharedModule` provides flexible configuration for various use cases, enabling easy sharing of authorization, permissions, and database settings across the entire NestJS application.
151
+
152
+ # Decorators
153
+
154
+ ## @User Decorator
155
+
156
+ The `@User` decorator is a custom parameter decorator in NestJS that simplifies retrieving the user object from an HTTP request.
157
+
158
+ ### Functionality
159
+
160
+ The `@User` decorator performs the following actions:
161
+
162
+ - Extracts the request object (`req`) from the execution context.
163
+ - Returns the `req.user` value, which typically contains information about the authenticated user.
164
+
165
+ ### Usage
166
+
167
+ The `@User` decorator can be used in NestJS controllers to easily access user data:
168
+
169
+ ```typescript
170
+ import { Controller, Get } from '@nestjs/common';
171
+
172
+ import { IUser } from '@smartsoft001/users';
173
+
174
+ import { User } from './user.decorator';
175
+
176
+ @Controller('profile')
177
+ export class ProfileController {
178
+ @Get()
179
+ getProfile(@User() user: IUser) {
180
+ return user;
181
+ }
182
+ }
183
+ ```
184
+
185
+ # Auth
186
+
187
+ After registering the authentication module, you can use `JwtStrategy` and `PermissionService` as follows:
188
+
189
+ ---
190
+
191
+ ## Using JwtStrategy
192
+
193
+ `JwtStrategy` is automatically used by `AuthGuard('jwt')`. You don't need to call it directly. Instead, use it indirectly via the `@UseGuards()` decorator:
194
+
195
+ ```typescript
196
+ import { Controller, Get, UseGuards } from '@nestjs/common';
197
+ import { AuthGuard } from '@nestjs/passport';
198
+
199
+ @Controller('secure')
200
+ @UseGuards(AuthGuard('jwt'))
201
+ export class SecureController {
202
+ @Get()
203
+ getSecureData() {
204
+ return 'This is protected content';
205
+ }
206
+ }
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Using PermissionService
212
+
213
+ `PermissionService` can be injected into controllers or services and used directly. Here are the main usage patterns:
214
+
215
+ ### 1. **Injecting the Service**
216
+
217
+ ```typescript
218
+ import { Injectable } from '@nestjs/common';
219
+ import { PermissionService } from './permission.service';
220
+
221
+ @Injectable()
222
+ export class SomeService {
223
+ constructor(private permissionService: PermissionService) {}
224
+
225
+ // ...
226
+ }
227
+ ```
228
+
229
+ ---
230
+
231
+ ### 2. **Validating Permissions**
232
+
233
+ ```typescript
234
+ import { User } from './user.decorator';
235
+
236
+ @Get('admin-panel')
237
+ adminPanel(@User() user) {
238
+ this.permissionService.valid('admin-panel', user);
239
+ return 'Admin Panel';
240
+ }
241
+ ```
242
+
243
+ ---
244
+
245
+ ### 3. **Handling Errors**
246
+
247
+ ```typescript
248
+ try {
249
+ this.permissionService.valid('some-action', user);
250
+ // Perform the protected action
251
+ } catch (error) {
252
+ if (error instanceof DomainForbiddenError) {
253
+ // Handle lack of permissions
254
+ }
255
+ throw error;
256
+ }
257
+ ```
258
+
259
+ ---
260
+
261
+ ### 4. **Using in a Custom Guard**
262
+
263
+ ```typescript
264
+ import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
265
+ import { PermissionService } from './permission.service';
266
+
267
+ @Injectable()
268
+ export class CustomPermissionGuard implements CanActivate {
269
+ constructor(private permissionService: PermissionService) {}
270
+
271
+ canActivate(context: ExecutionContext): boolean {
272
+ const request = context.switchToHttp().getRequest();
273
+ const user = request.user;
274
+ const requiredPermission = 'some-permission';
275
+
276
+ try {
277
+ this.permissionService.valid(requiredPermission, user);
278
+ return true;
279
+ } catch (error) {
280
+ return false;
281
+ }
282
+ }
283
+ }
284
+ ```
285
+
286
+ ---
287
+
288
+ ### 5. **Checking Multiple Permissions**
289
+
290
+ ```typescript
291
+ multipleChecks(@User() user) {
292
+ this.permissionService.valid('permission1', user);
293
+ this.permissionService.valid('permission2', user);
294
+ // If both checks pass, perform the action
295
+ }
296
+ ```
297
+
298
+ ---
299
+
300
+ ### Notes
301
+
302
+ - `PermissionService` throws a `DomainForbiddenError` if the required permissions are missing. Always be prepared to handle this exception or let it be caught by a global exception filter.
303
+
304
+ # Filters
305
+
306
+ ## AppExceptionFilter Overview
307
+
308
+ The `AppExceptionFilter` class implements the `ExceptionFilter` interface and is used for handling exceptions in a NestJS application.
309
+
310
+ ### Functionality
311
+
312
+ The filter intercepts all exceptions and processes them as follows:
313
+
314
+ - For `HttpException`, it uses the original HTTP status and message.
315
+ - For `DomainValidationError`, it sets a 400 (Bad Request) status.
316
+ - For `DomainForbiddenError`, it sets a 403 (Forbidden) status.
317
+ - For all other exceptions, it sets a 500 (Internal Server Error) status.
318
+
319
+ ### Logging
320
+
321
+ The filter logs exception details (stack trace or message) using `Logger.error()`.
322
+
323
+ ### Response
324
+
325
+ The filter returns an HTTP response with the appropriate status code and optionally a JSON object containing error details.
326
+
327
+ ### Usage
328
+
329
+ To use this filter globally in a NestJS application, register it in the main module:
330
+
331
+ ```typescript
332
+ import { Module } from '@nestjs/common';
333
+ import { APP_FILTER } from '@nestjs/core';
334
+
335
+ import { AppExceptionFilter } from '@smartsoft001/nestjs';
336
+
337
+ @Module({
338
+ providers: [
339
+ {
340
+ provide: APP_FILTER,
341
+ useClass: AppExceptionFilter,
342
+ },
343
+ ],
344
+ })
345
+ export class AppModule {}
346
+ ```
347
+
348
+ This filter ensures consistent error handling throughout the application, mapping different exception types to appropriate HTTP status codes and formatting responses accordingly.
package/jest.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ export default {
2
+ displayName: 'nestjs',
3
+ preset: '../../../jest.preset.js',
4
+ testEnvironment: 'node',
5
+ transform: {
6
+ '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
7
+ },
8
+ moduleFileExtensions: ['ts', 'js', 'html'],
9
+ coverageDirectory: '../../../coverage/packages/shared/nestjs',
10
+ };
package/package.json CHANGED
@@ -1,50 +1,16 @@
1
1
  {
2
2
  "name": "@smartsoft001/nestjs",
3
- "version": "1.1.91",
4
- "description": "Utils to nestjs",
5
- "repository": {
6
- "type": "git",
7
- "url": "git+https://github.com/emiljuchnikowski/smartsoft.git"
8
- },
9
- "keywords": [
10
- "smartsoft",
11
- "oauth",
12
- "nestjs"
13
- ],
14
- "author": "Emil Juchnikowski",
15
- "license": "MIT",
16
- "bugs": {
17
- "url": "https://github.com/emiljuchnikowski/smartsoft/issues"
18
- },
19
- "homepage": "https://github.com/emiljuchnikowski/smartsoft#readme",
20
- "dependencies": {
21
- "@angular/common": "16.1.3",
22
- "@angular/core": "16.1.3",
23
- "@angular/platform-browser-dynamic": "16.1.3",
24
- "@nestjs/axios": "3.0.0",
25
- "@nestjs/common": "^10.0.5",
26
- "@nestjs/passport": "^10.0.0",
27
- "@nestjs/terminus": "^10.0.1",
28
- "@nestjs/typeorm": "^10.0.0",
29
- "flatted": "^3.2.4",
30
- "guid-typescript": "1.0.9",
31
- "lodash": "^4.17.20",
32
- "md5": "2.3.0",
33
- "mongodb": "5.6.0",
34
- "passport-jwt": "4.0.0",
35
- "reflect-metadata": "0.1.13",
36
- "rxjs": "7.8.1"
37
- },
38
- "peerDependencies": {
39
- "@smartsoft001/crud-shell-dtos": "1.1.91",
40
- "@smartsoft001/domain-core": "1.1.91",
41
- "@smartsoft001/models": "1.1.91",
42
- "@smartsoft001/mongo": "1.1.91",
43
- "@smartsoft001/users": "1.1.91",
44
- "@smartsoft001/utils": "1.1.91",
45
- "util": "0.12.5",
46
- "tslib": "2.5.3"
47
- },
3
+ "version": "2.60.0",
4
+ "type": "commonjs",
48
5
  "main": "./src/index.js",
49
- "types": "./src/index.d.ts"
6
+ "types": "./src/index.d.ts",
7
+ "dependencies": {
8
+ "tslib": "^2.3.0",
9
+ "passport-jwt": "^4.0.1",
10
+ "@nestjs/passport": "^11.0.5",
11
+ "@nestjs/common": "^11.0.7",
12
+ "@nestjs/testing": "^11.0.7",
13
+ "@smartsoft001/domain-core": "2.60.0",
14
+ "@smartsoft001/users": "2.60.0"
15
+ }
50
16
  }
package/project.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "nestjs",
3
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "packages/shared/nestjs/src",
5
+ "projectType": "library",
6
+ "tags": [],
7
+ "targets": {
8
+ "build": {
9
+ "executor": "@nx/js:tsc",
10
+ "outputs": ["{options.outputPath}"],
11
+ "options": {
12
+ "outputPath": "dist/packages/shared/nestjs",
13
+ "main": "packages/shared/nestjs/src/index.ts",
14
+ "tsConfig": "packages/shared/nestjs/tsconfig.lib.json",
15
+ "assets": ["packages/shared/nestjs/*.md"]
16
+ }
17
+ },
18
+ "lint": {
19
+ "executor": "@nx/eslint:lint"
20
+ },
21
+ "test": {
22
+ "executor": "@nx/jest:jest",
23
+ "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
24
+ "options": {
25
+ "jestConfig": "packages/shared/nestjs/jest.config.ts"
26
+ }
27
+ },
28
+ "deploy": {
29
+ "executor": "ngx-deploy-npm:deploy",
30
+ "options": {
31
+ "access": "public",
32
+ "distFolderPath": "dist/packages/shared/nestjs"
33
+ },
34
+ "dependsOn": ["build"]
35
+ }
36
+ }
37
+ }
@@ -1,5 +1,5 @@
1
- export * from "./lib/filters";
2
- export * from './lib/decorators';
3
- export * from './lib/shared.module';
4
1
  export * from './lib/shared.config';
2
+ export * from './lib/shared.module';
3
+ export * from './lib/filters';
4
+ export * from './lib/decorators';
5
5
  export * from './lib/auth';
@@ -1 +1,2 @@
1
+ export * from './jwt.strategy';
1
2
  export * from './permission.service';
@@ -0,0 +1,24 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { PassportStrategy } from '@nestjs/passport';
3
+ import { ExtractJwt, Strategy } from 'passport-jwt';
4
+
5
+ import { SharedConfig } from '../shared.config';
6
+
7
+ @Injectable()
8
+ export class JwtStrategy extends PassportStrategy(Strategy) {
9
+ constructor(private config: SharedConfig) {
10
+ super({
11
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
12
+ ignoreExpiration: false,
13
+ secretOrKey: config.tokenConfig?.secretOrPrivateKey as string,
14
+ });
15
+ }
16
+
17
+ async validate(payload: any) {
18
+ return {
19
+ ...payload,
20
+ permissions: payload.permissions,
21
+ username: payload.sub,
22
+ };
23
+ }
24
+ }
@@ -0,0 +1,61 @@
1
+ import { Test, TestingModule } from '@nestjs/testing';
2
+ import { DomainForbiddenError } from '@smartsoft001/domain-core';
3
+ import { IUser } from '@smartsoft001/users';
4
+
5
+ import { PermissionService } from './permission.service';
6
+ import { SharedConfig } from '../shared.config';
7
+
8
+ describe('shared-nestjs: PermissionService', () => {
9
+ let service: PermissionService;
10
+ let config: SharedConfig;
11
+
12
+ beforeEach(async () => {
13
+ config = {
14
+ permissions: {
15
+ create: ['admin', 'editor'],
16
+ read: ['admin', 'editor', 'viewer'],
17
+ update: ['admin', 'editor'],
18
+ delete: ['admin'],
19
+ },
20
+ };
21
+
22
+ const module: TestingModule = await Test.createTestingModule({
23
+ providers: [
24
+ PermissionService,
25
+ { provide: SharedConfig, useValue: config },
26
+ ],
27
+ }).compile();
28
+
29
+ service = module.get<PermissionService>(PermissionService);
30
+ });
31
+
32
+ it('should be defined', () => {
33
+ expect(service).toBeDefined();
34
+ });
35
+
36
+ it('should allow access if user has the required permission', () => {
37
+ const user: IUser = { username: 'testuser', permissions: ['admin'] };
38
+ expect(() => service.valid('create', user)).not.toThrow();
39
+ });
40
+
41
+ it('should throw DomainForbiddenError if user does not have the required permission', () => {
42
+ const user: IUser = { username: 'testuser', permissions: ['viewer'] };
43
+ expect(() => service.valid('create', user)).toThrow(DomainForbiddenError);
44
+ });
45
+
46
+ it('should not throw if permissions config is not defined', () => {
47
+ config.permissions = undefined;
48
+ const user: IUser = { username: 'testuser', permissions: ['admin'] };
49
+ expect(() => service.valid('create', user)).not.toThrow();
50
+ });
51
+
52
+ it('should not throw if permission type config is not defined', () => {
53
+ const user: IUser = { username: 'testuser', permissions: ['admin'] };
54
+ expect(() => service.valid('nonexistent', user)).not.toThrow();
55
+ });
56
+
57
+ it('should throw DomainForbiddenError if user permissions are not defined', () => {
58
+ const user: IUser = { username: 'testuser', permissions: [] };
59
+ expect(() => service.valid('create', user)).toThrow(DomainForbiddenError);
60
+ });
61
+ });
@@ -0,0 +1,34 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { DomainForbiddenError } from '@smartsoft001/domain-core';
3
+ import { IUser } from '@smartsoft001/users';
4
+
5
+ import { PermissionType, SharedConfig } from '../shared.config';
6
+
7
+ /**
8
+ * Service to handle permission validation for users.
9
+ *
10
+ * @class PermissionService
11
+ */
12
+ @Injectable()
13
+ export class PermissionService {
14
+ constructor(private config: SharedConfig) {}
15
+
16
+ /**
17
+ * Validates if the user has the required permissions for a given type.
18
+ * @param {PermissionType} type - The type of permission to validate.
19
+ * @param {IUser} user - The user object containing permissions.
20
+ * @throws {DomainForbiddenError} If the user does not have the required permissions.
21
+ */
22
+ valid(type: PermissionType, user: IUser): void {
23
+ if (!this.config.permissions) return;
24
+
25
+ const typeConfig = this.config.permissions[type];
26
+
27
+ if (!typeConfig) return;
28
+
29
+ if (!user.permissions) throw new DomainForbiddenError(`Context forbidden`);
30
+
31
+ if (!typeConfig.some((tc) => user.permissions.some((up) => tc === up)))
32
+ throw new DomainForbiddenError(`Context forbidden`);
33
+ }
34
+ }
@@ -0,0 +1,26 @@
1
+ import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2
+
3
+ /**
4
+ * Custom decorator to extract the user object from the request.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { Controller, Get } from '@nestjs/common';
9
+ *
10
+ * import { IUser } from '@smartsoft001/users';
11
+ *
12
+ * import { User } from './user.decorator';
13
+ *
14
+ * @Controller('profile')
15
+ * export class ProfileController {
16
+ * @Get()
17
+ * getProfile(@User() user: IUser) {
18
+ * return user;
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export const User = createParamDecorator((_, context: ExecutionContext) => {
24
+ const [req] = context.getArgs();
25
+ return req.user;
26
+ });