@solidstarters/solid-core 1.2.153 → 1.2.154
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/config/iam.config.d.ts +6 -0
- package/dist/config/iam.config.d.ts.map +1 -1
- package/dist/config/iam.config.js +3 -0
- package/dist/config/iam.config.js.map +1 -1
- package/dist/constants/error-messages.js +1 -1
- package/dist/constants/error-messages.js.map +1 -1
- package/dist/controllers/ai-interaction.controller.d.ts +2 -1
- package/dist/controllers/ai-interaction.controller.d.ts.map +1 -1
- package/dist/controllers/ai-interaction.controller.js +5 -3
- package/dist/controllers/ai-interaction.controller.js.map +1 -1
- package/dist/controllers/authentication.controller.d.ts +6 -6
- package/dist/controllers/authentication.controller.d.ts.map +1 -1
- package/dist/controllers/authentication.controller.js +15 -7
- package/dist/controllers/authentication.controller.js.map +1 -1
- package/dist/controllers/email-template.controller.d.ts.map +1 -1
- package/dist/controllers/email-template.controller.js +3 -0
- package/dist/controllers/email-template.controller.js.map +1 -1
- package/dist/controllers/google-authentication.controller.d.ts.map +1 -1
- package/dist/controllers/google-authentication.controller.js +3 -0
- package/dist/controllers/google-authentication.controller.js.map +1 -1
- package/dist/controllers/media.controller.d.ts.map +1 -1
- package/dist/controllers/media.controller.js +4 -0
- package/dist/controllers/media.controller.js.map +1 -1
- package/dist/controllers/model-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/model-metadata.controller.js +5 -0
- package/dist/controllers/model-metadata.controller.js.map +1 -1
- package/dist/controllers/otp-authentication.controller.d.ts.map +1 -1
- package/dist/controllers/otp-authentication.controller.js +3 -0
- package/dist/controllers/otp-authentication.controller.js.map +1 -1
- package/dist/controllers/service.controller.d.ts.map +1 -1
- package/dist/controllers/service.controller.js +4 -0
- package/dist/controllers/service.controller.js.map +1 -1
- package/dist/controllers/sms-template.controller.d.ts +1 -1
- package/dist/controllers/sms-template.controller.d.ts.map +1 -1
- package/dist/controllers/sms-template.controller.js +6 -3
- package/dist/controllers/sms-template.controller.js.map +1 -1
- package/dist/decorators/solid-password.decorator.d.ts +12 -0
- package/dist/decorators/solid-password.decorator.d.ts.map +1 -0
- package/dist/decorators/solid-password.decorator.js +43 -0
- package/dist/decorators/solid-password.decorator.js.map +1 -0
- package/dist/dtos/change-password.dto.d.ts.map +1 -1
- package/dist/dtos/change-password.dto.js +2 -0
- package/dist/dtos/change-password.dto.js.map +1 -1
- package/dist/dtos/confirm-forgot-password.dto.d.ts.map +1 -1
- package/dist/dtos/confirm-forgot-password.dto.js +2 -0
- package/dist/dtos/confirm-forgot-password.dto.js.map +1 -1
- package/dist/helpers/cors.helper.d.ts +4 -0
- package/dist/helpers/cors.helper.d.ts.map +1 -0
- package/dist/helpers/cors.helper.js +33 -0
- package/dist/helpers/cors.helper.js.map +1 -0
- package/dist/helpers/security.helper.d.ts +9 -0
- package/dist/helpers/security.helper.d.ts.map +1 -0
- package/dist/helpers/security.helper.js +46 -0
- package/dist/helpers/security.helper.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/repository/chatter-message-details.repository.d.ts +16 -0
- package/dist/repository/chatter-message-details.repository.d.ts.map +1 -0
- package/dist/repository/chatter-message-details.repository.js +62 -0
- package/dist/repository/chatter-message-details.repository.js.map +1 -0
- package/dist/repository/chatter-message.repository.d.ts +16 -0
- package/dist/repository/chatter-message.repository.d.ts.map +1 -0
- package/dist/repository/chatter-message.repository.js +61 -0
- package/dist/repository/chatter-message.repository.js.map +1 -0
- package/dist/repository/security-rule.repository.d.ts +1 -1
- package/dist/repository/security-rule.repository.d.ts.map +1 -1
- package/dist/repository/security-rule.repository.js +2 -2
- package/dist/repository/security-rule.repository.js.map +1 -1
- package/dist/repository/solid-base.repository.d.ts +6 -1
- package/dist/repository/solid-base.repository.d.ts.map +1 -1
- package/dist/repository/solid-base.repository.js +35 -0
- package/dist/repository/solid-base.repository.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +9 -0
- package/dist/services/ai-interaction.service.d.ts +2 -4
- package/dist/services/ai-interaction.service.d.ts.map +1 -1
- package/dist/services/ai-interaction.service.js +4 -8
- package/dist/services/ai-interaction.service.js.map +1 -1
- package/dist/services/authentication.service.d.ts +6 -2
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +94 -43
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/chatter-message-details.service.d.ts +4 -3
- package/dist/services/chatter-message-details.service.d.ts.map +1 -1
- package/dist/services/chatter-message-details.service.js +2 -3
- package/dist/services/chatter-message-details.service.js.map +1 -1
- package/dist/services/chatter-message.service.d.ts +3 -2
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js +2 -2
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +4 -1
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/model-metadata.service.d.ts.map +1 -1
- package/dist/services/model-metadata.service.js +4 -1
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/request-context.service.d.ts +3 -0
- package/dist/services/request-context.service.d.ts.map +1 -1
- package/dist/services/request-context.service.js +6 -0
- package/dist/services/request-context.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +23 -5
- package/dist/solid-core.module.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -1
- package/src/config/iam.config.ts +3 -0
- package/src/constants/error-messages.ts +1 -1
- package/src/controllers/ai-interaction.controller.ts +4 -2
- package/src/controllers/authentication.controller.ts +16 -10
- package/src/controllers/email-template.controller.ts +4 -1
- package/src/controllers/google-authentication.controller.ts +4 -0
- package/src/controllers/media.controller.ts +5 -1
- package/src/controllers/model-metadata.controller.ts +7 -2
- package/src/controllers/otp-authentication.controller.ts +4 -1
- package/src/controllers/service.controller.ts +5 -1
- package/src/controllers/sms-template.controller.ts +8 -7
- package/src/decorators/solid-password.decorator.ts +51 -0
- package/src/dtos/change-password.dto.ts +2 -0
- package/src/dtos/confirm-forgot-password.dto.ts +2 -0
- package/src/helpers/cors.helper.ts +34 -0
- package/src/helpers/security.helper.ts +53 -0
- package/src/index.ts +3 -0
- package/src/repository/chatter-message-details.repository.ts +109 -0
- package/src/repository/chatter-message.repository.ts +68 -0
- package/src/repository/security-rule.repository.ts +2 -2
- package/src/repository/solid-base.repository.ts +66 -0
- package/src/seeders/seed-data/email-templates/password-changed.handlebars.html +158 -0
- package/src/seeders/seed-data/solid-core-metadata.json +9 -0
- package/src/services/ai-interaction.service.ts +5 -5
- package/src/services/authentication.service.ts +181 -56
- package/src/services/chatter-message-details.service.ts +3 -2
- package/src/services/chatter-message.service.ts +3 -2
- package/src/services/crud.service.ts +7 -2
- package/src/services/model-metadata.service.ts +15 -1
- package/src/services/request-context.service.ts +9 -0
- package/src/solid-core.module.ts +29 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidstarters/solid-core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.154",
|
|
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",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"@elasticemail/elasticemail-client": "^4.0.23",
|
|
40
40
|
"@hapi/joi": "^17.1.1",
|
|
41
41
|
"@nestjs/schedule": "^6.0.0",
|
|
42
|
+
"@nestjs/throttler": "^6.4.0",
|
|
42
43
|
"amqplib": "^0.10.4",
|
|
43
44
|
"axios": "^1.7.0",
|
|
44
45
|
"bcrypt": "^5.1.1",
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"exceljs": "^4.4.0",
|
|
51
52
|
"fast-csv": "^5.0.2",
|
|
52
53
|
"handlebars": "^4.7.8",
|
|
54
|
+
"helmet": "^8.1.0",
|
|
53
55
|
"ioredis": "^5.4.1",
|
|
54
56
|
"locale-codes": "^1.3.1",
|
|
55
57
|
"lodash": "^4.17.21",
|
package/src/config/iam.config.ts
CHANGED
|
@@ -9,10 +9,13 @@ export const iamConfig = registerAs('iam', () => {
|
|
|
9
9
|
activateUserOnRegistration: (process.env.IAM_ACTIVATE_USER_ON_REGISTRATION ?? 'true') === 'true',
|
|
10
10
|
autoLoginUserOnRegistration: (process.env.IAM_AUTO_LOGIN_USER_ON_REGISTRATION ?? 'false') === 'true',
|
|
11
11
|
otpExpiry: parseInt(process.env.IAM_OTP_EXPIRY ?? '10'),
|
|
12
|
+
forgotPasswordVerificationTokenExpiry: parseInt(process.env.IAM_FORGOT_PASSWORD_VERIFICATION_TOKEN_EXPIRY ?? '10'),
|
|
12
13
|
defaultRole: process.env.IAM_DEFAULT_ROLE ?? 'Public',
|
|
13
14
|
dummyOtp: process.env.IAM_OTP_DUMMY,
|
|
14
15
|
forgotPasswordSendVerificationTokenOn: process.env.IAM_FORGOT_PASSWORD_SEND_VERIFICATION_TOKEN_ON ?? 'email',
|
|
15
16
|
forceChangePasswordOnFirstLogin:true,
|
|
17
|
+
PASSWORD_REGEX: process.env.PASSWORD_REGEX || '^$|^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^\\da-zA-Z]).*$',
|
|
18
|
+
PASSWORD_COMPLEXITY_DESC : process.env.PASSWORD_COMPLEXITY_DESC || 'Password must contain at least one uppercase, one lowercase, one number, and one special character.',
|
|
16
19
|
googleOauth: {
|
|
17
20
|
clientID: process.env.IAM_GOOGLE_OAUTH_CLIENT_ID,
|
|
18
21
|
clientSecret: process.env.IAM_GOOGLE_OAUTH_CLIENT_SECRET,
|
|
@@ -21,7 +21,7 @@ export const ERROR_MESSAGES = {
|
|
|
21
21
|
USER_ID_MISMATCH: "User ID's do not match.",
|
|
22
22
|
USERNAME_MISMATCH: "User username's do not match.",
|
|
23
23
|
INCORRECT_CURRENT_PASSWORD: 'Incorrect current password specified.',
|
|
24
|
-
PASSWORD_REUSED: '
|
|
24
|
+
PASSWORD_REUSED: 'Try a different password',
|
|
25
25
|
INVALID_VERIFICATION_TOKEN: 'Invalid verification token',
|
|
26
26
|
ACCESS_DENIED: 'Access denied',
|
|
27
27
|
INVALID_USER_PROFILE: 'Invalid user profile',
|
|
@@ -5,6 +5,8 @@ import { AiInteractionService } from '../services/ai-interaction.service';
|
|
|
5
5
|
import { CreateAiInteractionDto } from '../dtos/create-ai-interaction.dto';
|
|
6
6
|
import { UpdateAiInteractionDto } from '../dtos/update-ai-interaction.dto';
|
|
7
7
|
import { InvokeAiPromptDto } from '../dtos/invoke-ai-prompt.dto';
|
|
8
|
+
import { ActiveUser } from 'src/decorators/active-user.decorator';
|
|
9
|
+
import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
|
|
8
10
|
|
|
9
11
|
enum ShowSoftDeleted {
|
|
10
12
|
INCLUSIVE = "inclusive",
|
|
@@ -92,8 +94,8 @@ export class AiInteractionController {
|
|
|
92
94
|
|
|
93
95
|
@ApiBearerAuth("jwt")
|
|
94
96
|
@Post('/trigger-mcp-client-job')
|
|
95
|
-
async triggerMcpClientJob(@Body() dto: InvokeAiPromptDto) {
|
|
96
|
-
return this.service.triggerMcpClientJob(dto.prompt);
|
|
97
|
+
async triggerMcpClientJob(@Body() dto: InvokeAiPromptDto, @ActiveUser() activeUser: ActiveUserData) {
|
|
98
|
+
return this.service.triggerMcpClientJob(dto.prompt, activeUser.sub);
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
@ApiBearerAuth("jwt")
|
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
import { Body, Controller, Get, HttpCode, HttpStatus, Logger, Post, Res, UseGuards } from '@nestjs/common';
|
|
2
|
-
import { AuthenticationService } from '../services/authentication.service';
|
|
3
|
-
import { SignInDto } from '../dtos/sign-in.dto';
|
|
4
|
-
import { SignUpDto } from '../dtos/sign-up.dto';
|
|
5
|
-
import { Response } from 'express';
|
|
6
|
-
import { RefreshTokenDto } from '../dtos/refresh-token.dto';
|
|
7
2
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
|
8
|
-
import {
|
|
3
|
+
import { SkipThrottle, ThrottlerGuard } from '@nestjs/throttler';
|
|
4
|
+
import { Response } from 'express';
|
|
5
|
+
import { ActiveUser } from "../decorators/active-user.decorator";
|
|
9
6
|
import { Public } from '../decorators/public.decorator';
|
|
10
|
-
import { InitiateForgotPasswordDto } from '../dtos/initiate-forgot-password.dto';
|
|
11
|
-
import { ConfirmForgotPasswordDto } from '../dtos/confirm-forgot-password.dto';
|
|
12
7
|
import { ChangePasswordDto } from "../dtos/change-password.dto";
|
|
13
|
-
import {
|
|
8
|
+
import { ConfirmForgotPasswordDto } from '../dtos/confirm-forgot-password.dto';
|
|
9
|
+
import { InitiateForgotPasswordDto } from '../dtos/initiate-forgot-password.dto';
|
|
10
|
+
import { RefreshTokenDto } from '../dtos/refresh-token.dto';
|
|
11
|
+
import { SignInDto } from '../dtos/sign-in.dto';
|
|
12
|
+
import { SignUpDto } from '../dtos/sign-up.dto';
|
|
14
13
|
import { ActiveUserData } from "../interfaces/active-user-data.interface";
|
|
15
|
-
import {
|
|
14
|
+
import { AuthenticationService } from '../services/authentication.service';
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
// @Auth(AuthType.None)
|
|
19
18
|
@Controller('iam')
|
|
20
19
|
@ApiTags("Iam")
|
|
20
|
+
@UseGuards(ThrottlerGuard)
|
|
21
|
+
@SkipThrottle({login: true, short: true, burst: true, sustained: true}) // disable all sets by default for this controller
|
|
21
22
|
export class AuthenticationController {
|
|
22
23
|
private readonly logger = new Logger(AuthenticationController.name);
|
|
23
24
|
|
|
24
25
|
constructor(private readonly authService: AuthenticationService) { }
|
|
25
26
|
|
|
26
27
|
@Public()
|
|
28
|
+
@SkipThrottle({ login: false }) //Enable the login throttle only
|
|
27
29
|
@Post('register')
|
|
28
30
|
signUp(@Body() signUpDto: SignUpDto) {
|
|
29
31
|
return this.authService.signUp(signUpDto);
|
|
@@ -37,6 +39,7 @@ export class AuthenticationController {
|
|
|
37
39
|
|
|
38
40
|
@Public()
|
|
39
41
|
// @UseGuards(LocalAuthGuard)
|
|
42
|
+
@SkipThrottle({ login: false }) //Enable the login throttle only
|
|
40
43
|
@HttpCode(HttpStatus.OK) // by default @Post does 201, we wanted 200 - hence using @HttpCode(HttpStatus.OK)
|
|
41
44
|
@Post('authenticate')
|
|
42
45
|
async signIn(
|
|
@@ -59,6 +62,7 @@ export class AuthenticationController {
|
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
@Public()
|
|
65
|
+
@SkipThrottle({ login: false }) //Enable the login throttle only
|
|
62
66
|
@HttpCode(HttpStatus.OK) // changed since the default is 201
|
|
63
67
|
@Post('refresh-tokens')
|
|
64
68
|
refreshTokens(@Body() refreshTokenDto: RefreshTokenDto) {
|
|
@@ -66,12 +70,14 @@ export class AuthenticationController {
|
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
@Public()
|
|
73
|
+
@SkipThrottle({ login: false }) //Enable the login throttle only
|
|
69
74
|
@Post('initiate/forgot-password')
|
|
70
75
|
initiateForgotPassword(@Body() initiateForgotPasswordDto: InitiateForgotPasswordDto) {
|
|
71
76
|
return this.authService.initiateForgotPassword(initiateForgotPasswordDto);
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
@Public()
|
|
80
|
+
@SkipThrottle({ login: false }) //Enable the login throttle only
|
|
75
81
|
@Post('confirm/forgot-password')
|
|
76
82
|
confirmForgotPassword(@Body() confirmForgotPasswordDto: ConfirmForgotPasswordDto) {
|
|
77
83
|
return this.authService.confirmForgotPassword(confirmForgotPasswordDto);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Body, Controller, Delete, Get, Header, Param, Patch, Post, Put, Query, UploadedFiles, UseInterceptors } from '@nestjs/common';
|
|
1
|
+
import { Body, Controller, Delete, Get, Header, Param, Patch, Post, Put, Query, UploadedFiles, UseGuards, UseInterceptors } from '@nestjs/common';
|
|
2
2
|
import { ApiBearerAuth, ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
3
3
|
import { PaginationQueryDto } from 'src/dtos/pagination-query.dto';
|
|
4
4
|
import { Roles } from 'src/decorators/roles.decorator';
|
|
@@ -13,10 +13,13 @@ import { Public } from 'src/decorators/public.decorator';
|
|
|
13
13
|
// import { Mailgen } from 'mailgen';
|
|
14
14
|
import Mailgen = require('mailgen');
|
|
15
15
|
import { AnyFilesInterceptor } from '@nestjs/platform-express';
|
|
16
|
+
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@Controller('email-template')
|
|
19
20
|
@ApiTags("Common")
|
|
21
|
+
@UseGuards(ThrottlerGuard)
|
|
22
|
+
@SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
20
23
|
export class EmailTemplateController {
|
|
21
24
|
constructor(private readonly service: EmailTemplateService) { }
|
|
22
25
|
|
|
@@ -10,11 +10,15 @@ import { UserService } from '../services/user.service';
|
|
|
10
10
|
import { Public } from '../decorators/public.decorator';
|
|
11
11
|
import { iamConfig } from '../config/iam.config';
|
|
12
12
|
import { isGoogleOAuthConfigured } from 'src/helpers/google-oauth.helper';
|
|
13
|
+
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
14
|
+
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
@Auth(AuthType.None)
|
|
16
18
|
@Controller('iam/google')
|
|
17
19
|
@ApiTags("Iam")
|
|
20
|
+
@UseGuards(ThrottlerGuard)
|
|
21
|
+
@SkipThrottle({ login: false, short: false, burst: true, sustained: true }) //Enable the login throttle only
|
|
18
22
|
export class GoogleAuthenticationController {
|
|
19
23
|
constructor(
|
|
20
24
|
@Inject(iamConfig.KEY) private iamConfiguration: ConfigType<typeof iamConfig>,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { Controller, Post, Body, Param, UploadedFiles, UseInterceptors, Put, Get, Query, Delete, Patch } from '@nestjs/common';
|
|
1
|
+
import { Controller, Post, Body, Param, UploadedFiles, UseInterceptors, Put, Get, Query, Delete, Patch, UseGuards } from '@nestjs/common';
|
|
2
2
|
import { AnyFilesInterceptor } from "@nestjs/platform-express";
|
|
3
3
|
import { ApiBearerAuth, ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
4
4
|
import { Public } from 'src/decorators/public.decorator';
|
|
5
5
|
import { MediaService } from 'src/services/media.service';
|
|
6
6
|
import { CreateMediaDto } from 'src/dtos/create-media.dto';
|
|
7
7
|
import { UpdateMediaDto } from 'src/dtos/update-media.dto';
|
|
8
|
+
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
8
9
|
|
|
9
10
|
enum ShowSoftDeleted {
|
|
10
11
|
INCLUSIVE = "inclusive",
|
|
@@ -13,6 +14,8 @@ enum ShowSoftDeleted {
|
|
|
13
14
|
|
|
14
15
|
@ApiTags('Solid Core')
|
|
15
16
|
@Controller('media')
|
|
17
|
+
@UseGuards(ThrottlerGuard)
|
|
18
|
+
@SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all
|
|
16
19
|
export class MediaController {
|
|
17
20
|
constructor(private readonly service: MediaService) {}
|
|
18
21
|
|
|
@@ -46,6 +49,7 @@ export class MediaController {
|
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
@Public()
|
|
52
|
+
@SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
49
53
|
@ApiBearerAuth("jwt")
|
|
50
54
|
@Post('/upload')
|
|
51
55
|
@UseInterceptors(AnyFilesInterceptor())
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { Body, Controller, Delete, Get, Logger, Param, ParseIntPipe, Post, Put, Query } from '@nestjs/common';
|
|
1
|
+
import { Body, Controller, Delete, Get, Logger, Param, ParseIntPipe, Post, Put, Query, UseGuards } from '@nestjs/common';
|
|
2
2
|
import { ApiBearerAuth, ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
3
3
|
import { Public } from 'src/decorators/public.decorator';
|
|
4
4
|
import { BasicFilterDto } from '../dtos/basic-filters.dto';
|
|
5
5
|
import { CreateModelMetadataDto } from '../dtos/create-model-metadata.dto';
|
|
6
6
|
import { UpdateModelMetaDataDto } from '../dtos/update-model-metadata.dto';
|
|
7
7
|
import { ModelMetadataService } from '../services/model-metadata.service';
|
|
8
|
+
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
8
9
|
|
|
9
10
|
@Controller('model-metadata')
|
|
10
11
|
@ApiTags("App Builder")
|
|
12
|
+
@UseGuards(ThrottlerGuard)
|
|
13
|
+
@SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all
|
|
11
14
|
export class ModelMetadataController {
|
|
12
15
|
private logger = new Logger('ModelMetadataController');
|
|
13
16
|
|
|
@@ -32,6 +35,7 @@ export class ModelMetadataController {
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
@Public()
|
|
38
|
+
@SkipThrottle({ burst: false, short: true, login: true, sustained: true }) //Enable burst only
|
|
35
39
|
@Get('public')
|
|
36
40
|
async findManyPublic() {
|
|
37
41
|
const basicFilterDto: BasicFilterDto = {
|
|
@@ -40,7 +44,7 @@ export class ModelMetadataController {
|
|
|
40
44
|
offset: 0,
|
|
41
45
|
filters: [],
|
|
42
46
|
groupBy: [],
|
|
43
|
-
populate: [],
|
|
47
|
+
populate: [],
|
|
44
48
|
populateMedia: [],
|
|
45
49
|
sort: []
|
|
46
50
|
}
|
|
@@ -61,6 +65,7 @@ export class ModelMetadataController {
|
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
@Public()
|
|
68
|
+
@SkipThrottle({ short: false, burst: true, login: true, sustained: true }) //Enable short only
|
|
64
69
|
@Post('/update-user-key')
|
|
65
70
|
updateUserKey(@Body() data: any) {
|
|
66
71
|
return this.modelMetadataService.updateUserKey(data);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Body, Controller, HttpCode, HttpStatus, Post, Res } from '@nestjs/common';
|
|
1
|
+
import { Body, Controller, HttpCode, HttpStatus, Post, Res, UseGuards } from '@nestjs/common';
|
|
2
2
|
import { ApiTags } from '@nestjs/swagger';
|
|
3
3
|
import { Response } from 'express';
|
|
4
4
|
import { Auth } from '../decorators/auth.decorator';
|
|
@@ -8,11 +8,14 @@ import { OTPSignInDto } from '../dtos/otp-sign-in.dto';
|
|
|
8
8
|
import { OTPSignUpDto } from '../dtos/otp-sign-up.dto';
|
|
9
9
|
import { AuthType } from '../enums/auth-type.enum';
|
|
10
10
|
import { AuthenticationService } from '../services/authentication.service';
|
|
11
|
+
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@Auth(AuthType.None)
|
|
14
15
|
@Controller('iam/otp')
|
|
15
16
|
@ApiTags("Iam")
|
|
17
|
+
@UseGuards(ThrottlerGuard)
|
|
18
|
+
@SkipThrottle({ login: false, short: true, burst: true, sustained: true }) //Enable the login throttle only
|
|
16
19
|
export class OTPAuthenticationController {
|
|
17
20
|
constructor(private readonly authService: AuthenticationService) { }
|
|
18
21
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { Body, Controller, Get, Logger, Post } from '@nestjs/common';
|
|
1
|
+
import { Body, Controller, Get, Logger, Post, UseGuards } from '@nestjs/common';
|
|
2
2
|
import { DiscoveryService, MetadataScanner, Reflector } from '@nestjs/core';
|
|
3
3
|
import { Public } from 'src/decorators/public.decorator';
|
|
4
4
|
import { SolidRegistry } from '../helpers/solid-registry';
|
|
5
5
|
import { ApiTags } from '@nestjs/swagger';
|
|
6
|
+
import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
@Controller('')
|
|
9
10
|
@ApiTags("Common")
|
|
11
|
+
@UseGuards(ThrottlerGuard)
|
|
12
|
+
@SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all
|
|
10
13
|
export class ServiceController {
|
|
11
14
|
private readonly logger = new Logger(ServiceController.name);
|
|
12
15
|
|
|
@@ -21,6 +24,7 @@ export class ServiceController {
|
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
@Public()
|
|
27
|
+
@SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
24
28
|
@Post('seed')
|
|
25
29
|
async seedData(@Body() seedData: any) {
|
|
26
30
|
const seeder = this.solidRegistry
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { Body, Controller, Delete, Get, Param,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { Body, Controller, Delete, Get, Param, Post, Put, Query, UploadedFiles, UseGuards, UseInterceptors } from '@nestjs/common';
|
|
2
|
+
import { AnyFilesInterceptor } from '@nestjs/platform-express';
|
|
3
|
+
import { ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
4
|
+
import { SkipThrottle, ThrottlerGuard } from '@nestjs/throttler';
|
|
5
|
+
import { Public } from 'src/decorators/public.decorator';
|
|
6
6
|
import { CreateSmsTemplateDto } from '../dtos/create-sms-template.dto';
|
|
7
7
|
import { UpdateSmsTemplateDto } from '../dtos/update-sms-template.dto';
|
|
8
|
-
import {
|
|
9
|
-
import { AnyFilesInterceptor } from '@nestjs/platform-express';
|
|
8
|
+
import { SmsTemplateService } from '../services/sms-template.service';
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
@Controller('sms-template')
|
|
13
12
|
@ApiTags("Common")
|
|
13
|
+
@UseGuards(ThrottlerGuard)
|
|
14
|
+
@SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
|
|
14
15
|
export class SmsTemplateController {
|
|
15
16
|
constructor(private readonly service: SmsTemplateService) { }
|
|
16
17
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// solid-password.decorator.ts
|
|
2
|
+
import {
|
|
3
|
+
registerDecorator,
|
|
4
|
+
ValidationArguments,
|
|
5
|
+
ValidationOptions,
|
|
6
|
+
ValidatorConstraint,
|
|
7
|
+
ValidatorConstraintInterface,
|
|
8
|
+
} from 'class-validator';
|
|
9
|
+
import { Injectable } from '@nestjs/common';
|
|
10
|
+
import { iamConfig } from '../config/iam.config';
|
|
11
|
+
|
|
12
|
+
interface SolidPasswordOptions extends ValidationOptions {
|
|
13
|
+
regex?: RegExp | string;
|
|
14
|
+
message ?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@ValidatorConstraint({ async: false })
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class SolidPasswordConstraint implements ValidatorConstraintInterface {
|
|
20
|
+
validate(value: string, args: ValidationArguments) {
|
|
21
|
+
if (!value) return false;
|
|
22
|
+
|
|
23
|
+
const opts = args.constraints[0] as SolidPasswordOptions;
|
|
24
|
+
|
|
25
|
+
// priority: decorator-provided regex → iamConfig().PASSWORD_REGEX
|
|
26
|
+
const regex = opts?.regex || iamConfig().PASSWORD_REGEX;
|
|
27
|
+
|
|
28
|
+
return new RegExp(regex).test(value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
defaultMessage(args?: ValidationArguments): string {
|
|
32
|
+
const opts = args?.constraints?.[0] as SolidPasswordOptions;
|
|
33
|
+
|
|
34
|
+
// Just use the string from decorator if passed, otherwise use iamConfig
|
|
35
|
+
return opts?.message || iamConfig().PASSWORD_COMPLEXITY_DESC;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function SolidPasswordRegex(
|
|
40
|
+
options?: SolidPasswordOptions,
|
|
41
|
+
): PropertyDecorator {
|
|
42
|
+
return (object: Object, propertyName: string) => {
|
|
43
|
+
registerDecorator({
|
|
44
|
+
target: object.constructor,
|
|
45
|
+
propertyName,
|
|
46
|
+
options,
|
|
47
|
+
constraints: [options],
|
|
48
|
+
validator: SolidPasswordConstraint,
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IsNotEmpty } from "class-validator";
|
|
2
|
+
import { SolidPasswordRegex } from "src/decorators/solid-password.decorator";
|
|
2
3
|
|
|
3
4
|
export class ChangePasswordDto {
|
|
4
5
|
@IsNotEmpty()
|
|
@@ -11,5 +12,6 @@ export class ChangePasswordDto {
|
|
|
11
12
|
currentPassword: string;
|
|
12
13
|
|
|
13
14
|
@IsNotEmpty()
|
|
15
|
+
@SolidPasswordRegex({ regex: /^$|^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).*$/})
|
|
14
16
|
newPassword: string;
|
|
15
17
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IsNotEmpty, IsOptional } from "class-validator";
|
|
2
|
+
import { SolidPasswordRegex } from "src/decorators/solid-password.decorator";
|
|
2
3
|
|
|
3
4
|
export class ConfirmForgotPasswordDto {
|
|
4
5
|
@IsNotEmpty()
|
|
@@ -13,5 +14,6 @@ export class ConfirmForgotPasswordDto {
|
|
|
13
14
|
verificationToken: string;
|
|
14
15
|
|
|
15
16
|
@IsNotEmpty()
|
|
17
|
+
@SolidPasswordRegex({ regex: /^$|^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).*$/})
|
|
16
18
|
password: string;
|
|
17
19
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CorsOptions } from 'cors';
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
3
|
+
|
|
4
|
+
/** Build CorsOptions from env; supports wildcards like https://*.example.com */
|
|
5
|
+
export function buildDefaultCorsOptions(configService: ConfigService): CorsOptions {
|
|
6
|
+
const rawOrigins = configService.get<string>('CORS_ORIGINS') ?? '';
|
|
7
|
+
const allowed = rawOrigins.split(',').map(s => s.trim()).filter(Boolean);
|
|
8
|
+
|
|
9
|
+
const escapeRx = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
10
|
+
const patternToRegex = (pattern: string): RegExp => {
|
|
11
|
+
const hasScheme = /^https?:\/\//i.test(pattern);
|
|
12
|
+
const schemePart = hasScheme ? '' : 'https?:\\/\\/';
|
|
13
|
+
if (pattern === '*' || pattern === '.*') return /^.*$/i;
|
|
14
|
+
const escaped = escapeRx(pattern)
|
|
15
|
+
.replace(/^https?:\/\//i, '') // strip scheme if present
|
|
16
|
+
.replace(/\*/g, '[^.]+'); // * => one subdomain segment
|
|
17
|
+
return new RegExp(`^${schemePart}${escaped}(?::\\d+)?$`, 'i');
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const matchers = allowed.map(patternToRegex);
|
|
21
|
+
const isAllowed = (origin: string) =>
|
|
22
|
+
matchers.length > 0 && matchers.some(rx => rx.test(origin));
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
origin: (origin, cb) => {
|
|
26
|
+
if (!origin) return cb(null, true); // allow no-origin (CLI/mobile/internal)
|
|
27
|
+
if (isAllowed(origin)) return cb(null, true);
|
|
28
|
+
return cb(new Error(`Origin ${origin} not allowed by CORS`), false);
|
|
29
|
+
},
|
|
30
|
+
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
|
31
|
+
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
32
|
+
credentials: true,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Environment } from "src/decorators/disallow-in-production.decorator";
|
|
2
|
+
import { HelmetOptions } from "helmet";
|
|
3
|
+
|
|
4
|
+
export function buildDefaultSecurityHeaderOptions(): Readonly<HelmetOptions> {
|
|
5
|
+
return {
|
|
6
|
+
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
|
|
7
|
+
crossOriginEmbedderPolicy: false,
|
|
8
|
+
crossOriginResourcePolicy: { policy: 'same-site' },
|
|
9
|
+
frameguard: { action: 'sameorigin' }, // or { action: 'deny' }
|
|
10
|
+
// HSTS: send only in prod over HTTPS
|
|
11
|
+
hsts:
|
|
12
|
+
process.env.NODE_ENV === Environment.Production
|
|
13
|
+
? { maxAge: 31536000, includeSubDomains: true, preload: true } // 1 year
|
|
14
|
+
: false,
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type Source = 'self' | 'none' | string; // string = an origin like 'https://cdn.example.com'
|
|
19
|
+
type DirectiveConfig = 'self' | 'none' | Source[];
|
|
20
|
+
|
|
21
|
+
export type PermissionsPolicyConfig = Record<string, DirectiveConfig>;
|
|
22
|
+
|
|
23
|
+
export const DEFAULT_PERMISSIONS_POLICY: PermissionsPolicyConfig = {
|
|
24
|
+
camera: 'none',
|
|
25
|
+
microphone: 'none',
|
|
26
|
+
geolocation: 'none',
|
|
27
|
+
fullscreen: 'self', // allow same-origin fullscreen
|
|
28
|
+
payment: 'none',
|
|
29
|
+
accelerometer: 'none',
|
|
30
|
+
autoplay: 'none',
|
|
31
|
+
'clipboard-read': 'none',
|
|
32
|
+
'clipboard-write': 'none',
|
|
33
|
+
gyroscope: 'none',
|
|
34
|
+
magnetometer: 'none',
|
|
35
|
+
usb: 'none',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function buildPermissionsPolicyHeader(
|
|
39
|
+
overrides: Partial<PermissionsPolicyConfig> = {}
|
|
40
|
+
): string {
|
|
41
|
+
const merged: PermissionsPolicyConfig = { ...DEFAULT_PERMISSIONS_POLICY, ...overrides };
|
|
42
|
+
return Object.entries(merged)
|
|
43
|
+
.map(([feature, value]) => `${feature}=${serializeValue(value)}`)
|
|
44
|
+
.join(', ');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function serializeValue(v: DirectiveConfig): string {
|
|
48
|
+
if (v === 'none') return '()';
|
|
49
|
+
if (v === 'self') return '(self)';
|
|
50
|
+
// array of sources: allow 'self' and/or explicit origins
|
|
51
|
+
const parts = v.map(src => (src === 'self' ? 'self' : src)).join(' ');
|
|
52
|
+
return `(${parts})`;
|
|
53
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -134,6 +134,7 @@ export * from './entities/dashboard-question-sql-dataset-config.entity'
|
|
|
134
134
|
export * from './entities/ai-interaction.entity'
|
|
135
135
|
|
|
136
136
|
export * from './enums/auth-type.enum'
|
|
137
|
+
export * from './decorators/disallow-in-production.decorator'
|
|
137
138
|
|
|
138
139
|
export * from './filters/http-exception.filter'
|
|
139
140
|
|
|
@@ -167,6 +168,8 @@ export * from './helpers/field-crud-managers/SelectionStaticFieldCrudManager' //
|
|
|
167
168
|
export * from './helpers/field-crud-managers/ShortTextFieldCrudManager' //rename
|
|
168
169
|
export * from './helpers/field-crud-managers/UUIDFieldCrudManager' //rename
|
|
169
170
|
export * from './helpers/environment.helper'
|
|
171
|
+
export * from './helpers/cors.helper'
|
|
172
|
+
export * from './helpers/security.helper'
|
|
170
173
|
|
|
171
174
|
export * from './services/crud.service'
|
|
172
175
|
export * from './interceptors/logging.interceptor'
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import {
|
|
3
|
+
DataSource,
|
|
4
|
+
QueryRunner,
|
|
5
|
+
SelectQueryBuilder,
|
|
6
|
+
} from 'typeorm';
|
|
7
|
+
import { camelize, classify } from '@angular-devkit/core/src/utils/strings';
|
|
8
|
+
|
|
9
|
+
import { ChatterMessageDetails } from 'src/entities/chatter-message-details.entity';
|
|
10
|
+
import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
|
|
11
|
+
import { RequestContextService } from 'src/services/request-context.service';
|
|
12
|
+
import { SecurityRuleRepository } from './security-rule.repository';
|
|
13
|
+
import { SolidBaseRepository } from './solid-base.repository';
|
|
14
|
+
import {get} from "lodash"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@Injectable()
|
|
18
|
+
export class ChatterMessageDetailsRepository extends SolidBaseRepository<ChatterMessageDetails> {
|
|
19
|
+
constructor(
|
|
20
|
+
readonly dataSource: DataSource,
|
|
21
|
+
readonly requestContextService: RequestContextService,
|
|
22
|
+
readonly securityRuleRepository: SecurityRuleRepository,
|
|
23
|
+
) {
|
|
24
|
+
super(ChatterMessageDetails, dataSource, requestContextService, securityRuleRepository);
|
|
25
|
+
}
|
|
26
|
+
private readonly CO_MODEL_NAME_PATH = 'filters.chatterMessage.coModelName.$eq';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Build a security-aware QB:
|
|
30
|
+
* - join the real relation to ChatterMessage (alias: "message")
|
|
31
|
+
* - left join the polymorphic co-model table using message.co_model_* fields
|
|
32
|
+
* - (optionally) apply security rules on the co-model alias
|
|
33
|
+
*/
|
|
34
|
+
override createQueryBuilder(
|
|
35
|
+
alias = 'detail',
|
|
36
|
+
queryRunner?: QueryRunner,
|
|
37
|
+
): SelectQueryBuilder<ChatterMessageDetails> {
|
|
38
|
+
const activeUser = this.requestContextService.getActiveUser();
|
|
39
|
+
let qb = super.createQueryBuilder(alias, queryRunner);
|
|
40
|
+
|
|
41
|
+
// Join the real relation so we can access co_model_* fields
|
|
42
|
+
qb = qb.leftJoin(`${alias}.chatterMessage`, 'chatterMessage');
|
|
43
|
+
|
|
44
|
+
// Example: join the "client" co-model (pass whatever co-model name you need)
|
|
45
|
+
const [coModelName, coModelAlias] = this.getCoModelNameAndAlias();
|
|
46
|
+
|
|
47
|
+
qb = this.leftJoinCoModel(qb, coModelName, 'chatterMessage');
|
|
48
|
+
|
|
49
|
+
if (!activeUser) return qb;
|
|
50
|
+
|
|
51
|
+
// If your security rules should apply to the co-model rows, pass the co-model alias.
|
|
52
|
+
// Here we use the co-model name "client" both as model key and alias base for consistency.
|
|
53
|
+
return this.securityRuleRepository.applySecurityRules(
|
|
54
|
+
qb,
|
|
55
|
+
coModelName, // modelSingularName (or whatever your rules expect)
|
|
56
|
+
activeUser as ActiveUserData,
|
|
57
|
+
coModelAlias, // the alias we used inside leftJoinCoModel
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Left-join the polymorphic co-model table, matching:
|
|
63
|
+
* <coModelAlias>.id = <messageAlias>.co_model_entity_id
|
|
64
|
+
* AND <messageAlias>.co_model_name = :model
|
|
65
|
+
*
|
|
66
|
+
* @param qb QB built on ChatterMessageDetails
|
|
67
|
+
* @param coModelName e.g. "client" | "invoice" | ...
|
|
68
|
+
* @param messageAlias alias used for joined ChatterMessage (default: "message")
|
|
69
|
+
*
|
|
70
|
+
* Notes:
|
|
71
|
+
* - We resolve the entity metadata from the classified name (e.g., "Client"),
|
|
72
|
+
* then use metadata.tablePath to get schema-qualified table.
|
|
73
|
+
* - We build a stable alias from metadata.name (camelized).
|
|
74
|
+
*/
|
|
75
|
+
leftJoinCoModel<T>(
|
|
76
|
+
qb: SelectQueryBuilder<T>,
|
|
77
|
+
coModelName: string,
|
|
78
|
+
messageAlias: string = 'message',
|
|
79
|
+
): SelectQueryBuilder<T> {
|
|
80
|
+
// Resolve entity metadata from your naming convention
|
|
81
|
+
const entityName = classify(coModelName); // "client" -> "Client"
|
|
82
|
+
const meta = this.dataSource.getMetadata(entityName); // throws if not registered
|
|
83
|
+
// const table = meta.tablePath; // schema-qualified
|
|
84
|
+
const coAlias = camelize(meta.name); // stable alias, e.g., "client"
|
|
85
|
+
|
|
86
|
+
// LEFT JOIN "<schema>"."<table>" "<coAlias>"
|
|
87
|
+
// ON "<coAlias>"."id" = "message"."co_model_entity_id"
|
|
88
|
+
// AND "message"."co_model_name" = :model
|
|
89
|
+
qb.leftJoin(
|
|
90
|
+
entityName,
|
|
91
|
+
coAlias,
|
|
92
|
+
`"${coAlias}"."id" = "${messageAlias}"."co_model_entity_id" AND "${messageAlias}"."co_model_name" = :model`,
|
|
93
|
+
{ model: coModelName },
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
return qb;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// This uses the requestContextService.getRequestFilter method and extracts the coModelName and creates the alias and returns the name and alias tuple
|
|
100
|
+
private getCoModelNameAndAlias() {
|
|
101
|
+
const requestFilter = this.requestContextService.getRequestFilter();
|
|
102
|
+
if (!requestFilter) return [undefined, undefined];
|
|
103
|
+
|
|
104
|
+
const coModelName = get(requestFilter, this.CO_MODEL_NAME_PATH);
|
|
105
|
+
const alias = camelize(coModelName);
|
|
106
|
+
return [coModelName, alias];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
}
|