@solidxai/core 0.1.13-beta.7 → 0.1.13-beta.8
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/.claude/settings.local.json +16 -0
- package/CHANGELOG.md +548 -0
- package/CLAUDE.md +26 -0
- package/dist/constants/draft-publish-fields.d.ts +2 -0
- package/dist/constants/draft-publish-fields.d.ts.map +1 -0
- package/dist/constants/draft-publish-fields.js +5 -0
- package/dist/constants/draft-publish-fields.js.map +1 -0
- package/dist/constants/media-file-types.d.ts +9 -0
- package/dist/constants/media-file-types.d.ts.map +1 -1
- package/dist/constants/media-file-types.js +27 -1
- package/dist/constants/media-file-types.js.map +1 -1
- package/dist/controllers/action-metadata.controller.d.ts +1 -1
- package/dist/controllers/action-metadata.controller.js +1 -1
- package/dist/controllers/agent-event.controller.d.ts +1 -1
- package/dist/controllers/agent-event.controller.js +1 -1
- package/dist/controllers/agent-session.controller.d.ts +1 -1
- package/dist/controllers/agent-session.controller.js +1 -1
- package/dist/controllers/dashboard-user-layout.controller.d.ts +1 -1
- package/dist/controllers/dashboard-user-layout.controller.js +1 -1
- package/dist/controllers/email-template.controller.d.ts +1 -1
- package/dist/controllers/email-template.controller.js +1 -1
- package/dist/controllers/export-template.controller.d.ts +1 -1
- package/dist/controllers/export-template.controller.d.ts.map +1 -1
- package/dist/controllers/export-template.controller.js +6 -4
- package/dist/controllers/export-template.controller.js.map +1 -1
- package/dist/controllers/export-transaction.controller.d.ts +1 -1
- package/dist/controllers/export-transaction.controller.js +1 -1
- package/dist/controllers/import-transaction-error-log.controller.d.ts +1 -1
- package/dist/controllers/import-transaction-error-log.controller.js +1 -1
- package/dist/controllers/import-transaction.controller.d.ts +1 -1
- package/dist/controllers/import-transaction.controller.d.ts.map +1 -1
- package/dist/controllers/import-transaction.controller.js +7 -7
- package/dist/controllers/import-transaction.controller.js.map +1 -1
- package/dist/controllers/list-of-values.controller.d.ts +1 -1
- package/dist/controllers/list-of-values.controller.js +1 -1
- package/dist/controllers/locale.controller.d.ts +1 -1
- package/dist/controllers/locale.controller.js +1 -1
- package/dist/controllers/mcp-audit-log.controller.d.ts +1 -1
- package/dist/controllers/mcp-audit-log.controller.js +1 -1
- package/dist/controllers/media.controller.d.ts +1 -1
- package/dist/controllers/media.controller.d.ts.map +1 -1
- package/dist/controllers/media.controller.js +12 -7
- package/dist/controllers/media.controller.js.map +1 -1
- package/dist/controllers/menu-item-metadata.controller.d.ts +1 -1
- package/dist/controllers/menu-item-metadata.controller.js +1 -1
- package/dist/controllers/model-sequence.controller.d.ts +1 -1
- package/dist/controllers/model-sequence.controller.js +1 -1
- package/dist/controllers/module-package.controller.d.ts.map +1 -1
- package/dist/controllers/module-package.controller.js +2 -3
- package/dist/controllers/module-package.controller.js.map +1 -1
- package/dist/controllers/mq-message-queue.controller.d.ts +1 -1
- package/dist/controllers/mq-message-queue.controller.js +1 -1
- package/dist/controllers/mq-message.controller.d.ts +1 -1
- package/dist/controllers/mq-message.controller.js +1 -1
- package/dist/controllers/permission-metadata.controller.d.ts +1 -1
- package/dist/controllers/permission-metadata.controller.js +1 -1
- package/dist/controllers/role-metadata.controller.d.ts +1 -1
- package/dist/controllers/role-metadata.controller.js +1 -1
- package/dist/controllers/saved-filters.controller.d.ts +1 -1
- package/dist/controllers/saved-filters.controller.js +1 -1
- package/dist/controllers/scheduled-job.controller.d.ts +1 -1
- package/dist/controllers/scheduled-job.controller.js +1 -1
- package/dist/controllers/security-rule.controller.d.ts +1 -1
- package/dist/controllers/security-rule.controller.js +1 -1
- package/dist/controllers/sms-template.controller.d.ts +1 -1
- package/dist/controllers/sms-template.controller.js +1 -1
- package/dist/controllers/user-activity-history.controller.d.ts +1 -1
- package/dist/controllers/user-activity-history.controller.js +1 -1
- package/dist/controllers/user-view-metadata.controller.d.ts +1 -1
- package/dist/controllers/user-view-metadata.controller.js +1 -1
- package/dist/controllers/user.controller.d.ts +2 -2
- package/dist/controllers/user.controller.js +2 -2
- package/dist/controllers/view-metadata.controller.d.ts +2 -2
- package/dist/controllers/view-metadata.controller.js +1 -1
- package/dist/controllers/workflow-definition.controller.d.ts +1 -1
- package/dist/controllers/workflow-definition.controller.js +1 -1
- package/dist/controllers/workflow-execution-artifact.controller.d.ts +1 -1
- package/dist/controllers/workflow-execution-artifact.controller.js +1 -1
- package/dist/controllers/workflow-execution-log.controller.d.ts +1 -1
- package/dist/controllers/workflow-execution-log.controller.js +1 -1
- package/dist/controllers/workflow-execution.controller.d.ts +1 -1
- package/dist/controllers/workflow-execution.controller.js +1 -1
- package/dist/controllers/workflow-secret.controller.d.ts +1 -1
- package/dist/controllers/workflow-secret.controller.js +1 -1
- package/dist/controllers/workflow-step-execution.controller.d.ts +1 -1
- package/dist/controllers/workflow-step-execution.controller.js +1 -1
- package/dist/controllers/workflow-trigger-execution.controller.d.ts +1 -1
- package/dist/controllers/workflow-trigger-execution.controller.js +1 -1
- package/dist/dtos/basic-filters.dto.d.ts +0 -1
- package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
- package/dist/dtos/basic-filters.dto.js +1 -6
- package/dist/dtos/basic-filters.dto.js.map +1 -1
- package/dist/entities/common.entity.d.ts +4 -0
- package/dist/entities/common.entity.d.ts.map +1 -1
- package/dist/entities/common.entity.js +25 -1
- package/dist/entities/common.entity.js.map +1 -1
- package/dist/entities/user.entity.js +2 -2
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/factories/mail.factory.d.ts.map +1 -1
- package/dist/factories/mail.factory.js +4 -0
- package/dist/factories/mail.factory.js.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts +1 -0
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +18 -11
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
- package/dist/helpers/file-download.helper.d.ts +9 -0
- package/dist/helpers/file-download.helper.d.ts.map +1 -0
- package/dist/helpers/file-download.helper.js +14 -0
- package/dist/helpers/file-download.helper.js.map +1 -0
- package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
- package/dist/helpers/model-metadata-helper.service.js +30 -1
- package/dist/helpers/model-metadata-helper.service.js.map +1 -1
- package/dist/helpers/solid-registry.js +1 -1
- package/dist/helpers/solid-registry.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/seeders/module-test-data.service.d.ts +3 -1
- package/dist/seeders/module-test-data.service.d.ts.map +1 -1
- package/dist/seeders/module-test-data.service.js +8 -2
- package/dist/seeders/module-test-data.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +2 -0
- package/dist/services/authentication.service.d.ts +4 -1
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +52 -4
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/chatter-message.service.d.ts +1 -0
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js +8 -0
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/crud-helper.service.d.ts +5 -2
- package/dist/services/crud-helper.service.d.ts.map +1 -1
- package/dist/services/crud-helper.service.js +30 -32
- package/dist/services/crud-helper.service.js.map +1 -1
- package/dist/services/crud.service.d.ts +11 -1
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +79 -66
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/datasource-introspection.service.d.ts.map +1 -1
- package/dist/services/datasource-introspection.service.js.map +1 -1
- package/dist/services/draft-publish-helper.service.d.ts +52 -0
- package/dist/services/draft-publish-helper.service.d.ts.map +1 -0
- package/dist/services/draft-publish-helper.service.js +368 -0
- package/dist/services/draft-publish-helper.service.js.map +1 -0
- package/dist/services/internationalisation-helper.service.d.ts +19 -0
- package/dist/services/internationalisation-helper.service.d.ts.map +1 -0
- package/dist/services/internationalisation-helper.service.js +107 -0
- package/dist/services/internationalisation-helper.service.js.map +1 -0
- package/dist/services/locale.service.d.ts +1 -1
- package/dist/services/media.service.d.ts +2 -1
- package/dist/services/media.service.d.ts.map +1 -1
- package/dist/services/media.service.js +28 -2
- package/dist/services/media.service.js.map +1 -1
- package/dist/services/metadata-validation.service.d.ts +7 -0
- package/dist/services/metadata-validation.service.d.ts.map +1 -0
- package/dist/services/metadata-validation.service.js +42 -0
- package/dist/services/metadata-validation.service.js.map +1 -0
- package/dist/services/model-metadata.service.d.ts.map +1 -1
- package/dist/services/model-metadata.service.js +2 -1
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/object.utils.d.ts +2 -0
- package/dist/services/object.utils.d.ts.map +1 -0
- package/dist/services/object.utils.js +11 -0
- package/dist/services/object.utils.js.map +1 -0
- package/dist/services/settings/default-settings-provider.service.d.ts +6 -6
- package/dist/services/settings/default-settings-provider.service.js +3 -3
- package/dist/services/settings/default-settings-provider.service.js.map +1 -1
- package/dist/services/user.service.d.ts +2 -2
- package/dist/services/user.service.d.ts.map +1 -1
- package/dist/services/user.service.js +9 -3
- package/dist/services/user.service.js.map +1 -1
- package/dist/services/view-metadata.service.d.ts +1 -2
- package/dist/services/view-metadata.service.d.ts.map +1 -1
- package/dist/services/view-metadata.service.js +3 -55
- package/dist/services/view-metadata.service.js.map +1 -1
- package/dist/services/workflow-definition.service.d.ts +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +10 -1
- package/dist/solid-core.module.js.map +1 -1
- package/package.json +1 -1
- package/src/constants/draft-publish-fields.ts +5 -0
- package/src/constants/media-file-types.ts +50 -0
- package/src/controllers/export-template.controller.ts +5 -3
- package/src/controllers/import-transaction.controller.ts +6 -6
- package/src/controllers/media.controller.ts +17 -6
- package/src/controllers/module-package.controller.ts +2 -3
- package/src/dtos/basic-filters.dto.ts +0 -4
- package/src/entities/common.entity.ts +20 -0
- package/src/entities/user.entity.ts +2 -2
- package/src/factories/mail.factory.ts +7 -1
- package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +26 -12
- package/src/helpers/file-download.helper.ts +31 -0
- package/src/helpers/model-metadata-helper.service.ts +32 -1
- package/src/helpers/solid-registry.ts +1 -1
- package/src/index.ts +2 -0
- package/src/seeders/module-test-data.service.ts +6 -0
- package/src/seeders/seed-data/solid-core-metadata.json +2 -0
- package/src/services/1.js +6 -0
- package/src/services/authentication.service.ts +76 -5
- package/src/services/chatter-message.service.ts +16 -0
- package/src/services/crud-helper.service.ts +16 -34
- package/src/services/crud.service.ts +98 -103
- package/src/services/datasource-introspection.service.ts +5 -0
- package/src/services/draft-publish-helper.service.ts +529 -0
- package/src/services/internationalisation-helper.service.ts +148 -0
- package/src/services/media.service.ts +48 -3
- package/src/services/metadata-validation.service.ts +39 -0
- package/src/services/model-metadata.service.ts +4 -1
- package/src/services/object.utils.ts +10 -0
- package/src/services/settings/default-settings-provider.service.ts +3 -3
- package/src/services/user.service.ts +18 -3
- package/src/services/view-metadata.service.ts +5 -145
- package/src/solid-core.module.ts +16 -3
- package/dist-tests/api/authenticate.spec.js +0 -119
- package/dist-tests/api/authenticate.spec.js.map +0 -1
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +0 -97
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +0 -1
- package/dist-tests/api/ping.spec.js +0 -21
- package/dist-tests/api/ping.spec.js.map +0 -1
- package/dist-tests/helpers/auth.js +0 -41
- package/dist-tests/helpers/auth.js.map +0 -1
- package/dist-tests/helpers/env.js +0 -11
- package/dist-tests/helpers/env.js.map +0 -1
- package/docs/agent-builder/notebook-lm-prompt-for-agent-builder.md +0 -136
- package/docs/agent-builder/team-ready-note-agent-builder.md +0 -305
- package/docs/agent-hub-grooming.md +0 -301
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +0 -438
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +0 -146
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +0 -172
- package/docs/datasource-introspection-ddl-analysis.md +0 -326
- package/docs/datasource-introspection-implementation-plan.md +0 -306
- package/docs/grouping-enhancements.md +0 -89
- package/docs/java-spring/README.md +0 -3
- package/docs/java-spring/solid-core-module-deep-dive-report.md +0 -1317
- package/docs/module-package-import-handoff.md +0 -691
- package/docs/seed-changes.md +0 -65
- package/docs/test-data-workflow.md +0 -200
- package/docs/type-declaration-import-issue.md +0 -24
- package/docs/workflow/business-automation-example-notes.md +0 -309
- package/docs/workflow/control-flow-node-addition-sop.md +0 -324
- package/docs/workflow/data-engineering-pipeline-example-notes.md +0 -330
- package/docs/workflow/foreach-example-notes.md +0 -187
- package/docs/workflow/hello-world-example-notes.md +0 -271
- package/docs/workflow/kestra-concepts-plugins-blueprints.md +0 -315
- package/docs/workflow/loop-until-example-notes.md +0 -198
- package/docs/workflow/microservices-and-apis-example-notes.md +0 -264
- package/docs/workflow/samples.md +0 -25
- package/docs/workflow/what-is-kestra.md +0 -79
- package/docs/workflow/workflow-core-module-handoff-summary.md +0 -191
- package/docs/workflow/workflow-module-brd.md +0 -185
- package/docs/workflow/workflow-module-domain-model.md +0 -252
- package/docs/workflow/workflow-module-metadata-dsl.md +0 -302
- package/docs/workflow/workflow-module-technical-spec.md +0 -293
- package/docs/workflow/workflow-node-type-contracts.md +0 -635
- package/docs/workflow/workflow-node-ui-metadata-contract.md +0 -1262
- package/docs/workflow/workflow-solidx-model-field-spec.md +0 -284
|
@@ -36,12 +36,12 @@ export class User extends CommonEntity {
|
|
|
36
36
|
@Expose()
|
|
37
37
|
username: string;
|
|
38
38
|
|
|
39
|
-
@Index()
|
|
39
|
+
@Index({ unique: true })
|
|
40
40
|
@Column({ type: "varchar", nullable: true })
|
|
41
41
|
@Expose()
|
|
42
42
|
email: string;
|
|
43
43
|
|
|
44
|
-
@Index()
|
|
44
|
+
@Index({ unique: true })
|
|
45
45
|
@Column({ type: "varchar", nullable: true })
|
|
46
46
|
@Expose()
|
|
47
47
|
mobile: string;
|
|
@@ -30,8 +30,14 @@ export class MailFactory {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const mailServiceProvider = mailProviders.find(provider => provider.name === mailServiceName);
|
|
33
|
+
if (!mailServiceProvider?.instance) {
|
|
34
|
+
const registeredProviders = mailProviders.map((provider) => provider?.name).filter(Boolean).join(", ");
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Mail provider "${mailServiceName}" is not registered. Registered providers: ${registeredProviders || "none"}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
33
39
|
|
|
34
40
|
return mailServiceProvider.instance as IMail;
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
}
|
|
43
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FieldCrudManager, ValidationError } from "src/interfaces";
|
|
2
|
-
import {
|
|
2
|
+
import { EXT_TO_MEDIA_TYPE, getLowercaseFileExtension, getUploadedFileName, isDangerousMediaFile, MediaCategory } from "src/constants/media-file-types";
|
|
3
3
|
|
|
4
4
|
export enum SolidMediaType {
|
|
5
5
|
mediaSingle = 'mediaSingle',
|
|
@@ -79,16 +79,15 @@ export class MediaFieldCrudManager implements FieldCrudManager {
|
|
|
79
79
|
constructor(private readonly options: MediaFieldOptions) {
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
private resolveMediaType(
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
private resolveMediaType(file: Express.Multer.File): MediaType | null {
|
|
83
|
+
// Belt-and-braces: dangerous files are already rejected outright by
|
|
84
|
+
// validateDangerousFiles, but never let one resolve to a usable category.
|
|
85
|
+
if (isDangerousMediaFile(file)) {
|
|
85
86
|
return null;
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
89
|
+
const ext = getLowercaseFileExtension(getUploadedFileName(file));
|
|
90
|
+
const mt = (file.mimetype || '').toLowerCase().trim();
|
|
92
91
|
if (mt && MIME_TO_MEDIA_TYPE[mt]) {
|
|
93
92
|
return MIME_TO_MEDIA_TYPE[mt];
|
|
94
93
|
}
|
|
@@ -113,16 +112,31 @@ export class MediaFieldCrudManager implements FieldCrudManager {
|
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
private applyValidations(fieldFiles: Array<Express.Multer.File>): ValidationError[] {
|
|
115
|
+
// Runs for every media field type and regardless of the admin-configured mediaTypes
|
|
116
|
+
// allowlist - a dangerous upload is never acceptable, so this must not sit behind
|
|
117
|
+
// the optional type checks below.
|
|
118
|
+
const errors = this.validateDangerousFiles(fieldFiles);
|
|
119
|
+
|
|
116
120
|
switch (this.options.type) {
|
|
117
121
|
case SolidMediaType.mediaSingle:
|
|
118
|
-
return this.validateMediaSingle(fieldFiles);
|
|
122
|
+
return [...errors, ...this.validateMediaSingle(fieldFiles)];
|
|
119
123
|
case SolidMediaType.mediaMultiple:
|
|
120
|
-
return this.validateMediaMultiple(fieldFiles);
|
|
124
|
+
return [...errors, ...this.validateMediaMultiple(fieldFiles)];
|
|
121
125
|
default:
|
|
122
|
-
return
|
|
126
|
+
return errors;
|
|
123
127
|
}
|
|
124
128
|
}
|
|
125
129
|
|
|
130
|
+
private validateDangerousFiles(fieldFiles: Array<Express.Multer.File>): ValidationError[] {
|
|
131
|
+
return fieldFiles
|
|
132
|
+
.filter(fieldFile => isDangerousMediaFile(fieldFile))
|
|
133
|
+
.map(fieldFile => ({
|
|
134
|
+
field: this.options.fieldName,
|
|
135
|
+
error: `${this.options.fieldName} file type not allowed. ` +
|
|
136
|
+
`${getUploadedFileName(fieldFile) || 'File'} is a potentially dangerous file type.`
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
|
|
126
140
|
private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {
|
|
127
141
|
const errors: ValidationError[] = [];
|
|
128
142
|
if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {
|
|
@@ -157,7 +171,7 @@ export class MediaFieldCrudManager implements FieldCrudManager {
|
|
|
157
171
|
for (let i = 0; i < fieldFiles.length; i++) {
|
|
158
172
|
const fieldFile = fieldFiles[i];
|
|
159
173
|
|
|
160
|
-
const resolvedType = this.resolveMediaType(fieldFile
|
|
174
|
+
const resolvedType = this.resolveMediaType(fieldFile);
|
|
161
175
|
if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {
|
|
162
176
|
errors.push({
|
|
163
177
|
field: this.options.fieldName,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Response } from "express";
|
|
2
|
+
|
|
3
|
+
export interface FileDownloadHeaderOptions {
|
|
4
|
+
fileName: string;
|
|
5
|
+
mimeType: string;
|
|
6
|
+
/** Defaults to 'attachment'; only pass 'inline' for types known safe to render. */
|
|
7
|
+
disposition?: "inline" | "attachment";
|
|
8
|
+
/** Opt in for assets loaded cross-origin by the UI (e.g. media served to :3000). */
|
|
9
|
+
crossOriginResourcePolicy?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Single place that stamps the response headers for every streamed file download, so the
|
|
14
|
+
* security headers can't be applied to one endpoint and forgotten on the next.
|
|
15
|
+
*/
|
|
16
|
+
export function setFileDownloadHeaders(res: Response, options: FileDownloadHeaderOptions): void {
|
|
17
|
+
const disposition = options.disposition ?? "attachment";
|
|
18
|
+
|
|
19
|
+
res.setHeader("Content-Disposition", `${disposition}; filename="${options.fileName}"`);
|
|
20
|
+
res.setHeader("Content-Type", options.mimeType);
|
|
21
|
+
res.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Type");
|
|
22
|
+
|
|
23
|
+
// Prevent the browser from ever content-sniffing a served file into something more
|
|
24
|
+
// dangerous than its declared Content-Type (e.g. rendering a mislabeled upload as HTML
|
|
25
|
+
// and executing embedded script).
|
|
26
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
27
|
+
|
|
28
|
+
if (options.crossOriginResourcePolicy) {
|
|
29
|
+
res.setHeader("Cross-Origin-Resource-Policy", "cross-origin");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef, Inject, Injectable, Logger } from "@nestjs/common";
|
|
4
4
|
import { _ } from "lodash";
|
|
5
|
+
import { DRAFT_PUBLISH_VERSIONING_FIELD_NAMES } from "src/constants/draft-publish-fields";
|
|
5
6
|
import { LEGACY_TABLE_FIELDS_PREFIX } from "src/entities/legacy-common.entity-with-existing-id.entity";
|
|
6
7
|
import { LegacyTableType } from "src/enums/legacy-table-type.enum";
|
|
7
8
|
import { ModelMetadataRepository } from "src/repository/model-metadata.repository";
|
|
@@ -87,6 +88,32 @@ export class ModelMetadataHelperService {
|
|
|
87
88
|
isSystem: true,
|
|
88
89
|
enableAuditTracking:true
|
|
89
90
|
},
|
|
91
|
+
{
|
|
92
|
+
name: "isPublished",
|
|
93
|
+
displayName: "Is Published",
|
|
94
|
+
type: "boolean",
|
|
95
|
+
isSystem: true,
|
|
96
|
+
enableAuditTracking: true
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "isLatest",
|
|
100
|
+
displayName: "Is Latest",
|
|
101
|
+
type: "boolean",
|
|
102
|
+
isSystem: true,
|
|
103
|
+
enableAuditTracking: true
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "initialEntityVersionId",
|
|
107
|
+
displayName: "Initial Entity Version Id",
|
|
108
|
+
type: "int",
|
|
109
|
+
isSystem: true,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "publishedTracker",
|
|
113
|
+
displayName: "Published Tracker",
|
|
114
|
+
type: "shortText",
|
|
115
|
+
isSystem: true,
|
|
116
|
+
},
|
|
90
117
|
{
|
|
91
118
|
name: "localeName",
|
|
92
119
|
displayName: "Locale",
|
|
@@ -117,7 +144,11 @@ export class ModelMetadataHelperService {
|
|
|
117
144
|
}
|
|
118
145
|
|
|
119
146
|
private getSystemFieldsMetadataMappingForLegacyTable(withId: boolean=true) {
|
|
120
|
-
|
|
147
|
+
// Legacy tables don't have the draft/publish versioning columns, so exclude
|
|
148
|
+
// them from the legacy system fields metadata mapping.
|
|
149
|
+
const legacyExcludedFieldNames: readonly string[] = DRAFT_PUBLISH_VERSIONING_FIELD_NAMES;
|
|
150
|
+
const systemFieldsMetadata = this.getSystemFieldsMetadataMapping()
|
|
151
|
+
.filter(field => !legacyExcludedFieldNames.includes(field.name));
|
|
121
152
|
if (!withId) {
|
|
122
153
|
// Remove the id field metadata
|
|
123
154
|
const index = systemFieldsMetadata.findIndex(field => field.name === 'id');
|
|
@@ -366,7 +366,7 @@ export class SolidRegistry {
|
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
getCommonEntityKeys(): (keyof CommonEntity | 'createdBy' | 'updatedBy')[] {
|
|
369
|
-
return ['id', 'createdAt', 'updatedAt', 'deletedAt', 'createdBy', 'updatedBy', 'deletedTracker', 'localeName', 'defaultEntityLocaleId', 'publishedAt'];
|
|
369
|
+
return ['id', 'createdAt', 'updatedAt', 'deletedAt', 'createdBy', 'updatedBy', 'deletedTracker', 'localeName', 'defaultEntityLocaleId', 'publishedAt', 'isPublished', 'isLatest', 'initialEntityVersionId', 'publishedTracker'];
|
|
370
370
|
// return Reflect.getMetadataKeys(CommonEntity.prototype) as (keyof CommonEntity)[];
|
|
371
371
|
}
|
|
372
372
|
|
package/src/index.ts
CHANGED
|
@@ -225,6 +225,7 @@ export * from './helpers/environment.helper'
|
|
|
225
225
|
export * from './helpers/cache.helper'
|
|
226
226
|
export * from './helpers/cors.helper'
|
|
227
227
|
export * from './helpers/security.helper'
|
|
228
|
+
export * from './helpers/file-download.helper'
|
|
228
229
|
export * from './helpers/model-metadata-helper.service'
|
|
229
230
|
export * from './helpers/image-encoding.helper'
|
|
230
231
|
export * from './helpers/solid-microservice-adapter.service'
|
|
@@ -337,6 +338,7 @@ export * from './services/action-metadata.service'
|
|
|
337
338
|
export * from './services/authentication.service'
|
|
338
339
|
export * from './services/bcrypt.service'
|
|
339
340
|
export * from './services/computed-fields/uuid-external-id-computed-field-provider.service'
|
|
341
|
+
export * from './services/draft-publish-helper.service'
|
|
340
342
|
export * from './services/crud-helper.service'
|
|
341
343
|
export * from './services/crud.service'
|
|
342
344
|
export * from './services/email-template.service'
|
|
@@ -12,6 +12,7 @@ import { CreateModelMetadataDto } from 'src/dtos/create-model-metadata.dto';
|
|
|
12
12
|
import { MediaStorageProviderType } from 'src/dtos/create-media-storage-provider-metadata.dto';
|
|
13
13
|
import { getDynamicModuleNamesBasedOnMetadata } from 'src/helpers/module.helper';
|
|
14
14
|
import { SolidRegistry } from 'src/helpers/solid-registry';
|
|
15
|
+
import { InternationalisationHelperService } from 'src/services/internationalisation-helper.service';
|
|
15
16
|
import { MediaRepository } from 'src/repository/media.repository';
|
|
16
17
|
import { PermissionMetadataRepository } from 'src/repository/permission-metadata.repository';
|
|
17
18
|
import { AuthenticationService } from 'src/services/authentication.service';
|
|
@@ -30,6 +31,7 @@ export class ModuleTestDataService {
|
|
|
30
31
|
private readonly moduleRef: ModuleRef,
|
|
31
32
|
private readonly discoveryService: DiscoveryService,
|
|
32
33
|
private readonly solidRegistry: SolidRegistry,
|
|
34
|
+
private readonly internationalisationHelperService: InternationalisationHelperService,
|
|
33
35
|
) {}
|
|
34
36
|
|
|
35
37
|
async setupTestData(modulesToTest?: string[]): Promise<void> {
|
|
@@ -246,6 +248,10 @@ export class ModuleTestDataService {
|
|
|
246
248
|
const entityRepo = this.resolveRepository(modelUserKey);
|
|
247
249
|
const payload: Record<string, any> = { ...(entry.data ?? {}) };
|
|
248
250
|
|
|
251
|
+
if (modelDef.internationalisation && !payload.localeName) {
|
|
252
|
+
payload.localeName = this.internationalisationHelperService.resolveDefaultLocaleName(this.solidRegistry);
|
|
253
|
+
}
|
|
254
|
+
|
|
249
255
|
for (const field of modelDef.fields ?? []) {
|
|
250
256
|
if (field.type === 'relation' && field.relationType === 'many-to-one') {
|
|
251
257
|
const userKeyProp = `${field.name}UserKey`;
|
|
@@ -1808,6 +1808,8 @@
|
|
|
1808
1808
|
"index": true,
|
|
1809
1809
|
"private": false,
|
|
1810
1810
|
"encrypt": false,
|
|
1811
|
+
"regexPattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$",
|
|
1812
|
+
"regexPatternNotMatchingErrorMsg": "Please enter a valid email address.",
|
|
1811
1813
|
"isSystem": true,
|
|
1812
1814
|
"enableAuditTracking": true
|
|
1813
1815
|
},
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
1. Do i need to create a storeStreams method for aws service too?
|
|
2
|
+
- Handle later
|
|
3
|
+
2. queues handling -> if queues is enabled by default, i.e triggerExport(exportTransactionEntity.id).
|
|
4
|
+
- startExport should either return the data or return the transaction id
|
|
5
|
+
3. How to handle scenarios wherein, nested related exist.(do i need to only get the userkey)
|
|
6
|
+
- show the userKey
|
|
@@ -20,7 +20,7 @@ import { SUCCESS_MESSAGES } from "src/constants/success-messages";
|
|
|
20
20
|
import { CreateUserDto } from "src/dtos/create-user.dto";
|
|
21
21
|
import { MailFactory } from "src/factories/mail.factory";
|
|
22
22
|
import { UserRepository } from "src/repository/user.repository";
|
|
23
|
-
import { DataSource, DeepPartial, Repository } from "typeorm";
|
|
23
|
+
import { DataSource, DeepPartial, FindOptionsWhere, Repository } from "typeorm";
|
|
24
24
|
import { v4 as uuidv4 } from "uuid";
|
|
25
25
|
import {
|
|
26
26
|
ForgotPasswordSendVerificationTokenOn,
|
|
@@ -49,6 +49,7 @@ import { SsoCodeStorageService } from "./sso-code-storage.service";
|
|
|
49
49
|
import { RoleMetadataService } from "./role-metadata.service";
|
|
50
50
|
import { SettingService } from "./setting.service";
|
|
51
51
|
import { UserActivityHistoryService } from "./user-activity-history.service";
|
|
52
|
+
import { MetadataValidationService } from "./metadata-validation.service";
|
|
52
53
|
import { UserService } from "./user.service";
|
|
53
54
|
import { SmsFactory } from "src/factories/sms.factory";
|
|
54
55
|
import { WhatsAppFactory } from "src/factories/whatsapp.factory";
|
|
@@ -88,6 +89,7 @@ export class AuthenticationService {
|
|
|
88
89
|
private readonly roleMetadataService: RoleMetadataService,
|
|
89
90
|
private readonly userActivityHistoryService: UserActivityHistoryService,
|
|
90
91
|
private readonly ssoCodeStorage: SsoCodeStorageService,
|
|
92
|
+
private readonly metadataValidationService: MetadataValidationService,
|
|
91
93
|
|
|
92
94
|
@InjectDataSource()
|
|
93
95
|
private readonly dataSource: DataSource,
|
|
@@ -225,6 +227,9 @@ export class AuthenticationService {
|
|
|
225
227
|
preferEntityApiKeyFlag: boolean = false,
|
|
226
228
|
): Promise<T> {
|
|
227
229
|
try {
|
|
230
|
+
await this.assertUniqueSignupIdentifiers(signUpDto, repo);
|
|
231
|
+
await this.metadataValidationService.validateCreateDto("user", signUpDto);
|
|
232
|
+
|
|
228
233
|
const onForcePasswordChange =
|
|
229
234
|
this.settingService.getConfigValue<SolidCoreSetting>(
|
|
230
235
|
"forceChangePasswordOnFirstLogin",
|
|
@@ -276,6 +281,59 @@ export class AuthenticationService {
|
|
|
276
281
|
}
|
|
277
282
|
}
|
|
278
283
|
|
|
284
|
+
private async assertUniqueSignupIdentifiers<T extends User>(
|
|
285
|
+
signUpDto: SignUpDto,
|
|
286
|
+
repo: Repository<T>,
|
|
287
|
+
): Promise<void> {
|
|
288
|
+
const username = signUpDto.username?.trim();
|
|
289
|
+
const email = signUpDto.email?.trim();
|
|
290
|
+
const mobile = signUpDto.mobile?.trim();
|
|
291
|
+
|
|
292
|
+
const where: FindOptionsWhere<T>[] = [];
|
|
293
|
+
|
|
294
|
+
if (username) {
|
|
295
|
+
where.push({ username } as FindOptionsWhere<T>);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (email) {
|
|
299
|
+
where.push({ email } as FindOptionsWhere<T>);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (mobile) {
|
|
303
|
+
where.push({ mobile } as FindOptionsWhere<T>);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (where.length === 0) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const existingUser = await repo.findOne({ where });
|
|
311
|
+
|
|
312
|
+
if (!existingUser) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (email && existingUser.email === email) {
|
|
317
|
+
throw new ConflictException(
|
|
318
|
+
`A user with email address "${email}" already exists.`,
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (mobile && existingUser.mobile === mobile) {
|
|
323
|
+
throw new ConflictException(
|
|
324
|
+
`A user with mobile number "${mobile}" already exists.`,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (username && existingUser.username === username) {
|
|
329
|
+
throw new ConflictException(
|
|
330
|
+
`A user with username "${username}" already exists.`,
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
throw new ConflictException(ERROR_MESSAGES.USER_ALREADY_EXISTS);
|
|
335
|
+
}
|
|
336
|
+
|
|
279
337
|
private async handlePasswordlessSignupOtp<T extends User>(
|
|
280
338
|
user: T,
|
|
281
339
|
signUpDto: SignUpDto,
|
|
@@ -400,11 +458,23 @@ export class AuthenticationService {
|
|
|
400
458
|
// if forcePasswordChange is true, then we trigger an email to the user to change the password, this needs to be done using a queue.
|
|
401
459
|
// Create a new method like notifyUserOnForcePasswordChange, create a new email template we can call it on-force-password-change this template to include the random password
|
|
402
460
|
if (user.forcePasswordChange && autoGeneratedPwd) {
|
|
403
|
-
|
|
461
|
+
try {
|
|
462
|
+
await this.notifyUserOnForcePasswordChange(user, autoGeneratedPwd);
|
|
463
|
+
} catch (error: any) {
|
|
464
|
+
this.logger.error(
|
|
465
|
+
`Failed to send force-password-change email for user ${user.id}: ${error?.message ?? error}`,
|
|
466
|
+
);
|
|
467
|
+
}
|
|
404
468
|
}
|
|
405
469
|
|
|
406
470
|
// Send welcome notifications (email/SMS) if enabled.
|
|
407
|
-
|
|
471
|
+
try {
|
|
472
|
+
await this.notifyUserOnSignup(user);
|
|
473
|
+
} catch (error: any) {
|
|
474
|
+
this.logger.error(
|
|
475
|
+
`Failed to send signup notifications for user ${user.id}: ${error?.message ?? error}`,
|
|
476
|
+
);
|
|
477
|
+
}
|
|
408
478
|
}
|
|
409
479
|
|
|
410
480
|
generatePassword(length: number = 8): string {
|
|
@@ -1578,7 +1648,7 @@ export class AuthenticationService {
|
|
|
1578
1648
|
// Assuming all users do not have mobile as mandatory.
|
|
1579
1649
|
if (
|
|
1580
1650
|
forgotPasswordSendVerificationTokenOn ==
|
|
1581
|
-
|
|
1651
|
+
ForgotPasswordSendVerificationTokenOn.MOBILE &&
|
|
1582
1652
|
user.mobile
|
|
1583
1653
|
) {
|
|
1584
1654
|
const smsService = this.smsFactory.getSmsService();
|
|
@@ -1702,7 +1772,7 @@ export class AuthenticationService {
|
|
|
1702
1772
|
// Assuming all users do not have mobile as mandatory.
|
|
1703
1773
|
if (
|
|
1704
1774
|
forgotPasswordSendVerificationTokenOn ==
|
|
1705
|
-
|
|
1775
|
+
ForgotPasswordSendVerificationTokenOn.MOBILE &&
|
|
1706
1776
|
user.mobile
|
|
1707
1777
|
) {
|
|
1708
1778
|
const smsService = this.smsFactory.getSmsService();
|
|
@@ -2342,6 +2412,7 @@ function parseUniqueConstraintError(detail: string): string {
|
|
|
2342
2412
|
const fieldMap: Record<string, string> = {
|
|
2343
2413
|
username: "username",
|
|
2344
2414
|
email: "email address",
|
|
2415
|
+
mobile: "mobile number",
|
|
2345
2416
|
full_name_user_key: "full name",
|
|
2346
2417
|
};
|
|
2347
2418
|
const friendlyField = fieldMap[field] || field;
|
|
@@ -6,6 +6,7 @@ import { Brackets, EntityManager, EntityMetadata, In } from 'typeorm';
|
|
|
6
6
|
|
|
7
7
|
import { classify } from '@angular-devkit/core/src/utils/strings';
|
|
8
8
|
import { CHATTER_MESSAGE_STATUS, CHATTER_MESSAGE_SUBTYPE, CHATTER_MESSAGE_TYPE, CHATTER_MESSAGE_USER_FIELDS } from 'src/constants/chatter-message.constants';
|
|
9
|
+
import { isDangerousMediaFile } from 'src/constants/media-file-types';
|
|
9
10
|
import { ERROR_MESSAGES } from 'src/constants/error-messages';
|
|
10
11
|
import { PostChatterMessageDto } from 'src/dtos/post-chatter-message.dto';
|
|
11
12
|
import { UpdateChatterNoteMessageDto } from 'src/dtos/update-chatter-note-message.dto';
|
|
@@ -174,6 +175,17 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
174
175
|
}, messageBody || '');
|
|
175
176
|
}
|
|
176
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Chatter attachments bypass MediaFieldCrudManager - they go straight to
|
|
180
|
+
* storageProvider.store() - so the shared predicate is applied here directly. The rules
|
|
181
|
+
* themselves live in media-file-types so upload paths can't drift apart.
|
|
182
|
+
*/
|
|
183
|
+
private validateChatterMediaFiles(files: Express.Multer.File[] = []) {
|
|
184
|
+
if (Array.isArray(files) && files.some(file => isDangerousMediaFile(file))) {
|
|
185
|
+
throw new BadRequestException('Dangerous file types are not allowed in chatter attachments.');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
177
189
|
private async publishChatterMentionNotifications(message: ChatterMessage, model: any) {
|
|
178
190
|
if (message.messageType !== CHATTER_MESSAGE_TYPE.CUSTOM || message.messageSubType !== CHATTER_MESSAGE_SUBTYPE.NOTE) {
|
|
179
191
|
return;
|
|
@@ -305,6 +317,8 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
305
317
|
throw new BadRequestException('Message body cannot be empty.');
|
|
306
318
|
}
|
|
307
319
|
|
|
320
|
+
this.validateChatterMediaFiles(files);
|
|
321
|
+
|
|
308
322
|
if (hasMessageBody) {
|
|
309
323
|
message.messageBody = trimmedMessageBody;
|
|
310
324
|
}
|
|
@@ -379,6 +393,8 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
|
|
|
379
393
|
const coModelName = lowerFirst(postDto.coModelName);
|
|
380
394
|
await this.assertRecordAccess(coModelName, postDto.coModelEntityId);
|
|
381
395
|
|
|
396
|
+
this.validateChatterMediaFiles(files);
|
|
397
|
+
|
|
382
398
|
const chatterMessage = new ChatterMessage();
|
|
383
399
|
chatterMessage.messageType = CHATTER_MESSAGE_TYPE.CUSTOM;
|
|
384
400
|
chatterMessage.messageSubType = postDto.messageSubType || CHATTER_MESSAGE_SUBTYPE.CUSTOM;
|
|
@@ -3,9 +3,12 @@ import { BasicFilterDto } from "../dtos/basic-filters.dto";
|
|
|
3
3
|
import { classify } from '../helpers/string.helper';
|
|
4
4
|
import { ActiveUserData } from "src/interfaces/active-user-data.interface";
|
|
5
5
|
import { SolidRegistry } from "src/helpers/solid-registry";
|
|
6
|
-
import { BadRequestException, Logger } from "@nestjs/common";
|
|
6
|
+
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
|
7
7
|
import { ERROR_MESSAGES } from "src/constants/error-messages";
|
|
8
8
|
import { buildCastToText } from "src/helpers/typeorm-db-helper";
|
|
9
|
+
import { DraftPublishHelperService } from "./draft-publish-helper.service";
|
|
10
|
+
import { InternationalisationHelperService } from "./internationalisation-helper.service";
|
|
11
|
+
import { normalizeObjectKeys } from "./object.utils";
|
|
9
12
|
|
|
10
13
|
export enum FilterCombinator {
|
|
11
14
|
AND = '$and',
|
|
@@ -36,10 +39,14 @@ export interface ResolvedFieldPath {
|
|
|
36
39
|
leafIsRelation: boolean;
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
@Injectable()
|
|
39
43
|
export class CrudHelperService {
|
|
44
|
+
private readonly logger = new Logger(CrudHelperService.name);
|
|
45
|
+
|
|
40
46
|
constructor(
|
|
47
|
+
private readonly draftPublishHelperService: DraftPublishHelperService,
|
|
48
|
+
private readonly internationalisationHelperService: InternationalisationHelperService,
|
|
41
49
|
) { }
|
|
42
|
-
private readonly logger = new Logger(CrudHelperService.name);
|
|
43
50
|
|
|
44
51
|
/**
|
|
45
52
|
* Resolve a user-supplied dotted path (e.g. "customer.name") against real TypeORM metadata.
|
|
@@ -163,7 +170,7 @@ export class CrudHelperService {
|
|
|
163
170
|
}
|
|
164
171
|
|
|
165
172
|
applyFilters(qb: WhereExpressionBuilder, filters: any, alias: string = 'entity', selectQb: SelectQueryBuilder<any>) {
|
|
166
|
-
const normalizedFilters =
|
|
173
|
+
const normalizedFilters = normalizeObjectKeys(filters);
|
|
167
174
|
if (normalizedFilters.$and) {
|
|
168
175
|
normalizedFilters.$and.forEach((andFilter: any) => {
|
|
169
176
|
qb.andWhere(
|
|
@@ -182,7 +189,7 @@ export class CrudHelperService {
|
|
|
182
189
|
// For individual conditions
|
|
183
190
|
Object.keys(normalizedFilters).forEach(key => {
|
|
184
191
|
const primaryFilterObj = normalizedFilters[key];
|
|
185
|
-
const normalizedPrimaryFilterObj =
|
|
192
|
+
const normalizedPrimaryFilterObj = normalizeObjectKeys(primaryFilterObj);
|
|
186
193
|
|
|
187
194
|
const [rawField, funcAlias] = key.split(':');
|
|
188
195
|
|
|
@@ -312,17 +319,6 @@ export class CrudHelperService {
|
|
|
312
319
|
}
|
|
313
320
|
}
|
|
314
321
|
|
|
315
|
-
// Normalize the primary operator object by removing the surrounding brackets in the keys e.g [$eq] => $eq
|
|
316
|
-
private normalizeObjectKeys(obj: any): any {
|
|
317
|
-
return Object.keys(obj).reduce((acc, key) => {
|
|
318
|
-
// Transform the key by removing surrounding brackets
|
|
319
|
-
const newKey = key.replace(/^\[(.*)\]$/, '$1');
|
|
320
|
-
// Assign the value to the transformed key in the accumulator object
|
|
321
|
-
acc[newKey] = obj[key];
|
|
322
|
-
return acc;
|
|
323
|
-
}, {});
|
|
324
|
-
}
|
|
325
|
-
|
|
326
322
|
normalize(value: string | string[]): string[] {
|
|
327
323
|
if (!value) return []; // if the value is nullish, then return an empty array
|
|
328
324
|
return Array.isArray(value) ? value : [value]; // if the value is an array, return it as is, otherwise return it as an array
|
|
@@ -359,7 +355,7 @@ export class CrudHelperService {
|
|
|
359
355
|
applySorting: boolean = true
|
|
360
356
|
): SelectQueryBuilder<any> { // TODO : Check how to pass a type to SelectQueryBuilder instead of any
|
|
361
357
|
let { limit, offset, showSoftDeleted, filters } = basicFilterDto;
|
|
362
|
-
const { fields, sort, populate = [], populateMedia = [], locale
|
|
358
|
+
const { fields, sort, populate = [], populateMedia = [], locale } = basicFilterDto;
|
|
363
359
|
|
|
364
360
|
// Normalize the fields, sort, groupBy and populate options i.e (since they can be either a string or an array of strings, when coming from the request)
|
|
365
361
|
const normalizedFields = this.normalize(fields);
|
|
@@ -390,28 +386,14 @@ export class CrudHelperService {
|
|
|
390
386
|
}
|
|
391
387
|
}
|
|
392
388
|
|
|
393
|
-
let finalLocale = locale
|
|
394
389
|
if (internationalisation) {
|
|
395
|
-
// If locale is not provided in the filter dto, then assume it is the default locale to be used.
|
|
396
|
-
|
|
397
|
-
//Get default locale from registry
|
|
398
|
-
const solidRegistry = moduleRef.get(SolidRegistry, { strict: false });
|
|
399
|
-
const defaultLocale = solidRegistry.getDefaultLocale();
|
|
400
|
-
if(defaultLocale){
|
|
401
|
-
finalLocale = defaultLocale.locale;
|
|
402
|
-
}else{
|
|
403
|
-
finalLocale = 'en';
|
|
404
|
-
}
|
|
405
|
-
}
|
|
390
|
+
// If locale is not provided in the filter dto, then assume it is the default locale to be used.
|
|
391
|
+
const finalLocale = locale || this.internationalisationHelperService.resolveDefaultLocaleName(moduleRef.get(SolidRegistry, { strict: false }));
|
|
406
392
|
qb.andWhere(`${entityAlias}.localeName = :locale`, { locale: finalLocale });
|
|
407
393
|
}
|
|
408
394
|
|
|
409
|
-
if (draftPublishWorkflow
|
|
410
|
-
|
|
411
|
-
qb.andWhere(`${entityAlias}.publishedAt IS NOT NULL`);
|
|
412
|
-
} else if (basicFilterDto.status === 'draft') {
|
|
413
|
-
qb.andWhere(`${entityAlias}.publishedAt IS NULL`);
|
|
414
|
-
}
|
|
395
|
+
if (draftPublishWorkflow) {
|
|
396
|
+
this.draftPublishHelperService.applyDraftPublishFilterDefaults(qb, filters, entityAlias);
|
|
415
397
|
}
|
|
416
398
|
// Depending upon the select option, apply the select clause
|
|
417
399
|
if (normalizedFields && normalizedFields.length) {
|