@dynamatix/cat-shared 0.0.79 → 0.0.80

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/README.md CHANGED
@@ -1,7 +1,7 @@
1
- This is the shared library for Catura Services.
2
- # Purpose
3
-
4
- The purposes of this repository are to include:
5
- - All the models of Catura
6
- - Shared services in Catura
1
+ This is the shared library for Catura Services.
2
+ # Purpose
3
+
4
+ The purposes of this repository are to include:
5
+ - All the models of Catura
6
+ - Shared services in Catura
7
7
  - Shared middlewares in Catura
package/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export * from './models/index.js';
2
- export * from './middlewares/index.js';
1
+ export * from './models/index.js';
2
+ export * from './middlewares/index.js';
3
3
  export * from './services/index.js';
@@ -1,140 +1,140 @@
1
- import AuditConfigModel from '../models/audit-config.model.js';
2
- import AuditLog from '../models/audit.model.js';
3
- import ValueReferenceMap from '../models/value-reference-map.model.js';
4
- import { getContext } from '../services/request-context.service.js';
5
- import mongoose from 'mongoose';
6
-
7
- let onAuditLogCreated = null;
8
-
9
- // Generic resolver: fetch display values using ValueReferenceMap
10
- async function resolveAuditValues(field, oldValue, newValue) {
11
- const map = await ValueReferenceMap.findOne({ field });
12
- if (!map || (!oldValue && !newValue)) return { oldValue, newValue };
13
-
14
- const Model = mongoose.models[map.model];
15
- if (!Model) return { oldValue, newValue };
16
-
17
- const [oldDoc, newDoc] = await Promise.all([
18
- oldValue ? Model.findById(oldValue).lean() : null,
19
- newValue ? Model.findById(newValue).lean() : null
20
- ]);
21
-
22
- return {
23
- oldValue: oldDoc?.[map.displayField] || oldValue,
24
- newValue: newDoc?.[map.displayField] || newValue
25
- };
26
- }
27
-
28
- async function resolveExternalData(descriptionResolutorForExternalData, recordId) {
29
- const map = await ValueReferenceMap.findOne({ field: descriptionResolutorForExternalData });
30
- const Model = mongoose.models[map.model];
31
- if (!Model) return "";
32
- const doc = await Model.findById(recordId).lean()
33
- return doc[map.displayField];
34
- }
35
-
36
- function applyAuditMiddleware(schema, collectionName) {
37
- // Handle creation audit
38
- schema.post('save', async function (doc) {
39
- const auditConfig = await AuditConfigModel.findOne({ collectionName });
40
- if (!auditConfig?.trackCreation) return;
41
-
42
- const context = getContext();
43
- const userId = context?.userId || 'anonymous';
44
- const contextId = context?.contextId;
45
-
46
- const log = {
47
- name: `${collectionName} created`,
48
- recordId: contextId || doc._id,
49
- oldValue: null,
50
- newValue: 'Document created',
51
- createdBy: userId,
52
- contextId
53
- };
54
- if (auditConfig.descriptionResolutorForExternalData) {
55
- log.externalData.description = await resolveExternalData(auditConfig.descriptionResolutorForExternalData, doc[descriptionResolutorForExternalData])
56
- log.externalData.contextId = contextId;
57
- }
58
- await AuditLog.create(log);
59
- await updateContextAuditCount(contextId, 1);
60
-
61
- if (onAuditLogCreated) {
62
- await onAuditLogCreated([log], contextId);
63
- }
64
- });
65
-
66
- // Capture the original doc before update
67
- schema.pre(['findOneAndUpdate', 'findByIdAndUpdate'], async function (next) {
68
- this._originalDoc = await this.model.findOne(this.getQuery()).lean();
69
- next();
70
- });
71
-
72
- // Handle update audits
73
- schema.post(['findOneAndUpdate', 'findByIdAndUpdate'], async function (result) {
74
- if (!result) return;
75
-
76
- const auditConfig = await AuditConfigModel.findOne({ collectionName });
77
- if (!auditConfig?.fields?.length) return;
78
-
79
- const update = this.getUpdate();
80
- const logs = [];
81
- const context = getContext();
82
- const userId = context?.userId || 'anonymous';
83
- const contextId = context?.contextId;
84
-
85
- for (const field of auditConfig.fields) {
86
- const hasChanged =
87
- update?.$set?.hasOwnProperty(field) || update?.hasOwnProperty(field);
88
-
89
- if (hasChanged) {
90
- const newValue = update?.$set?.[field] ?? update?.[field];
91
- const oldValue = this._originalDoc ? this._originalDoc[field] : '';
92
-
93
- if (oldValue !== newValue) {
94
- // Resolve human-readable values
95
- const { oldValue: resolvedOld, newValue: resolvedNew } =
96
- await resolveAuditValues(field, oldValue, newValue);
97
-
98
- let externalData = {};
99
- if (auditConfig.descriptionResolutorForExternalData) {
100
- externalData.description = await resolveExternalData(auditConfig.descriptionResolutorForExternalData, result[auditConfig.descriptionResolutorForExternalData])
101
- externalData.contextId = contextId || result._id;
102
- }
103
- logs.push({
104
- name: `${collectionName}.${field}`,
105
- recordId: contextId || result._id,
106
- oldValue: resolvedOld,
107
- newValue: resolvedNew,
108
- createdBy: userId,
109
- externalData
110
- });
111
- }
112
- }
113
- }
114
-
115
- if (logs.length) {
116
- await AuditLog.insertMany(logs);
117
- await updateContextAuditCount(contextId, logs.length);
118
- if (onAuditLogCreated) {
119
- await onAuditLogCreated(logs, contextId);
120
- }
121
- }
122
- });
123
- }
124
-
125
- async function updateContextAuditCount(contextId, count) {
126
- count = Number(count);
127
- if (!contextId || isNaN(count)) return;
128
- const model = mongoose.models['Application'];
129
- await model.findByIdAndUpdate(
130
- { _id: contextId },
131
- { $inc: { newAuditRecordsCount: count } },
132
- { new: true, upsert: true }
133
- );
134
- }
135
-
136
- export function registerAuditHook(callback) {
137
- onAuditLogCreated = callback;
138
- }
139
-
140
- export default applyAuditMiddleware;
1
+ import AuditConfigModel from '../models/audit-config.model.js';
2
+ import AuditLog from '../models/audit.model.js';
3
+ import ValueReferenceMap from '../models/value-reference-map.model.js';
4
+ import { getContext } from '../services/request-context.service.js';
5
+ import mongoose from 'mongoose';
6
+
7
+ let onAuditLogCreated = null;
8
+
9
+ // Generic resolver: fetch display values using ValueReferenceMap
10
+ async function resolveAuditValues(field, oldValue, newValue) {
11
+ const map = await ValueReferenceMap.findOne({ field });
12
+ if (!map || (!oldValue && !newValue)) return { oldValue, newValue };
13
+
14
+ const Model = mongoose.models[map.model];
15
+ if (!Model) return { oldValue, newValue };
16
+
17
+ const [oldDoc, newDoc] = await Promise.all([
18
+ oldValue ? Model.findById(oldValue).lean() : null,
19
+ newValue ? Model.findById(newValue).lean() : null
20
+ ]);
21
+
22
+ return {
23
+ oldValue: oldDoc?.[map.displayField] || oldValue,
24
+ newValue: newDoc?.[map.displayField] || newValue
25
+ };
26
+ }
27
+
28
+ async function resolveExternalData(descriptionResolutorForExternalData, recordId) {
29
+ const map = await ValueReferenceMap.findOne({ field: descriptionResolutorForExternalData });
30
+ const Model = mongoose.models[map.model];
31
+ if (!Model) return "";
32
+ const doc = await Model.findById(recordId).lean()
33
+ return doc[map.displayField];
34
+ }
35
+
36
+ function applyAuditMiddleware(schema, collectionName) {
37
+ // Handle creation audit
38
+ schema.post('save', async function (doc) {
39
+ const auditConfig = await AuditConfigModel.findOne({ collectionName });
40
+ if (!auditConfig?.trackCreation) return;
41
+
42
+ const context = getContext();
43
+ const userId = context?.userId || 'anonymous';
44
+ const contextId = context?.contextId;
45
+
46
+ const log = {
47
+ name: `${collectionName} created`,
48
+ recordId: contextId || doc._id,
49
+ oldValue: null,
50
+ newValue: 'Document created',
51
+ createdBy: userId,
52
+ contextId
53
+ };
54
+ if (auditConfig.descriptionResolutorForExternalData) {
55
+ log.externalData.description = await resolveExternalData(auditConfig.descriptionResolutorForExternalData, doc[auditConfig.descriptionResolutorForExternalData])
56
+ log.externalData.contextId = contextId;
57
+ }
58
+ await AuditLog.create(log);
59
+ await updateContextAuditCount(contextId, 1);
60
+
61
+ if (onAuditLogCreated) {
62
+ await onAuditLogCreated([log], contextId);
63
+ }
64
+ });
65
+
66
+ // Capture the original doc before update
67
+ schema.pre(['findOneAndUpdate', 'findByIdAndUpdate'], async function (next) {
68
+ this._originalDoc = await this.model.findOne(this.getQuery()).lean();
69
+ next();
70
+ });
71
+
72
+ // Handle update audits
73
+ schema.post(['findOneAndUpdate', 'findByIdAndUpdate'], async function (result) {
74
+ if (!result) return;
75
+
76
+ const auditConfig = await AuditConfigModel.findOne({ collectionName });
77
+ if (!auditConfig?.fields?.length) return;
78
+
79
+ const update = this.getUpdate();
80
+ const logs = [];
81
+ const context = getContext();
82
+ const userId = context?.userId || 'anonymous';
83
+ const contextId = context?.contextId;
84
+
85
+ for (const field of auditConfig.fields) {
86
+ const hasChanged =
87
+ update?.$set?.hasOwnProperty(field) || update?.hasOwnProperty(field);
88
+
89
+ if (hasChanged) {
90
+ const newValue = update?.$set?.[field] ?? update?.[field];
91
+ const oldValue = this._originalDoc ? this._originalDoc[field] : '';
92
+
93
+ if (oldValue !== newValue) {
94
+ // Resolve human-readable values
95
+ const { oldValue: resolvedOld, newValue: resolvedNew } =
96
+ await resolveAuditValues(field, oldValue, newValue);
97
+
98
+ let externalData = {};
99
+ if (auditConfig.descriptionResolutorForExternalData) {
100
+ externalData.description = await resolveExternalData(auditConfig.descriptionResolutorForExternalData, result[auditConfig.descriptionResolutorForExternalData])
101
+ externalData.contextId = contextId || result._id;
102
+ }
103
+ logs.push({
104
+ name: `${collectionName}.${field}`,
105
+ recordId: contextId || result._id,
106
+ oldValue: resolvedOld,
107
+ newValue: resolvedNew,
108
+ createdBy: userId,
109
+ externalData
110
+ });
111
+ }
112
+ }
113
+ }
114
+
115
+ if (logs.length) {
116
+ await AuditLog.insertMany(logs);
117
+ await updateContextAuditCount(contextId, logs.length);
118
+ if (onAuditLogCreated) {
119
+ await onAuditLogCreated(logs, contextId);
120
+ }
121
+ }
122
+ });
123
+ }
124
+
125
+ async function updateContextAuditCount(contextId, count) {
126
+ count = Number(count);
127
+ if (!contextId || isNaN(count)) return;
128
+ const model = mongoose.models['Application'];
129
+ await model.findByIdAndUpdate(
130
+ { _id: contextId },
131
+ { $inc: { newAuditRecordsCount: count } },
132
+ { new: true, upsert: true }
133
+ );
134
+ }
135
+
136
+ export function registerAuditHook(callback) {
137
+ onAuditLogCreated = callback;
138
+ }
139
+
140
+ export default applyAuditMiddleware;
@@ -1,2 +1,2 @@
1
- export {default as applyAuditMiddleware} from './audit.middleware.js';
2
- export { registerAuditHook } from './audit.middleware.js';
1
+ export {default as applyAuditMiddleware} from './audit.middleware.js';
2
+ export { registerAuditHook } from './audit.middleware.js';
@@ -1,13 +1,13 @@
1
- import mongoose from 'mongoose';
2
-
3
- const auditConfigSchema = new mongoose.Schema({
4
- collectionName: String,
5
- fields: [String],
6
- trackCreation: { type: Boolean, default: false },
7
- descriptionResolutorForExternalData: { type: String, default: null },
8
- });
9
-
10
- const AuditConfigModel = mongoose.models.AuditConfig || mongoose.model('AuditConfig', auditConfigSchema);
11
-
12
-
13
- export default AuditConfigModel;
1
+ import mongoose from 'mongoose';
2
+
3
+ const auditConfigSchema = new mongoose.Schema({
4
+ collectionName: String,
5
+ fields: [String],
6
+ trackCreation: { type: Boolean, default: false },
7
+ descriptionResolutorForExternalData: { type: String, default: null },
8
+ });
9
+
10
+ const AuditConfigModel = mongoose.models.AuditConfig || mongoose.model('AuditConfig', auditConfigSchema);
11
+
12
+
13
+ export default AuditConfigModel;
@@ -1,16 +1,16 @@
1
- import mongoose from 'mongoose';
2
-
3
- const auditSchema = new mongoose.Schema({
4
- name: String,
5
- recordId: mongoose.Schema.Types.ObjectId,
6
- contextId: mongoose.Schema.Types.ObjectId,
7
- oldValue: mongoose.Schema.Types.Mixed,
8
- newValue: mongoose.Schema.Types.Mixed,
9
- timestamp: { type: Date, default: Date.now },
10
- createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
11
- externalData: mongoose.Schema.Types.Mixed
12
- });
13
-
14
- const AuditLog = mongoose.models.AuditLog || mongoose.model('AuditLog', auditSchema);
15
-
16
- export default AuditLog;
1
+ import mongoose from 'mongoose';
2
+
3
+ const auditSchema = new mongoose.Schema({
4
+ name: String,
5
+ recordId: mongoose.Schema.Types.ObjectId,
6
+ contextId: mongoose.Schema.Types.ObjectId,
7
+ oldValue: mongoose.Schema.Types.Mixed,
8
+ newValue: mongoose.Schema.Types.Mixed,
9
+ timestamp: { type: Date, default: Date.now },
10
+ createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
11
+ externalData: mongoose.Schema.Types.Mixed
12
+ });
13
+
14
+ const AuditLog = mongoose.models.AuditLog || mongoose.model('AuditLog', auditSchema);
15
+
16
+ export default AuditLog;
@@ -1,269 +1,269 @@
1
- import mongoose from 'mongoose';
2
-
3
- const optionSchema = new mongoose.Schema({
4
- label: { type: mongoose.Schema.Types.Mixed },
5
- value: { type: mongoose.Schema.Types.Mixed },
6
- text: { type: mongoose.Schema.Types.Mixed }
7
-
8
- }, { _id: false });
9
-
10
- const formfieldSchema = new mongoose.Schema({
11
- isFutureDateBlocked: {
12
- type: Boolean,
13
- },
14
- addToPayload: {
15
- type: Boolean,
16
- default: false
17
- },
18
- fieldName: {
19
- type: String,
20
- required: true,
21
- trim: true
22
- },
23
- isHidden: {
24
- type: Boolean,
25
- default: false
26
- },
27
- isEditable: {
28
- type: Boolean,
29
- default: true
30
- },
31
- size: {
32
- type: Number,
33
- default: 6,
34
- enum: [3, 4, 6, 8, 10, 12],
35
- },
36
- layout: {
37
- type: String,
38
- enum: ['horizontal', 'vertical'],
39
- },
40
- label: {
41
- type: String,
42
- required: true,
43
- trim: true
44
- },
45
- dataType: {
46
- type: String,
47
- required: true,
48
- enum: ['text-area', 'string', 'number', 'boolean-check', 'boolean-radio', 'percentage', 'date', 'array', 'object', 'select', 'radio', 'drop-down', 'sort-code', 'post-code', 'pound', 'lookup', 'multi-select', 'email', 'phone', 'internationalPhone'] // Added common form field types
49
- },
50
- isRequired: {
51
- type: Boolean,
52
- default: false
53
- },
54
- helpText: {
55
- type: String,
56
- default: null
57
- },
58
- isForceUpdate: {
59
- type: Boolean,
60
- default: false
61
- },
62
- isShowClearIcon: {
63
- type: Boolean,
64
- default: true
65
- },
66
- requiredErrorMessage: {
67
- type: String,
68
- default: 'Field is required'
69
- },
70
- defaultValue: {
71
- type: mongoose.Schema.Types.Mixed
72
- },
73
- validationRules: [{
74
- type: mongoose.Schema.Types.Mixed,
75
- default: {}
76
- }],
77
- visibilityCondition: { // (LendingType=='BTL' || ApplicationType=='Company')
78
- type: mongoose.Schema.Types.Mixed,
79
- default: null
80
- },
81
- options: [optionSchema],
82
- section: {
83
- type: String,
84
- default: null
85
- },
86
- keyIconClass: {
87
- type: String,
88
- default: null
89
- },
90
- keyIconStyle: {
91
- type: Object,
92
- default: null
93
- },
94
- // Ex: sort-code, post-code, pound, drop-down, lookup
95
- uiHint: {
96
- type: String
97
- },
98
- list: {
99
- name: { // Lookup.BusinessType, DocumentType(collection)
100
- type: String
101
- },
102
- label: { // name
103
- type: String
104
- },
105
- value: { // _id
106
- type: String
107
- },
108
- listFilterQuery: { // MongoDB query ex: applicationId:applicationId
109
- type: mongoose.Schema.Types.Mixed,
110
- default: null
111
- },
112
- dynamicSource: {
113
- sourceMapping: [{
114
- sourceField: {
115
- type: String,
116
- default: null
117
- },
118
- sourceValue: { type: mongoose.Schema.Types.Mixed },
119
- listName: { type: String }, // The collection name to use when source field has this value
120
- fixedValue: { type: mongoose.Schema.Types.Mixed } // It's not req , and it can be a number like 0 , or a string etc.
121
- }]
122
- }
123
- },
124
- isSyncEnabled: { // Fixed typo (was isSyncEnabed)
125
- type: Boolean,
126
- default: true
127
- },
128
- dataElement: { //<collectionName>.<fieldName>
129
- type: String,
130
- default: null
131
- },
132
- syncTargetDataElement: { //<collectionName>.<fieldName> of Apprivo
133
- type: String,
134
- default: null
135
- },
136
- syncMapping: mongoose.Schema.Types.Mixed, // Ex: {true:'Checked', false: ''}
137
- order: {
138
- type: Number,
139
- default: 0
140
- },
141
- maxLength: {
142
- type: Number,
143
- default: null,
144
- min: 0
145
- },
146
- maxValue: { // this is not required used only when given else ignore ex- 100% max
147
- type: mongoose.Schema.Types.Mixed
148
- },
149
- minValue: { // this is not required used only when given else ignore ex- 0% min
150
- type: Number
151
- },
152
- isReadOnly: {
153
- type: Boolean,
154
- default: false
155
- },
156
- collectionName: { // name of collection for field if field doesnt belong to main collection
157
- type: String,
158
- default: null
159
- },
160
- foreignReferenceField: { // Ex: when field is from forieng collection then foreignReferenceField could be applicationId(which refers to the application)
161
- type: String,
162
- default: null
163
- },
164
- shouldfilterOptionsAfterAdd: {
165
- type : Boolean,
166
- default : false
167
- },
168
- shouldfilterOptionsAfterDelete: {
169
- type : Boolean,
170
- default : false
171
- }
172
- }, { timestamps: true, _id: false });
173
-
174
- const formConfigurationSchema = new mongoose.Schema({
175
- formName: {
176
- type: String,
177
- required: true,
178
- trim: true,
179
- unique: true // Consider making form names unique
180
- },
181
- collectionName: {
182
- type: String,
183
- required: true
184
- },
185
- sectionLayout: {
186
- type: String,
187
- trim: true
188
- },
189
- parentKey: String,
190
- populations: [Object],
191
- visibilityCondition: {
192
- type: mongoose.Schema.Types.Mixed,
193
- default: null
194
- },
195
- sections: [{
196
- sectionName: {
197
- type: String,
198
- trim: true
199
- },
200
- sectionLabel: {
201
- type: String,
202
- trim: true
203
- },
204
- isArray: {
205
- type: Boolean,
206
- default: false
207
- },
208
- isTable: {
209
- type: Boolean,
210
- default: false
211
- },
212
- dataFromSectionName: {
213
- type: Boolean,
214
- default: false
215
- },
216
- fields: [formfieldSchema],
217
- order: {
218
- type: Number,
219
- default: 0
220
- },
221
- visibilityCondition: { // Added section-level visibility
222
- type: mongoose.Schema.Types.Mixed,
223
- default: null
224
- },
225
- sections: [{
226
- sectionName: {
227
- type: String,
228
- trim: true
229
- },
230
- sectionLabel: {
231
- type: String,
232
- trim: true
233
- },
234
- fields: [formfieldSchema],
235
- order: {
236
- type: Number,
237
- default: 0
238
- },
239
- isTable: {
240
- type: Boolean,
241
- default: false
242
- },
243
- visibilityCondition: { // Added section-level visibility
244
- type: mongoose.Schema.Types.Mixed,
245
- default: null
246
- }
247
- }]
248
- }],
249
- isActive: { // Consider adding status flag
250
- type: Boolean,
251
- default: true
252
- },
253
- isDeleteApprivoSync: {
254
- type: Boolean,
255
- default: true
256
- },
257
- isCreateApprivoSync: {
258
- type: Boolean,
259
- default: true
260
- },
261
- version: { // Consider adding versioning
262
- type: Number,
263
- default: 1
264
- }
265
- }, { timestamps: true });
266
-
267
- const FormConfigurationModel = mongoose.models.FormConfiguration || mongoose.model('FormConfiguration', formConfigurationSchema);
268
-
269
- export default FormConfigurationModel;
1
+ import mongoose from 'mongoose';
2
+
3
+ const optionSchema = new mongoose.Schema({
4
+ label: { type: mongoose.Schema.Types.Mixed },
5
+ value: { type: mongoose.Schema.Types.Mixed },
6
+ text: { type: mongoose.Schema.Types.Mixed }
7
+
8
+ }, { _id: false });
9
+
10
+ const formfieldSchema = new mongoose.Schema({
11
+ isFutureDateBlocked: {
12
+ type: Boolean,
13
+ },
14
+ addToPayload: {
15
+ type: Boolean,
16
+ default: false
17
+ },
18
+ fieldName: {
19
+ type: String,
20
+ required: true,
21
+ trim: true
22
+ },
23
+ isHidden: {
24
+ type: Boolean,
25
+ default: false
26
+ },
27
+ isEditable: {
28
+ type: Boolean,
29
+ default: true
30
+ },
31
+ size: {
32
+ type: Number,
33
+ default: 6,
34
+ enum: [3, 4, 6, 8, 10, 12],
35
+ },
36
+ layout: {
37
+ type: String,
38
+ enum: ['horizontal', 'vertical'],
39
+ },
40
+ label: {
41
+ type: String,
42
+ required: true,
43
+ trim: true
44
+ },
45
+ dataType: {
46
+ type: String,
47
+ required: true,
48
+ enum: ['text-area', 'string', 'number', 'boolean-check', 'boolean-radio', 'percentage', 'date', 'array', 'object', 'select', 'radio', 'drop-down', 'sort-code', 'post-code', 'pound', 'lookup', 'multi-select', 'email', 'phone', 'internationalPhone'] // Added common form field types
49
+ },
50
+ isRequired: {
51
+ type: Boolean,
52
+ default: false
53
+ },
54
+ helpText: {
55
+ type: String,
56
+ default: null
57
+ },
58
+ isForceUpdate: {
59
+ type: Boolean,
60
+ default: false
61
+ },
62
+ isShowClearIcon: {
63
+ type: Boolean,
64
+ default: true
65
+ },
66
+ requiredErrorMessage: {
67
+ type: String,
68
+ default: 'Field is required'
69
+ },
70
+ defaultValue: {
71
+ type: mongoose.Schema.Types.Mixed
72
+ },
73
+ validationRules: [{
74
+ type: mongoose.Schema.Types.Mixed,
75
+ default: {}
76
+ }],
77
+ visibilityCondition: { // (LendingType=='BTL' || ApplicationType=='Company')
78
+ type: mongoose.Schema.Types.Mixed,
79
+ default: null
80
+ },
81
+ options: [optionSchema],
82
+ section: {
83
+ type: String,
84
+ default: null
85
+ },
86
+ keyIconClass: {
87
+ type: String,
88
+ default: null
89
+ },
90
+ keyIconStyle: {
91
+ type: Object,
92
+ default: null
93
+ },
94
+ // Ex: sort-code, post-code, pound, drop-down, lookup
95
+ uiHint: {
96
+ type: String
97
+ },
98
+ list: {
99
+ name: { // Lookup.BusinessType, DocumentType(collection)
100
+ type: String
101
+ },
102
+ label: { // name
103
+ type: String
104
+ },
105
+ value: { // _id
106
+ type: String
107
+ },
108
+ listFilterQuery: { // MongoDB query ex: applicationId:applicationId
109
+ type: mongoose.Schema.Types.Mixed,
110
+ default: null
111
+ },
112
+ dynamicSource: {
113
+ sourceMapping: [{
114
+ sourceField: {
115
+ type: String,
116
+ default: null
117
+ },
118
+ sourceValue: { type: mongoose.Schema.Types.Mixed },
119
+ listName: { type: String }, // The collection name to use when source field has this value
120
+ fixedValue: { type: mongoose.Schema.Types.Mixed } // It's not req , and it can be a number like 0 , or a string etc.
121
+ }]
122
+ }
123
+ },
124
+ isSyncEnabled: { // Fixed typo (was isSyncEnabed)
125
+ type: Boolean,
126
+ default: true
127
+ },
128
+ dataElement: { //<collectionName>.<fieldName>
129
+ type: String,
130
+ default: null
131
+ },
132
+ syncTargetDataElement: { //<collectionName>.<fieldName> of Apprivo
133
+ type: String,
134
+ default: null
135
+ },
136
+ syncMapping: mongoose.Schema.Types.Mixed, // Ex: {true:'Checked', false: ''}
137
+ order: {
138
+ type: Number,
139
+ default: 0
140
+ },
141
+ maxLength: {
142
+ type: Number,
143
+ default: null,
144
+ min: 0
145
+ },
146
+ maxValue: { // this is not required used only when given else ignore ex- 100% max
147
+ type: mongoose.Schema.Types.Mixed
148
+ },
149
+ minValue: { // this is not required used only when given else ignore ex- 0% min
150
+ type: Number
151
+ },
152
+ isReadOnly: {
153
+ type: Boolean,
154
+ default: false
155
+ },
156
+ collectionName: { // name of collection for field if field doesnt belong to main collection
157
+ type: String,
158
+ default: null
159
+ },
160
+ foreignReferenceField: { // Ex: when field is from forieng collection then foreignReferenceField could be applicationId(which refers to the application)
161
+ type: String,
162
+ default: null
163
+ },
164
+ shouldfilterOptionsAfterAdd: {
165
+ type : Boolean,
166
+ default : false
167
+ },
168
+ shouldfilterOptionsAfterDelete: {
169
+ type : Boolean,
170
+ default : false
171
+ }
172
+ }, { timestamps: true, _id: false });
173
+
174
+ const formConfigurationSchema = new mongoose.Schema({
175
+ formName: {
176
+ type: String,
177
+ required: true,
178
+ trim: true,
179
+ unique: true // Consider making form names unique
180
+ },
181
+ collectionName: {
182
+ type: String,
183
+ required: true
184
+ },
185
+ sectionLayout: {
186
+ type: String,
187
+ trim: true
188
+ },
189
+ parentKey: String,
190
+ populations: [Object],
191
+ visibilityCondition: {
192
+ type: mongoose.Schema.Types.Mixed,
193
+ default: null
194
+ },
195
+ sections: [{
196
+ sectionName: {
197
+ type: String,
198
+ trim: true
199
+ },
200
+ sectionLabel: {
201
+ type: String,
202
+ trim: true
203
+ },
204
+ isArray: {
205
+ type: Boolean,
206
+ default: false
207
+ },
208
+ isTable: {
209
+ type: Boolean,
210
+ default: false
211
+ },
212
+ dataFromSectionName: {
213
+ type: Boolean,
214
+ default: false
215
+ },
216
+ fields: [formfieldSchema],
217
+ order: {
218
+ type: Number,
219
+ default: 0
220
+ },
221
+ visibilityCondition: { // Added section-level visibility
222
+ type: mongoose.Schema.Types.Mixed,
223
+ default: null
224
+ },
225
+ sections: [{
226
+ sectionName: {
227
+ type: String,
228
+ trim: true
229
+ },
230
+ sectionLabel: {
231
+ type: String,
232
+ trim: true
233
+ },
234
+ fields: [formfieldSchema],
235
+ order: {
236
+ type: Number,
237
+ default: 0
238
+ },
239
+ isTable: {
240
+ type: Boolean,
241
+ default: false
242
+ },
243
+ visibilityCondition: { // Added section-level visibility
244
+ type: mongoose.Schema.Types.Mixed,
245
+ default: null
246
+ }
247
+ }]
248
+ }],
249
+ isActive: { // Consider adding status flag
250
+ type: Boolean,
251
+ default: true
252
+ },
253
+ isDeleteApprivoSync: {
254
+ type: Boolean,
255
+ default: true
256
+ },
257
+ isCreateApprivoSync: {
258
+ type: Boolean,
259
+ default: true
260
+ },
261
+ version: { // Consider adding versioning
262
+ type: Number,
263
+ default: 1
264
+ }
265
+ }, { timestamps: true });
266
+
267
+ const FormConfigurationModel = mongoose.models.FormConfiguration || mongoose.model('FormConfiguration', formConfigurationSchema);
268
+
269
+ export default FormConfigurationModel;
package/models/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { default as AuditConfigModel } from './audit-config.model.js';
2
- export { default as AuditModel } from './audit.model.js';
3
- export { default as ValueReferenceMapModel } from './value-reference-map.model.js';
1
+ export { default as AuditConfigModel } from './audit-config.model.js';
2
+ export { default as AuditModel } from './audit.model.js';
3
+ export { default as ValueReferenceMapModel } from './value-reference-map.model.js';
4
4
  export { default as FormConfigurationModel } from './form-configuration.model.js';
@@ -1,12 +1,12 @@
1
- import mongoose from 'mongoose';
2
-
3
- const valueReferenceMapSchema = new mongoose.Schema({
4
- field: String, // e.g. 'documentTypeId', 'createdBy', 'status'
5
- model: String, // e.g. 'DocumentType', 'User', 'ApplicationStatus'
6
- displayField: String, // e.g. 'name', 'fullName', 'label'
7
- });
8
-
9
- valueReferenceMapSchema.index({ field: 1 }, { unique: true });
10
-
11
- const ValueReferenceMapModel = mongoose.models.ValueReferenceMap || mongoose.model('ValueReferenceMap', valueReferenceMapSchema);
12
- export default ValueReferenceMapModel;
1
+ import mongoose from 'mongoose';
2
+
3
+ const valueReferenceMapSchema = new mongoose.Schema({
4
+ field: String, // e.g. 'documentTypeId', 'createdBy', 'status'
5
+ model: String, // e.g. 'DocumentType', 'User', 'ApplicationStatus'
6
+ displayField: String, // e.g. 'name', 'fullName', 'label'
7
+ });
8
+
9
+ valueReferenceMapSchema.index({ field: 1 }, { unique: true });
10
+
11
+ const ValueReferenceMapModel = mongoose.models.ValueReferenceMap || mongoose.model('ValueReferenceMap', valueReferenceMapSchema);
12
+ export default ValueReferenceMapModel;
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
- {
2
- "name": "@dynamatix/cat-shared",
3
- "version": "0.0.79",
4
- "main": "index.js",
5
- "scripts": {
6
- "test": "echo \"Error: no test specified\" && exit 1"
7
- },
8
- "author": "",
9
- "license": "ISC",
10
- "type": "module",
11
- "description": "",
12
- "exports": {
13
- "./models": "./models/index.js",
14
- "./middlewares": "./middlewares/index.js",
15
- "./services": "./services/index.js"
16
- },
17
- "dependencies": {
18
- "dotenv": "^16.4.7",
19
- "mongoose": "^8.13.1"
20
- }
21
- }
1
+ {
2
+ "name": "@dynamatix/cat-shared",
3
+ "version": "0.0.80",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1"
7
+ },
8
+ "author": "",
9
+ "license": "ISC",
10
+ "type": "module",
11
+ "description": "",
12
+ "exports": {
13
+ "./models": "./models/index.js",
14
+ "./middlewares": "./middlewares/index.js",
15
+ "./services": "./services/index.js"
16
+ },
17
+ "dependencies": {
18
+ "dotenv": "^16.4.7",
19
+ "mongoose": "^8.13.1"
20
+ }
21
+ }
@@ -1,66 +1,66 @@
1
- import mongoose, { model } from 'mongoose';
2
- import dotenv from 'dotenv';
3
- import ValueReferenceMapModel from '../models/value-reference-map.model.js';
4
-
5
- dotenv.config();
6
-
7
- const MONGO_URI = 'mongodb+srv://qa-user:vw4sIy3lZpyTPoX0@gatehouse-testing.e08r2.mongodb.net/gatehouse-qa?retryWrites=true&w=majority';
8
-
9
- // Grouped definition (DRY)
10
- const groupedMappings = [
11
- {
12
- model: 'DocumentType',
13
- displayField: 'name',
14
- fields: ['documentTypeId']
15
- },
16
- {
17
- model: 'User',
18
- displayField: 'fullName',
19
- fields: ['createdBy', 'updatedBy', 'ownerId','documentOwnerId']
20
- },
21
- {
22
- model: 'Applicant',
23
- displayField: 'firstName',
24
- fields: ['documentOwnerId', 'applicantId']
25
- }
26
- ];
27
-
28
- // Flatten the mappings
29
- const referenceMappings = groupedMappings.flatMap(group =>
30
- group.fields.map(field => ({
31
- field,
32
- model: group.model,
33
- displayField: group.displayField
34
- }))
35
- );
36
-
37
- async function seed() {
38
- try {
39
- console.log(MONGO_URI);
40
- await mongoose.connect(MONGO_URI);
41
- console.log('āœ… Connected to MongoDB');
42
-
43
- for (const mapping of referenceMappings) {
44
- const existing = await ValueReferenceMapModel.findOne({ field: mapping.field });
45
- if (existing) {
46
- await ValueReferenceMapModel.updateOne(
47
- { field: mapping.field },
48
- { $set: mapping }
49
- );
50
- console.log(`šŸ”„ Updated mapping for '${mapping.field}'`);
51
- } else {
52
- await ValueReferenceMapModel.create(mapping);
53
- console.log(`āž• Inserted mapping for '${mapping.field}'`);
54
- }
55
- }
56
-
57
- console.log('\n🌱 Seeding complete āœ…');
58
- } catch (err) {
59
- console.error('āŒ Seeding failed', err);
60
- } finally {
61
- await mongoose.disconnect();
62
- process.exit();
63
- }
64
- }
65
-
66
- seed();
1
+ import mongoose, { model } from 'mongoose';
2
+ import dotenv from 'dotenv';
3
+ import ValueReferenceMapModel from '../models/value-reference-map.model.js';
4
+
5
+ dotenv.config();
6
+
7
+ const MONGO_URI = 'mongodb+srv://qa-user:vw4sIy3lZpyTPoX0@gatehouse-testing.e08r2.mongodb.net/gatehouse-qa?retryWrites=true&w=majority';
8
+
9
+ // Grouped definition (DRY)
10
+ const groupedMappings = [
11
+ {
12
+ model: 'DocumentType',
13
+ displayField: 'name',
14
+ fields: ['documentTypeId']
15
+ },
16
+ {
17
+ model: 'User',
18
+ displayField: 'fullName',
19
+ fields: ['createdBy', 'updatedBy', 'ownerId','documentOwnerId']
20
+ },
21
+ {
22
+ model: 'Applicant',
23
+ displayField: 'firstName',
24
+ fields: ['documentOwnerId', 'applicantId']
25
+ }
26
+ ];
27
+
28
+ // Flatten the mappings
29
+ const referenceMappings = groupedMappings.flatMap(group =>
30
+ group.fields.map(field => ({
31
+ field,
32
+ model: group.model,
33
+ displayField: group.displayField
34
+ }))
35
+ );
36
+
37
+ async function seed() {
38
+ try {
39
+ console.log(MONGO_URI);
40
+ await mongoose.connect(MONGO_URI);
41
+ console.log('āœ… Connected to MongoDB');
42
+
43
+ for (const mapping of referenceMappings) {
44
+ const existing = await ValueReferenceMapModel.findOne({ field: mapping.field });
45
+ if (existing) {
46
+ await ValueReferenceMapModel.updateOne(
47
+ { field: mapping.field },
48
+ { $set: mapping }
49
+ );
50
+ console.log(`šŸ”„ Updated mapping for '${mapping.field}'`);
51
+ } else {
52
+ await ValueReferenceMapModel.create(mapping);
53
+ console.log(`āž• Inserted mapping for '${mapping.field}'`);
54
+ }
55
+ }
56
+
57
+ console.log('\n🌱 Seeding complete āœ…');
58
+ } catch (err) {
59
+ console.error('āŒ Seeding failed', err);
60
+ } finally {
61
+ await mongoose.disconnect();
62
+ process.exit();
63
+ }
64
+ }
65
+
66
+ seed();
@@ -1,2 +1,2 @@
1
-
2
-
1
+
2
+
package/services/index.js CHANGED
@@ -1 +1 @@
1
- export { getContext, setContext } from './request-context.service.js';
1
+ export { getContext, setContext } from './request-context.service.js';
@@ -1,8 +1,8 @@
1
- // utils/request-context.js
2
- import { AsyncLocalStorage } from 'node:async_hooks';
3
-
4
- const asyncLocalStorage = new AsyncLocalStorage();
5
-
6
- export const setContext = (data) => asyncLocalStorage.enterWith(data);
7
-
8
- export const getContext = () => asyncLocalStorage.getStore();
1
+ // utils/request-context.js
2
+ import { AsyncLocalStorage } from 'node:async_hooks';
3
+
4
+ const asyncLocalStorage = new AsyncLocalStorage();
5
+
6
+ export const setContext = (data) => asyncLocalStorage.enterWith(data);
7
+
8
+ export const getContext = () => asyncLocalStorage.getStore();