@solidxai/core 0.1.13-beta.20 → 0.1.13-beta.22

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 (70) hide show
  1. package/CHANGELOG.md +1181 -0
  2. package/CLAUDE.md +5 -6
  3. package/dist/constants/media-file-types.d.ts.map +1 -1
  4. package/dist/constants/media-file-types.js +1 -0
  5. package/dist/constants/media-file-types.js.map +1 -1
  6. package/dist/dtos/create-field-metadata.dto.d.ts +1 -0
  7. package/dist/dtos/create-field-metadata.dto.d.ts.map +1 -1
  8. package/dist/dtos/create-field-metadata.dto.js +12 -1
  9. package/dist/dtos/create-field-metadata.dto.js.map +1 -1
  10. package/dist/entities/field-metadata.entity.d.ts +1 -0
  11. package/dist/entities/field-metadata.entity.d.ts.map +1 -1
  12. package/dist/entities/field-metadata.entity.js +5 -1
  13. package/dist/entities/field-metadata.entity.js.map +1 -1
  14. package/dist/helpers/field-crud-managers/LongTextFieldCrudManager.d.ts.map +1 -1
  15. package/dist/helpers/field-crud-managers/LongTextFieldCrudManager.js +3 -2
  16. package/dist/helpers/field-crud-managers/LongTextFieldCrudManager.js.map +1 -1
  17. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts +6 -0
  18. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
  19. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +54 -27
  20. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
  21. package/dist/helpers/field-crud-managers/ShortTextFieldCrudManager.d.ts.map +1 -1
  22. package/dist/helpers/field-crud-managers/ShortTextFieldCrudManager.js +3 -2
  23. package/dist/helpers/field-crud-managers/ShortTextFieldCrudManager.js.map +1 -1
  24. package/dist/helpers/field-crud-managers/textFieldCrudManagerUtils.d.ts +3 -0
  25. package/dist/helpers/field-crud-managers/textFieldCrudManagerUtils.d.ts.map +1 -0
  26. package/dist/helpers/field-crud-managers/textFieldCrudManagerUtils.js +17 -0
  27. package/dist/helpers/field-crud-managers/textFieldCrudManagerUtils.js.map +1 -0
  28. package/dist/services/chatter-message.service.d.ts +1 -0
  29. package/dist/services/chatter-message.service.d.ts.map +1 -1
  30. package/dist/services/chatter-message.service.js +44 -12
  31. package/dist/services/chatter-message.service.js.map +1 -1
  32. package/dist/services/crud.service.d.ts.map +1 -1
  33. package/dist/services/crud.service.js +1 -0
  34. package/dist/services/crud.service.js.map +1 -1
  35. package/dist/services/field-metadata.service.d.ts.map +1 -1
  36. package/dist/services/field-metadata.service.js +2 -0
  37. package/dist/services/field-metadata.service.js.map +1 -1
  38. package/dist/services/media.service.d.ts.map +1 -1
  39. package/dist/services/media.service.js +1 -0
  40. package/dist/services/media.service.js.map +1 -1
  41. package/dist/services/module-metadata.service.d.ts.map +1 -1
  42. package/dist/services/module-metadata.service.js +7 -0
  43. package/dist/services/module-metadata.service.js.map +1 -1
  44. package/dist/services/setting.service.d.ts.map +1 -1
  45. package/dist/services/setting.service.js +4 -0
  46. package/dist/services/setting.service.js.map +1 -1
  47. package/dist/services/settings/default-settings-provider.service.d.ts +20 -0
  48. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  49. package/dist/services/settings/default-settings-provider.service.js +14 -0
  50. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  51. package/dist/solid-core.module.d.ts.map +1 -1
  52. package/dist/solid-core.module.js +6 -0
  53. package/dist/solid-core.module.js.map +1 -1
  54. package/package.json +1 -1
  55. package/src/constants/media-file-types.ts +1 -0
  56. package/src/dtos/create-field-metadata.dto.ts +14 -1
  57. package/src/entities/field-metadata.entity.ts +3 -0
  58. package/src/helpers/field-crud-managers/LongTextFieldCrudManager.ts +3 -2
  59. package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +73 -34
  60. package/src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts +3 -2
  61. package/src/helpers/field-crud-managers/textFieldCrudManagerUtils.ts +14 -0
  62. package/src/services/chatter-message.service.ts +56 -14
  63. package/src/services/crud.service.ts +1 -0
  64. package/src/services/field-metadata.service.ts +2 -0
  65. package/src/services/media.service.ts +1 -0
  66. package/src/services/module-metadata.service.ts +7 -0
  67. package/src/services/setting.service.ts +5 -0
  68. package/src/services/settings/default-settings-provider.service.ts +14 -0
  69. package/src/solid-core.module.ts +13 -0
  70. package/postman/mpin.postman_collection.json +0 -1045
@@ -61,34 +61,31 @@ class MediaFieldCrudManager {
61
61
  return null;
62
62
  }
63
63
  const ext = (0, media_file_types_1.getLowercaseFileExtension)((0, media_file_types_1.getUploadedFileName)(file));
64
- const mt = (file.mimetype || '').toLowerCase().trim();
65
- if (mt && MIME_TO_MEDIA_TYPE[mt]) {
66
- return MIME_TO_MEDIA_TYPE[mt];
64
+ const extType = ext ? media_file_types_1.EXT_TO_MEDIA_TYPE[ext] : undefined;
65
+ if (!extType) {
66
+ return null;
67
67
  }
68
- if (mt.startsWith('image/'))
69
- return 'image';
70
- if (mt.startsWith('audio/'))
71
- return 'audio';
72
- if (mt.startsWith('video/'))
73
- return 'video';
74
- if (ext && media_file_types_1.EXT_TO_MEDIA_TYPE[ext]) {
75
- return media_file_types_1.EXT_TO_MEDIA_TYPE[ext];
68
+ const mt = (file.mimetype || '').toLowerCase().trim();
69
+ const mimeType = MIME_TO_MEDIA_TYPE[mt]
70
+ ?? (mt.startsWith('image/') ? 'image' : mt.startsWith('audio/') ? 'audio' : mt.startsWith('video/') ? 'video' : undefined);
71
+ if (mimeType && mimeType !== extType) {
72
+ return null;
76
73
  }
77
- return null;
74
+ return extType;
78
75
  }
79
76
  validate(dto, files) {
80
77
  const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);
81
78
  return this.applyValidations(fieldFiles);
82
79
  }
83
80
  applyValidations(fieldFiles) {
84
- const errors = this.validateDangerousFiles(fieldFiles);
81
+ const dangerousFileErrors = this.validateDangerousFiles(fieldFiles);
85
82
  switch (this.options.type) {
86
83
  case SolidMediaType.mediaSingle:
87
- return [...errors, ...this.validateMediaSingle(fieldFiles)];
84
+ return [...dangerousFileErrors, ...this.validateMediaSingle(fieldFiles)];
88
85
  case SolidMediaType.mediaMultiple:
89
- return [...errors, ...this.validateMediaMultiple(fieldFiles)];
86
+ return [...dangerousFileErrors, ...this.validateMediaMultiple(fieldFiles)];
90
87
  default:
91
- return errors;
88
+ return dangerousFileErrors;
92
89
  }
93
90
  }
94
91
  validateDangerousFiles(fieldFiles) {
@@ -100,7 +97,15 @@ class MediaFieldCrudManager {
100
97
  `${(0, media_file_types_1.getUploadedFileName)(fieldFile) || 'File'} is a potentially dangerous file type.`
101
98
  }));
102
99
  }
103
- validateMediaSingle(fieldFiles) {
100
+ validateCommon(fieldFiles) {
101
+ return [
102
+ ...this.validateRequired(fieldFiles),
103
+ ...this.validateSize(fieldFiles),
104
+ ...this.validateTypes(fieldFiles),
105
+ ...this.validateAllowedExtensions(fieldFiles),
106
+ ];
107
+ }
108
+ validateRequired(fieldFiles) {
104
109
  const errors = [];
105
110
  if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {
106
111
  errors.push({
@@ -108,12 +113,10 @@ class MediaFieldCrudManager {
108
113
  error: `${this.options.fieldName} is required`
109
114
  });
110
115
  }
111
- if (fieldFiles.length > 1) {
112
- errors.push({
113
- field: this.options.fieldName,
114
- error: `${this.options.fieldName} must be a single file`
115
- });
116
- }
116
+ return errors;
117
+ }
118
+ validateSize(fieldFiles) {
119
+ const errors = [];
117
120
  if (this.options.mediaMaxSizeKb) {
118
121
  for (let i = 0; i < fieldFiles.length; i++) {
119
122
  const fieldFile = fieldFiles[i];
@@ -126,6 +129,10 @@ class MediaFieldCrudManager {
126
129
  }
127
130
  }
128
131
  }
132
+ return errors;
133
+ }
134
+ validateTypes(fieldFiles) {
135
+ const errors = [];
129
136
  if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {
130
137
  const allowedFileTypes = this.options.mediaTypes;
131
138
  for (let i = 0; i < fieldFiles.length; i++) {
@@ -143,16 +150,36 @@ class MediaFieldCrudManager {
143
150
  }
144
151
  return errors;
145
152
  }
146
- validateMediaMultiple(fieldFiles) {
147
- const errors = [];
148
- if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {
153
+ validateAllowedExtensions(fieldFiles) {
154
+ const allowed = this.options.mediaAllowedExtensions;
155
+ if (!allowed || allowed.length === 0) {
156
+ return [];
157
+ }
158
+ const normalizedAllowed = new Set(allowed.map(ext => ext.toLowerCase().replace(/^\./, '')));
159
+ return fieldFiles
160
+ .filter(fieldFile => {
161
+ const ext = (0, media_file_types_1.getLowercaseFileExtension)((0, media_file_types_1.getUploadedFileName)(fieldFile));
162
+ return !ext || !normalizedAllowed.has(ext);
163
+ })
164
+ .map(fieldFile => ({
165
+ field: this.options.fieldName,
166
+ error: `${this.options.fieldName} file type not allowed. ` +
167
+ `Allowed extensions: ${[...normalizedAllowed].join(', ')}.`
168
+ }));
169
+ }
170
+ validateMediaSingle(fieldFiles) {
171
+ const errors = this.validateCommon(fieldFiles);
172
+ if (fieldFiles.length > 1) {
149
173
  errors.push({
150
174
  field: this.options.fieldName,
151
- error: `${this.options.fieldName} is required`
175
+ error: `${this.options.fieldName} must be a single file`
152
176
  });
153
177
  }
154
178
  return errors;
155
179
  }
180
+ validateMediaMultiple(fieldFiles) {
181
+ return this.validateCommon(fieldFiles);
182
+ }
156
183
  transformForCreate(dto) {
157
184
  return dto;
158
185
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MediaFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/MediaFieldCrudManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldCrudManager, ValidationError } from \"src/interfaces\";\nimport { EXT_TO_MEDIA_TYPE, getLowercaseFileExtension, getUploadedFileName, isDangerousMediaFile, MediaCategory } from \"src/constants/media-file-types\";\n\nexport enum SolidMediaType {\n mediaSingle = 'mediaSingle',\n mediaMultiple = 'mediaMultiple'\n}\n\nexport interface MediaFieldOptions {\n type: SolidMediaType;\n required: boolean | undefined | null;\n fieldName: string | undefined | null;\n mediaMaxSizeKb: number | undefined | null;\n mediaTypes: string[];\n isUpdate: boolean | undefined | null;\n}\n\ntype MediaType = MediaCategory;\n\nconst MIME_TO_MEDIA_TYPE: Record<string, MediaType> = {\n // Images\n 'image/png': 'image',\n 'image/jpeg': 'image',\n 'image/jpg': 'image',\n 'image/webp': 'image',\n 'image/gif': 'image',\n 'image/bmp': 'image',\n 'image/tiff': 'image',\n 'image/heic': 'image',\n 'image/heif': 'image',\n\n // Audio\n 'audio/mpeg': 'audio', // mp3\n 'audio/mp3': 'audio',\n 'audio/wav': 'audio',\n 'audio/x-wav': 'audio',\n 'audio/webm': 'audio',\n 'audio/ogg': 'audio',\n 'audio/aac': 'audio',\n 'audio/mp4': 'audio', // m4a often shows as audio/mp4\n 'audio/x-m4a': 'audio',\n 'audio/flac': 'audio',\n\n // Video\n 'video/mp4': 'video',\n 'video/mpeg': 'video',\n 'video/webm': 'video',\n 'video/ogg': 'video',\n 'video/quicktime': 'video', // mov\n 'video/x-msvideo': 'video', // avi\n 'video/x-matroska': 'video',// mkv\n 'video/3gpp': 'video',\n 'video/3gpp2': 'video',\n\n // Documents / files (treat as \"file\")\n 'application/pdf': 'pdf',\n 'text/plain': 'file',\n 'text/markdown': 'file',\n 'application/json': 'file',\n 'text/csv': 'file',\n\n // Office\n 'application/msword': 'file', // doc\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'file', // docx\n 'application/vnd.ms-excel': 'file', // xls\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'file', // xlsx\n 'application/vnd.ms-powerpoint': 'file', // ppt\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'file', // pptx,\n\n // Archives (optional)\n 'application/zip': 'file',\n 'application/x-zip-compressed': 'file',\n 'application/x-rar-compressed': 'file',\n 'application/x-7z-compressed': 'file',\n};\n\nexport class MediaFieldCrudManager implements FieldCrudManager {\n\n constructor(private readonly options: MediaFieldOptions) {\n }\n\n private resolveMediaType(file: Express.Multer.File): MediaType | null {\n // Belt-and-braces: dangerous files are already rejected outright by\n // validateDangerousFiles, but never let one resolve to a usable category.\n if (isDangerousMediaFile(file)) {\n return null;\n }\n\n const ext = getLowercaseFileExtension(getUploadedFileName(file));\n const mt = (file.mimetype || '').toLowerCase().trim();\n if (mt && MIME_TO_MEDIA_TYPE[mt]) {\n return MIME_TO_MEDIA_TYPE[mt];\n }\n\n // Some libs may send \"image/*\" etc. Treat broad families safely.\n if (mt.startsWith('image/')) return 'image';\n if (mt.startsWith('audio/')) return 'audio';\n if (mt.startsWith('video/')) return 'video';\n\n // Fallback to extension if provided (also covers generic/unrecognized\n // mimetypes such as application/octet-stream).\n if (ext && EXT_TO_MEDIA_TYPE[ext]) {\n return EXT_TO_MEDIA_TYPE[ext];\n }\n\n return null;\n }\n\n validate(dto: any, files: Array<Express.Multer.File>): ValidationError[] {\n const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);\n return this.applyValidations(fieldFiles);\n }\n\n private applyValidations(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n // Runs for every media field type and regardless of the admin-configured mediaTypes\n // allowlist - a dangerous upload is never acceptable, so this must not sit behind\n // the optional type checks below.\n const errors = this.validateDangerousFiles(fieldFiles);\n\n switch (this.options.type) {\n case SolidMediaType.mediaSingle:\n return [...errors, ...this.validateMediaSingle(fieldFiles)];\n case SolidMediaType.mediaMultiple:\n return [...errors, ...this.validateMediaMultiple(fieldFiles)];\n default:\n return errors;\n }\n }\n\n private validateDangerousFiles(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return fieldFiles\n .filter(fieldFile => isDangerousMediaFile(fieldFile))\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `${getUploadedFileName(fieldFile) || 'File'} is a potentially dangerous file type.`\n }));\n }\n\n private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n if (fieldFiles.length > 1) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} must be a single file`\n });\n }\n // validate size\n if (this.options.mediaMaxSizeKb) {\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n const fieldFileSizeInBytes = Math.ceil(fieldFile.size / 1024);\n if (fieldFileSizeInBytes > this.options.mediaMaxSizeKb) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`\n });\n }\n }\n }\n // validate type\n if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {\n const allowedFileTypes = this.options.mediaTypes as MediaType[];\n\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n\n const resolvedType = this.resolveMediaType(fieldFile);\n if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed: ${allowedFileTypes.join(', ')}. ` +\n `Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`\n });\n }\n }\n }\n\n return errors;\n }\n\n private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n return errors;\n }\n\n transformForCreate(dto: any): any {\n return dto;\n }\n\n // Validation to be applied\n}\n"]}
1
+ {"version":3,"file":"MediaFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/MediaFieldCrudManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldCrudManager, ValidationError } from \"src/interfaces\";\nimport { EXT_TO_MEDIA_TYPE, getLowercaseFileExtension, getUploadedFileName, isDangerousMediaFile, MediaCategory } from \"src/constants/media-file-types\";\n\nexport enum SolidMediaType {\n mediaSingle = 'mediaSingle',\n mediaMultiple = 'mediaMultiple'\n}\n\nexport interface MediaFieldOptions {\n type: SolidMediaType;\n required: boolean | undefined | null;\n fieldName: string | undefined | null;\n mediaMaxSizeKb: number | undefined | null;\n mediaTypes: string[];\n mediaAllowedExtensions?: string[] | null;\n isUpdate: boolean | undefined | null;\n}\n\ntype MediaType = MediaCategory;\n\nconst MIME_TO_MEDIA_TYPE: Record<string, MediaType> = {\n // Images\n 'image/png': 'image',\n 'image/jpeg': 'image',\n 'image/jpg': 'image',\n 'image/webp': 'image',\n 'image/gif': 'image',\n 'image/bmp': 'image',\n 'image/tiff': 'image',\n 'image/heic': 'image',\n 'image/heif': 'image',\n\n // Audio\n 'audio/mpeg': 'audio', // mp3\n 'audio/mp3': 'audio',\n 'audio/wav': 'audio',\n 'audio/x-wav': 'audio',\n 'audio/webm': 'audio',\n 'audio/ogg': 'audio',\n 'audio/aac': 'audio',\n 'audio/mp4': 'audio', // m4a often shows as audio/mp4\n 'audio/x-m4a': 'audio',\n 'audio/flac': 'audio',\n\n // Video\n 'video/mp4': 'video',\n 'video/mpeg': 'video',\n 'video/webm': 'video',\n 'video/ogg': 'video',\n 'video/quicktime': 'video', // mov\n 'video/x-msvideo': 'video', // avi\n 'video/x-matroska': 'video',// mkv\n 'video/3gpp': 'video',\n 'video/3gpp2': 'video',\n\n // Documents / files (treat as \"file\")\n 'application/pdf': 'pdf',\n 'text/plain': 'file',\n 'text/markdown': 'file',\n 'application/json': 'file',\n 'text/csv': 'file',\n\n // Office\n 'application/msword': 'file', // doc\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'file', // docx\n 'application/vnd.ms-excel': 'file', // xls\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'file', // xlsx\n 'application/vnd.ms-powerpoint': 'file', // ppt\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'file', // pptx,\n\n // Archives (optional)\n 'application/zip': 'file',\n 'application/x-zip-compressed': 'file',\n 'application/x-rar-compressed': 'file',\n 'application/x-7z-compressed': 'file',\n};\n\nexport class MediaFieldCrudManager implements FieldCrudManager {\n\n constructor(private readonly options: MediaFieldOptions) {\n }\n\n private resolveMediaType(file: Express.Multer.File): MediaType | null {\n // Belt-and-braces: dangerous files are already rejected outright by\n // validateDangerousFiles, but never let one resolve to a usable category.\n if (isDangerousMediaFile(file)) {\n return null;\n }\n\n // Extension is authoritative: a declared mimetype is fully attacker-controlled and\n // proved insufficient on its own (a .msi uploaded as image/png previously resolved to\n // 'image', since the mimetype match short-circuited before the extension was ever\n // checked). The extension must independently resolve to a known-safe category before\n // anything is accepted - not merely \"not on the denylist\".\n const ext = getLowercaseFileExtension(getUploadedFileName(file));\n const extType = ext ? EXT_TO_MEDIA_TYPE[ext] : undefined;\n if (!extType) {\n return null;\n }\n\n // The mimetype may only confirm or veto what the extension already established, never\n // grant a category on its own. A mimetype that doesn't resolve to anything (e.g.\n // application/octet-stream) has no opinion and is treated as agreeing.\n const mt = (file.mimetype || '').toLowerCase().trim();\n const mimeType = MIME_TO_MEDIA_TYPE[mt]\n ?? (mt.startsWith('image/') ? 'image' : mt.startsWith('audio/') ? 'audio' : mt.startsWith('video/') ? 'video' : undefined);\n if (mimeType && mimeType !== extType) {\n return null;\n }\n\n return extType;\n }\n\n validate(dto: any, files: Array<Express.Multer.File>): ValidationError[] {\n const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);\n return this.applyValidations(fieldFiles);\n }\n\n private applyValidations(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n // A dangerous upload is never acceptable, regardless of admin config, so this is the\n // only check that sits outside validateCommon() and can't be skipped either way below.\n const dangerousFileErrors = this.validateDangerousFiles(fieldFiles);\n\n switch (this.options.type) {\n case SolidMediaType.mediaSingle:\n return [...dangerousFileErrors, ...this.validateMediaSingle(fieldFiles)];\n case SolidMediaType.mediaMultiple:\n return [...dangerousFileErrors, ...this.validateMediaMultiple(fieldFiles)];\n default:\n return dangerousFileErrors;\n }\n }\n\n private validateDangerousFiles(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return fieldFiles\n .filter(fieldFile => isDangerousMediaFile(fieldFile))\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `${getUploadedFileName(fieldFile) || 'File'} is a potentially dangerous file type.`\n }));\n }\n\n // Every optional, admin-configured, per-field check - no-ops when its setting is unset -\n // shared between mediaSingle and mediaMultiple so neither can drift out of sync with it.\n private validateCommon(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return [\n ...this.validateRequired(fieldFiles),\n ...this.validateSize(fieldFiles),\n ...this.validateTypes(fieldFiles),\n ...this.validateAllowedExtensions(fieldFiles),\n ];\n }\n\n private validateRequired(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n return errors;\n }\n\n private validateSize(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (this.options.mediaMaxSizeKb) {\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n const fieldFileSizeInBytes = Math.ceil(fieldFile.size / 1024);\n if (fieldFileSizeInBytes > this.options.mediaMaxSizeKb) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`\n });\n }\n }\n }\n return errors;\n }\n\n private validateTypes(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {\n const allowedFileTypes = this.options.mediaTypes as MediaType[];\n\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n\n const resolvedType = this.resolveMediaType(fieldFile);\n if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed: ${allowedFileTypes.join(', ')}. ` +\n `Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`\n });\n }\n }\n }\n return errors;\n }\n\n private validateAllowedExtensions(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const allowed = this.options.mediaAllowedExtensions;\n if (!allowed || allowed.length === 0) {\n return [];\n }\n\n const normalizedAllowed = new Set(allowed.map(ext => ext.toLowerCase().replace(/^\\./, '')));\n return fieldFiles\n .filter(fieldFile => {\n const ext = getLowercaseFileExtension(getUploadedFileName(fieldFile));\n return !ext || !normalizedAllowed.has(ext);\n })\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed extensions: ${[...normalizedAllowed].join(', ')}.`\n }));\n }\n\n private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors = this.validateCommon(fieldFiles);\n if (fieldFiles.length > 1) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} must be a single file`\n });\n }\n return errors;\n }\n\n private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return this.validateCommon(fieldFiles);\n }\n\n transformForCreate(dto: any): any {\n return dto;\n }\n\n // Validation to be applied\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ShortTextFieldCrudManager.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEnE,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACxC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,yBAA0B,YAAW,gBAAgB;IAC9D,OAAO,CAAC,OAAO,CAAwB;gBAE3B,OAAO,EAAE,qBAAqB;IAI1C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAG,MAAM,EAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,EAAE;IAMzE,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,sBAAsB;IAQ9B,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG;IAKjC,OAAO,CAAC,uBAAuB;IAG/B,OAAO,CAAC,uBAAuB;IAG/B,OAAO,CAAC,sBAAsB;IAG9B,OAAO,CAAC,yBAAyB;CAGpC"}
1
+ {"version":3,"file":"ShortTextFieldCrudManager.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGnE,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACxC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,yBAA0B,YAAW,gBAAgB;IAC9D,OAAO,CAAC,OAAO,CAAwB;gBAE3B,OAAO,EAAE,qBAAqB;IAI1C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAG,MAAM,EAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,EAAE;IAMzE,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,sBAAsB;IAQ9B,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG;IAKjC,OAAO,CAAC,uBAAuB;IAG/B,OAAO,CAAC,uBAAuB;IAG/B,OAAO,CAAC,sBAAsB;IAG9B,OAAO,CAAC,yBAAyB;CAGpC"}
@@ -2,12 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ShortTextFieldCrudManager = void 0;
4
4
  const class_validator_1 = require("class-validator");
5
+ const textFieldCrudManagerUtils_1 = require("./textFieldCrudManagerUtils");
5
6
  class ShortTextFieldCrudManager {
6
7
  constructor(options) {
7
8
  this.options = options;
8
9
  }
9
10
  validate(dto, _files) {
10
- const fieldValue = dto[this.options.fieldName];
11
+ const fieldValue = (0, textFieldCrudManagerUtils_1.normalizeTextFieldValue)(dto[this.options.fieldName]);
11
12
  return this.applyValidations(fieldValue);
12
13
  }
13
14
  applyValidations(fieldValue) {
@@ -26,7 +27,7 @@ class ShortTextFieldCrudManager {
26
27
  return errors;
27
28
  }
28
29
  transformForCreate(dto) {
29
- return dto;
30
+ return (0, textFieldCrudManagerUtils_1.normalizeTextFieldInDto)(dto, this.options.fieldName);
30
31
  }
31
32
  isApplyStringValidation() {
32
33
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"ShortTextFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts"],"names":[],"mappings":";;;AAAA,qDAAiF;AAUjF,MAAa,yBAAyB;IAGlC,YAAY,OAA8B;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,QAAQ,CAAC,GAAQ,EAAG,MAAiC;QACjD,MAAM,UAAU,GAAQ,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAGO,gBAAgB,CAAC,UAAe;QACpC,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,yBAAyB,EAAE,IAAI,IAAA,yBAAO,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAA,CAAC,CAAC,WAAW,CAAC;QAC7K,IAAI,IAAA,4BAAU,EAAC,UAAU,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,sBAAsB,CAAC,UAAe;QAC1C,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,IAAA,0BAAQ,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACvJ,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,IAAA,wBAAM,EAAC,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAC/K,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,IAAA,yBAAO,EAAC,UAAU,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACrM,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,kBAAkB,CAAC,GAAQ;QACvB,OAAO,GAAG,CAAC;IACf,CAAC;IAGO,uBAAuB;QAC3B,OAAO,IAAI,CAAC;IAChB,CAAC;IACO,uBAAuB;QAC3B,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,CAAC;IACO,sBAAsB;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IACxI,CAAC;IACO,yBAAyB;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IACjC,CAAC;CACJ;AA/CD,8DA+CC","sourcesContent":["import { isEmpty, isNotEmpty, isString, length, matches } from \"class-validator\";\nimport { FieldCrudManager, ValidationError } from \"src/interfaces\";\n\nexport interface ShortTextFieldOptions {\n length: number | undefined | null;\n regexPattern: string | undefined | null;\n required: boolean | undefined | null;\n fieldName: string;\n}\n\nexport class ShortTextFieldCrudManager implements FieldCrudManager {\n private options: ShortTextFieldOptions;\n\n constructor(options: ShortTextFieldOptions) {\n this.options = options;\n }\n\n validate(dto: any, _files:Array<Express.Multer.File>): ValidationError[] {\n const fieldValue: any = dto[this.options.fieldName];\n return this.applyValidations(fieldValue);\n }\n\n\n private applyValidations(fieldValue: any): ValidationError[] {\n const errors: ValidationError[] = [];\n this.isApplyRequiredValidation() && isEmpty(fieldValue) ? errors.push({ field: this.options.fieldName, error: `Field: ${this.options.fieldName} is required` }): \"no errors\";\n if (isNotEmpty(fieldValue)) {\n errors.push(...this.applyFormatValidations(fieldValue));\n }\n return errors;\n }\n\n private applyFormatValidations(fieldValue: any): ValidationError[] {\n const errors: ValidationError[] = [];\n this.isApplyStringValidation() && !isString(fieldValue) ? errors.push({ field: this.options.fieldName, error: 'Field is not a string' }) : \"no errors\";\n this.isApplyLengthValidation() && !length(fieldValue, 1, this.options.length) ? errors.push({ field: this.options.fieldName, error: 'Field length is invalid' }) : \"no errors\"; //FIXME min length to be handled\n this.isApplyRegexValidation() && !matches(fieldValue, new RegExp(this.options.regexPattern)) ? errors.push({ field: this.options.fieldName, error: 'Field regex pattern is invalid' }) : \"no errors\";\n return errors;\n }\n\n transformForCreate(dto: any): any {\n return dto;\n }\n\n // Validation to be applied\n private isApplyStringValidation(): boolean {\n return true;\n }\n private isApplyLengthValidation(): boolean {\n return (this.options.length > 0);\n }\n private isApplyRegexValidation(): boolean {\n return this.options.regexPattern !== null && this.options.regexPattern !== undefined && this.options.regexPattern.trim().length > 0;\n }\n private isApplyRequiredValidation(): boolean {\n return this.options.required;\n }\n}"]}
1
+ {"version":3,"file":"ShortTextFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/ShortTextFieldCrudManager.ts"],"names":[],"mappings":";;;AAAA,qDAAiF;AAEjF,2EAA+F;AAS/F,MAAa,yBAAyB;IAGlC,YAAY,OAA8B;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,QAAQ,CAAC,GAAQ,EAAG,MAAiC;QACjD,MAAM,UAAU,GAAQ,IAAA,mDAAuB,EAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAGO,gBAAgB,CAAC,UAAe;QACpC,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,yBAAyB,EAAE,IAAI,IAAA,yBAAO,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAA,CAAC,CAAC,WAAW,CAAC;QAC7K,IAAI,IAAA,4BAAU,EAAC,UAAU,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,sBAAsB,CAAC,UAAe;QAC1C,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,IAAA,0BAAQ,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACvJ,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,IAAA,wBAAM,EAAC,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAC/K,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,IAAA,yBAAO,EAAC,UAAU,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACrM,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,kBAAkB,CAAC,GAAQ;QACvB,OAAO,IAAA,mDAAuB,EAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IAGO,uBAAuB;QAC3B,OAAO,IAAI,CAAC;IAChB,CAAC;IACO,uBAAuB;QAC3B,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,CAAC;IACO,sBAAsB;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IACxI,CAAC;IACO,yBAAyB;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IACjC,CAAC;CACJ;AA/CD,8DA+CC","sourcesContent":["import { isEmpty, isNotEmpty, isString, length, matches } from \"class-validator\";\nimport { FieldCrudManager, ValidationError } from \"src/interfaces\";\nimport { normalizeTextFieldInDto, normalizeTextFieldValue } from \"./textFieldCrudManagerUtils\";\n\nexport interface ShortTextFieldOptions {\n length: number | undefined | null;\n regexPattern: string | undefined | null;\n required: boolean | undefined | null;\n fieldName: string;\n}\n\nexport class ShortTextFieldCrudManager implements FieldCrudManager {\n private options: ShortTextFieldOptions;\n\n constructor(options: ShortTextFieldOptions) {\n this.options = options;\n }\n\n validate(dto: any, _files:Array<Express.Multer.File>): ValidationError[] {\n const fieldValue: any = normalizeTextFieldValue(dto[this.options.fieldName]);\n return this.applyValidations(fieldValue);\n }\n\n\n private applyValidations(fieldValue: any): ValidationError[] {\n const errors: ValidationError[] = [];\n this.isApplyRequiredValidation() && isEmpty(fieldValue) ? errors.push({ field: this.options.fieldName, error: `Field: ${this.options.fieldName} is required` }): \"no errors\";\n if (isNotEmpty(fieldValue)) {\n errors.push(...this.applyFormatValidations(fieldValue));\n }\n return errors;\n }\n\n private applyFormatValidations(fieldValue: any): ValidationError[] {\n const errors: ValidationError[] = [];\n this.isApplyStringValidation() && !isString(fieldValue) ? errors.push({ field: this.options.fieldName, error: 'Field is not a string' }) : \"no errors\";\n this.isApplyLengthValidation() && !length(fieldValue, 1, this.options.length) ? errors.push({ field: this.options.fieldName, error: 'Field length is invalid' }) : \"no errors\"; //FIXME min length to be handled\n this.isApplyRegexValidation() && !matches(fieldValue, new RegExp(this.options.regexPattern)) ? errors.push({ field: this.options.fieldName, error: 'Field regex pattern is invalid' }) : \"no errors\";\n return errors;\n }\n\n transformForCreate(dto: any): any {\n return normalizeTextFieldInDto(dto, this.options.fieldName);\n }\n\n // Validation to be applied\n private isApplyStringValidation(): boolean {\n return true;\n }\n private isApplyLengthValidation(): boolean {\n return (this.options.length > 0);\n }\n private isApplyRegexValidation(): boolean {\n return this.options.regexPattern !== null && this.options.regexPattern !== undefined && this.options.regexPattern.trim().length > 0;\n }\n private isApplyRequiredValidation(): boolean {\n return this.options.required;\n }\n}"]}
@@ -0,0 +1,3 @@
1
+ export declare const normalizeTextFieldValue: (fieldValue: any) => any;
2
+ export declare const normalizeTextFieldInDto: (dto: any, fieldName?: string | null) => any;
3
+ //# sourceMappingURL=textFieldCrudManagerUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textFieldCrudManagerUtils.d.ts","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/textFieldCrudManagerUtils.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,uBAAuB,GAAI,YAAY,GAAG,KAAG,GAEzD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,KAAK,GAAG,EAAE,YAAY,MAAM,GAAG,IAAI,KAAG,GAO7E,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeTextFieldInDto = exports.normalizeTextFieldValue = void 0;
4
+ const class_validator_1 = require("class-validator");
5
+ const normalizeTextFieldValue = (fieldValue) => {
6
+ return (0, class_validator_1.isString)(fieldValue) ? fieldValue.trim() : fieldValue;
7
+ };
8
+ exports.normalizeTextFieldValue = normalizeTextFieldValue;
9
+ const normalizeTextFieldInDto = (dto, fieldName) => {
10
+ if (!fieldName || !Object.prototype.hasOwnProperty.call(dto, fieldName)) {
11
+ return dto;
12
+ }
13
+ dto[fieldName] = (0, exports.normalizeTextFieldValue)(dto[fieldName]);
14
+ return dto;
15
+ };
16
+ exports.normalizeTextFieldInDto = normalizeTextFieldInDto;
17
+ //# sourceMappingURL=textFieldCrudManagerUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textFieldCrudManagerUtils.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/textFieldCrudManagerUtils.ts"],"names":[],"mappings":";;;AAAA,qDAA2C;AAEpC,MAAM,uBAAuB,GAAG,CAAC,UAAe,EAAO,EAAE;IAC5D,OAAO,IAAA,0BAAQ,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AACjE,CAAC,CAAC;AAFW,QAAA,uBAAuB,2BAElC;AAEK,MAAM,uBAAuB,GAAG,CAAC,GAAQ,EAAE,SAAyB,EAAO,EAAE;IAChF,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,CAAC;QACtE,OAAO,GAAG,CAAC;IACf,CAAC;IAED,GAAG,CAAC,SAAS,CAAC,GAAG,IAAA,+BAAuB,EAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IACzD,OAAO,GAAG,CAAC;AACf,CAAC,CAAC;AAPW,QAAA,uBAAuB,2BAOlC","sourcesContent":["import { isString } from \"class-validator\";\n\nexport const normalizeTextFieldValue = (fieldValue: any): any => {\n return isString(fieldValue) ? fieldValue.trim() : fieldValue;\n};\n\nexport const normalizeTextFieldInDto = (dto: any, fieldName?: string | null): any => {\n if (!fieldName || !Object.prototype.hasOwnProperty.call(dto, fieldName)) {\n return dto;\n }\n\n dto[fieldName] = normalizeTextFieldValue(dto[fieldName]);\n return dto;\n};\n"]}
@@ -44,6 +44,7 @@ export declare class ChatterMessageService extends CRUDService<ChatterMessage> {
44
44
  private parseMessageBodyMentions;
45
45
  private renderMentionTokens;
46
46
  private validateChatterMediaFiles;
47
+ private validateChatterAttachmentsForFields;
47
48
  private publishChatterMentionNotifications;
48
49
  getMentionableUsers(search?: string, limit?: number): Promise<Array<{
49
50
  id: number;
@@ -1 +1 @@
1
- {"version":3,"file":"chatter-message.service.d.ts","sourceRoot":"","sources":["../../src/services/chatter-message.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chatter-message.service.d.ts","sourceRoot":"","sources":["../../src/services/chatter-message.service.ts"],"names":[],"mappings":"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"}
@@ -23,6 +23,7 @@ const strings_1 = require("@angular-devkit/core/src/utils/strings");
23
23
  const chatter_message_constants_1 = require("../constants/chatter-message.constants");
24
24
  const media_file_types_1 = require("../constants/media-file-types");
25
25
  const error_messages_1 = require("../constants/error-messages");
26
+ const MediaFieldCrudManager_1 = require("../helpers/field-crud-managers/MediaFieldCrudManager");
26
27
  const model_metadata_helper_service_1 = require("../helpers/model-metadata-helper.service");
27
28
  const string_helper_1 = require("../helpers/string.helper");
28
29
  const chatter_message_details_repository_1 = require("../repository/chatter-message-details.repository");
@@ -145,6 +146,26 @@ let ChatterMessageService = ChatterMessageService_1 = class ChatterMessageServic
145
146
  throw new common_1.BadRequestException('Dangerous file types are not allowed in chatter attachments.');
146
147
  }
147
148
  }
149
+ validateChatterAttachmentsForFields(files, mediaFields, isUpdate) {
150
+ for (const mediaField of mediaFields) {
151
+ const media = files.filter(multerFile => multerFile.fieldname === mediaField.name);
152
+ if (media.length === 0)
153
+ continue;
154
+ const validator = new MediaFieldCrudManager_1.MediaFieldCrudManager({
155
+ type: mediaField.type,
156
+ required: mediaField.required,
157
+ fieldName: mediaField.name,
158
+ mediaMaxSizeKb: mediaField.mediaMaxSizeKb,
159
+ mediaTypes: mediaField.mediaTypes,
160
+ mediaAllowedExtensions: mediaField.mediaAllowedExtensions,
161
+ isUpdate,
162
+ });
163
+ const validationErrors = validator.validate({}, media);
164
+ if (validationErrors.length > 0) {
165
+ throw new common_1.BadRequestException(validationErrors.map(error => error.error).join(', '));
166
+ }
167
+ }
168
+ }
148
169
  async publishChatterMentionNotifications(message, model) {
149
170
  if (message.messageType !== chatter_message_constants_1.CHATTER_MESSAGE_TYPE.CUSTOM || message.messageSubType !== chatter_message_constants_1.CHATTER_MESSAGE_SUBTYPE.NOTE) {
150
171
  return;
@@ -251,6 +272,21 @@ let ChatterMessageService = ChatterMessageService_1 = class ChatterMessageServic
251
272
  throw new common_1.BadRequestException('Message body cannot be empty.');
252
273
  }
253
274
  this.validateChatterMediaFiles(files);
275
+ let chatterModel = null;
276
+ let mediaFields = [];
277
+ if (removeAttachmentIds.length > 0 || hasNewFiles) {
278
+ chatterModel = await this.modelMetadataService.findOneBySingularName('chatterMessage', {
279
+ fields: {
280
+ model: true,
281
+ mediaStorageProvider: true,
282
+ },
283
+ module: true,
284
+ });
285
+ mediaFields = chatterModel.fields.filter(field => field.type === 'mediaSingle' || field.type === 'mediaMultiple');
286
+ if (hasNewFiles) {
287
+ this.validateChatterAttachmentsForFields(files, mediaFields, true);
288
+ }
289
+ }
254
290
  if (hasMessageBody) {
255
291
  message.messageBody = trimmedMessageBody;
256
292
  }
@@ -265,21 +301,13 @@ let ChatterMessageService = ChatterMessageService_1 = class ChatterMessageServic
265
301
  message.updatedAt = new Date();
266
302
  const savedMessage = await this.repo.save(message);
267
303
  if (removeAttachmentIds.length > 0 || hasNewFiles) {
268
- const model = await this.modelMetadataService.findOneBySingularName('chatterMessage', {
269
- fields: {
270
- model: true,
271
- mediaStorageProvider: true,
272
- },
273
- module: true,
274
- });
275
- const mediaFields = model.fields.filter(field => field.type === 'mediaSingle' || field.type === 'mediaMultiple');
276
304
  const attachmentFieldIds = mediaFields.map(field => field.id);
277
305
  if (removeAttachmentIds.length > 0 && attachmentFieldIds.length > 0) {
278
306
  const mediaToRemove = await this.mediaRepository.find({
279
307
  where: {
280
308
  id: (0, typeorm_2.In)(removeAttachmentIds),
281
309
  entityId: savedMessage.id,
282
- modelMetadata: { id: model.id },
310
+ modelMetadata: { id: chatterModel.id },
283
311
  fieldMetadata: { id: (0, typeorm_2.In)(attachmentFieldIds) },
284
312
  },
285
313
  relations: {
@@ -331,16 +359,20 @@ let ChatterMessageService = ChatterMessageService_1 = class ChatterMessageServic
331
359
  });
332
360
  chatterMessage.modelDisplayName = model?.displayName ?? null;
333
361
  this.stampMessageAuditFields(chatterMessage);
334
- const savedMessage = await this.repo.save(chatterMessage);
362
+ let mediaFields = [];
335
363
  if (files && files.length > 0) {
336
- const model = await this.modelMetadataService.findOneBySingularName('chatterMessage', {
364
+ const chatterModel = await this.modelMetadataService.findOneBySingularName('chatterMessage', {
337
365
  fields: {
338
366
  model: true,
339
367
  mediaStorageProvider: true,
340
368
  },
341
369
  module: true,
342
370
  });
343
- const mediaFields = model.fields.filter(field => field.type === 'mediaSingle' || field.type === 'mediaMultiple');
371
+ mediaFields = chatterModel.fields.filter(field => field.type === 'mediaSingle' || field.type === 'mediaMultiple');
372
+ this.validateChatterAttachmentsForFields(files, mediaFields, false);
373
+ }
374
+ const savedMessage = await this.repo.save(chatterMessage);
375
+ if (files && files.length > 0) {
344
376
  for (const mediaField of mediaFields) {
345
377
  const media = files.filter(multerFile => multerFile.fieldname === mediaField.name);
346
378
  if (media.length > 0) {