@autofleet/sadot 0.13.0-beta.8 → 0.13.1

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.
@@ -80,8 +80,9 @@ router.get('/', async (req, res) => {
80
80
  */
81
81
  router.get('/:validatorId', async (req, res) => {
82
82
  try {
83
- const { validatorId } = req.params;
84
- const validators = await ValidatorRepo.findAll({ id: validatorId });
83
+ const { validatorId, modelName } = req.params;
84
+ // Include disabled validators when fetching by ID
85
+ const validators = await ValidatorRepo.findAll({ id: validatorId, modelType: modelName }, { withDisabled: true });
85
86
  if (!validators.length) {
86
87
  throw new errors_1.ResourceNotFoundError('Validator not found');
87
88
  }
@@ -103,6 +104,11 @@ router.patch('/:validatorId', async (req, res) => {
103
104
  if (validatedPayload.schema) {
104
105
  (0, validator_schema_1.validateValidatorSchema)(validatedPayload.schema);
105
106
  }
107
+ // First verify the validator exists, including disabled ones
108
+ const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });
109
+ if (!existingValidators.length) {
110
+ throw new errors_1.ResourceNotFoundError('Validator not found');
111
+ }
106
112
  const [count, validators] = await ValidatorRepo.update(validatorId, validatedPayload);
107
113
  if (!count) {
108
114
  throw new errors_1.ResourceNotFoundError('Validator not found');
@@ -119,9 +125,14 @@ router.patch('/:validatorId', async (req, res) => {
119
125
  router.delete('/:validatorId', async (req, res) => {
120
126
  try {
121
127
  const { validatorId } = req.params;
128
+ // First verify the validator exists, including disabled ones
129
+ const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });
130
+ if (!existingValidators.length) {
131
+ throw new errors_1.ResourceNotFoundError('Validator not found');
132
+ }
122
133
  const [count] = await ValidatorRepo.disable(validatorId);
123
134
  if (!count) {
124
- throw new errors_1.ResourceNotFoundError('Validator not found');
135
+ throw new errors_1.ResourceNotFoundError('Validator failed to be disabled');
125
136
  }
126
137
  return res.status(http_status_codes_1.StatusCodes.NO_CONTENT).send();
127
138
  }
@@ -23,6 +23,7 @@ const validationSchemas = {
23
23
  }),
24
24
  update: joi_1.default.object({
25
25
  entityId: joi_1.default.string().uuid(),
26
+ entityType: joi_1.default.string(),
26
27
  schema: joi_1.default.object({
27
28
  type: joi_1.default.string().valid('object'),
28
29
  properties: joi_1.default.object({
@@ -44,6 +44,46 @@ const ajv = new ajv_1.default({
44
44
  $data: true, // Enable $data references
45
45
  });
46
46
  (0, ajv_formats_1.default)(ajv);
47
+ /**
48
+ * Helper function to manually copy object properties
49
+ * This is more efficient for large objects and avoids excessive object creation
50
+ */
51
+ // eslint-disable-next-line prefer-object-spread
52
+ const manualObjectCopy = (sourceObj, additionalProps) => ({ __proto__: null, ...sourceObj, ...additionalProps });
53
+ /**
54
+ * Fetches complete custom fields for an instance by merging DB values with update values
55
+ * This is needed for partial updates to ensure all related fields are available for validation
56
+ */
57
+ const getCompleteCustomFields = async (instance, options) => {
58
+ // If we don't have an instance id or no custom fields being updated, return original fields
59
+ if (!instance.id || !instance.customFields || Object.keys(instance.customFields).length === 0) {
60
+ return instance.customFields || {};
61
+ }
62
+ try {
63
+ const ModelClass = instance.constructor;
64
+ // Only select the customFields column to minimize data transfer
65
+ const currentCustomFields = await ModelClass.findOne({
66
+ where: { id: instance.id },
67
+ attributes: ['customFields'],
68
+ transaction: options.transaction,
69
+ raw: true, // Get plain object instead of model instance for better performance
70
+ });
71
+ if (currentCustomFields?.customFields) {
72
+ // Merge existing fields with update fields using our helper function
73
+ const completeFields = manualObjectCopy(currentCustomFields.customFields, instance.customFields);
74
+ logger_1.default.debug('sadot - fetched complete custom fields for validation', {
75
+ fieldsCount: Object.keys(completeFields).length,
76
+ updateFieldsCount: Object.keys(instance.customFields).length,
77
+ });
78
+ return completeFields;
79
+ }
80
+ }
81
+ catch (error) {
82
+ logger_1.default.error('sadot - error fetching complete model for validation', { error });
83
+ // Continue with partial data if we can't fetch the complete model
84
+ }
85
+ return instance.customFields || {};
86
+ };
47
87
  /**
48
88
  * Validates the model using custom validators
49
89
  */
@@ -71,21 +111,26 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
71
111
  return;
72
112
  }
73
113
  // For updates, get the previous values
74
- const originalValues = isCreate
75
- ? null
76
- : {
77
- ...instance.previous(),
78
- customFields: instance.previous('customFields') || {},
79
- };
80
- // For debugging in case of update
114
+ let originalValues = null;
81
115
  if (!isCreate) {
116
+ // Create originalValues with our helper function
117
+ originalValues = manualObjectCopy(instance.previous());
118
+ // Add customFields separately
119
+ originalValues.customFields = instance.previous('customFields') || {};
120
+ }
121
+ // Get complete custom fields by merging DB values with update values
122
+ // This is especially important for partial updates to ensure all related fields are available
123
+ const completeCustomFields = !isCreate
124
+ ? await getCompleteCustomFields(instance, options)
125
+ : instance.customFields || {};
126
+ // For debugging in case of update
127
+ if (!isCreate && process.env.NODE_ENV !== 'production') {
128
+ // Create after object for logging
129
+ const logAfterObj = manualObjectCopy(instance.dataValues, { customFields: completeCustomFields });
82
130
  logger_1.default.debug('sadot - validate with values', {
83
131
  before: originalValues,
84
- after: {
85
- ...instance.dataValues,
86
- ...instance.customFields,
87
- },
88
- schema: JSON.stringify(validators[0].schema),
132
+ after: logAfterObj,
133
+ schema: validators[0].schema,
89
134
  });
90
135
  }
91
136
  // eslint-disable-next-line no-restricted-syntax
@@ -93,7 +138,7 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
93
138
  const { schema } = validator;
94
139
  const typedSchema = schema;
95
140
  logger_1.default.debug('sadot - validating with schema', {
96
- schema: JSON.stringify(schema),
141
+ schema,
97
142
  hasAfterProps: !!typedSchema.properties?.after,
98
143
  hasBeforeProps: !!typedSchema.properties?.before,
99
144
  });
@@ -107,12 +152,12 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
107
152
  after: typedSchema.properties.after,
108
153
  },
109
154
  });
110
- const isValid = validateSchema({
155
+ const isValid = validateSchema(JSON.parse(JSON.stringify({
111
156
  after: {
112
157
  ...instance.dataValues,
113
- ...instance.customFields,
158
+ customFields: completeCustomFields,
114
159
  },
115
- });
160
+ })));
116
161
  if (!isValid) {
117
162
  const errorDetails = validateSchema.errors?.map((err) => `${err.instancePath || ''} ${err.message || 'Invalid value'}`).join(', ');
118
163
  throw new errors_1.BadRequest([new Error(`Validation failed for ${modelType}: ${errorDetails}`)]);
@@ -122,25 +167,29 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
122
167
  else {
123
168
  // For update operations, we need both before and after
124
169
  const validateSchema = ajv.compile(typedSchema);
125
- const isValid = validateSchema({
170
+ // Create after object with our helper function
171
+ const afterObj = manualObjectCopy(instance.dataValues);
172
+ // Add complete custom fields
173
+ afterObj.customFields = completeCustomFields;
174
+ // Create validation payload
175
+ const payload = {
126
176
  before: originalValues,
127
- after: {
128
- ...instance.dataValues,
129
- ...instance.customFields,
130
- },
131
- });
177
+ after: afterObj,
178
+ };
179
+ // Validate
180
+ const isValid = validateSchema(JSON.parse(JSON.stringify(payload)));
132
181
  logger_1.default.info('sadot - validation result', {
133
182
  isValid,
134
183
  test: {
135
184
  before: originalValues,
136
- after: {
137
- ...instance.dataValues,
138
- ...instance.customFields,
139
- },
185
+ after: afterObj,
140
186
  },
141
187
  });
142
188
  if (!isValid) {
143
- const errorDetails = validateSchema.errors?.map((err) => `${err.instancePath || ''} ${err.message || 'Invalid value'}`).join(', ');
189
+ const errorDetails = validateSchema.errors?.map((err) => {
190
+ logger_1.default.info('dor', err);
191
+ return `${err.instancePath || ''} ${err.message || 'Invalid value'}`;
192
+ }).join(', ');
144
193
  throw new errors_1.BadRequest([new Error(`Validation failed for ${modelType}: ${errorDetails}`)]);
145
194
  }
146
195
  }
package/dist/index.d.ts CHANGED
@@ -4,9 +4,6 @@ import type { CustomFieldOptions, ModelFetcher, Models } from './types';
4
4
  export * from './utils/validations/schema/custom-fields';
5
5
  export * from './utils/constants';
6
6
  export * from './utils/helpers';
7
- export * as DefinitionRepo from './repository/definition';
8
- export * as ValueRepo from './repository/value';
9
- export * as ValidatorRepo from './repository/validator';
10
7
  /**
11
8
  * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file
12
9
  * @see {@link 'custom-fields/config'} for configurations
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
29
29
  return (mod && mod.__esModule) ? mod : { "default": mod };
30
30
  };
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.disableCustomFields = exports.ValidatorRepo = exports.ValueRepo = exports.DefinitionRepo = void 0;
32
+ exports.disableCustomFields = void 0;
33
33
  const models_1 = require("./models");
34
34
  const api_1 = __importDefault(require("./api"));
35
35
  const db_1 = __importDefault(require("./utils/db"));
@@ -38,10 +38,6 @@ const init_1 = require("./utils/init");
38
38
  __exportStar(require("./utils/validations/schema/custom-fields"), exports);
39
39
  __exportStar(require("./utils/constants"), exports);
40
40
  __exportStar(require("./utils/helpers"), exports);
41
- // Export repositories
42
- exports.DefinitionRepo = __importStar(require("./repository/definition"));
43
- exports.ValueRepo = __importStar(require("./repository/value"));
44
- exports.ValidatorRepo = __importStar(require("./repository/validator"));
45
41
  /**
46
42
  * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file
47
43
  * @see {@link 'custom-fields/config'} for configurations
@@ -90,6 +90,7 @@ __decorate([
90
90
  __metadata("design:returntype", void 0)
91
91
  ], CustomValidator, "afterSaveHandler", null);
92
92
  CustomValidator = __decorate([
93
+ (0, sequelize_typescript_1.DefaultScope)(() => ({ where: { disabled: false } })),
93
94
  (0, sequelize_typescript_1.Table)({
94
95
  timestamps: true,
95
96
  })
@@ -58,6 +58,21 @@ const initTables = async (sequelize, getUser, { schemaPrefix, schemaVersion, use
58
58
  },
59
59
  };
60
60
  });
61
+ CustomValidator_1.default.addScope('userScope', () => {
62
+ const user = getUser();
63
+ if (!user?.permissions) {
64
+ return {};
65
+ }
66
+ return {
67
+ where: {
68
+ entityId: [
69
+ ...Object.keys(user.permissions.fleets),
70
+ ...Object.keys(user.permissions.businessModels),
71
+ ...Object.keys(user.permissions.demandSources),
72
+ ],
73
+ },
74
+ };
75
+ });
61
76
  logger_1.default.info('custom-fields: models added');
62
77
  const SequelizeMeta = sequelize.define('SequelizeMeta', {
63
78
  name: {
@@ -7,7 +7,7 @@ export interface ValidatorAttributes {
7
7
  entityId: string;
8
8
  entityType: string;
9
9
  modelType: string;
10
- schema: Record<string, unknown>;
10
+ schema: CustomValidator['schema'];
11
11
  disabled?: boolean;
12
12
  [key: string]: unknown;
13
13
  }
@@ -16,13 +16,23 @@ exports.create = create;
16
16
  const findAll = async (where = {}, options = { withDisabled: false }) => {
17
17
  logger_1.default.debug('custom-validator - find all validators');
18
18
  const { transaction, withDisabled } = options;
19
- const fullWhere = withDisabled
20
- ? where
21
- : { ...where, disabled: false };
22
- const validators = await models_1.CustomValidator.findAll({
23
- where: fullWhere,
24
- transaction,
25
- });
19
+ let validators;
20
+ if (withDisabled) {
21
+ // If withDisabled is true, use unscoped to ignore the default scope that filters disabled items
22
+ // Apply the userScope separately to maintain permission filtering
23
+ validators = await models_1.CustomValidator.unscoped().scope('userScope').findAll({
24
+ where,
25
+ transaction,
26
+ });
27
+ }
28
+ else {
29
+ // Use defaultScope and userScope to filter both disabled and by permissions
30
+ // The defaultScope keeps only non-disabled validators
31
+ validators = await models_1.CustomValidator.scope(['defaultScope', 'userScope']).findAll({
32
+ where,
33
+ transaction,
34
+ });
35
+ }
26
36
  return validators;
27
37
  };
28
38
  exports.findAll = findAll;
@@ -4,7 +4,7 @@ exports.default = {
4
4
  test: {
5
5
  username: process.env.DB_USERNAME || '',
6
6
  password: process.env.DB_PASSWORD || null,
7
- database: process.env.DB_NAME || 'sadot_package_test',
7
+ database: process.env.DB_NAME || 'postgres',
8
8
  host: process.env.DB_HOST || '127.0.0.1',
9
9
  port: process.env.DB_PORT || 5432,
10
10
  dialect: process.env.DB_TYPE || 'postgres',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.13.0-beta.8",
3
+ "version": "0.13.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -66,8 +66,9 @@ router.get<
66
66
  */
67
67
  router.get<{ modelName: string; validatorId: string }, CustomValidator>('/:validatorId', async (req, res) => {
68
68
  try {
69
- const { validatorId } = req.params;
70
- const validators = await ValidatorRepo.findAll({ id: validatorId });
69
+ const { validatorId, modelName } = req.params;
70
+ // Include disabled validators when fetching by ID
71
+ const validators = await ValidatorRepo.findAll({ id: validatorId, modelType: modelName }, { withDisabled: true });
71
72
 
72
73
  if (!validators.length) {
73
74
  throw new ResourceNotFoundError('Validator not found');
@@ -94,6 +95,12 @@ router.patch<{ modelName: string; validatorId: string }, CustomValidator>('/:val
94
95
  validateValidatorSchema(validatedPayload.schema);
95
96
  }
96
97
 
98
+ // First verify the validator exists, including disabled ones
99
+ const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });
100
+ if (!existingValidators.length) {
101
+ throw new ResourceNotFoundError('Validator not found');
102
+ }
103
+
97
104
  const [count, validators] = await ValidatorRepo.update(validatorId, validatedPayload);
98
105
 
99
106
  if (!count) {
@@ -112,10 +119,17 @@ router.patch<{ modelName: string; validatorId: string }, CustomValidator>('/:val
112
119
  router.delete<{ modelName: string; validatorId: string }>('/:validatorId', async (req, res) => {
113
120
  try {
114
121
  const { validatorId } = req.params;
122
+
123
+ // First verify the validator exists, including disabled ones
124
+ const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });
125
+ if (!existingValidators.length) {
126
+ throw new ResourceNotFoundError('Validator not found');
127
+ }
128
+
115
129
  const [count] = await ValidatorRepo.disable(validatorId);
116
130
 
117
131
  if (!count) {
118
- throw new ResourceNotFoundError('Validator not found');
132
+ throw new ResourceNotFoundError('Validator failed to be disabled');
119
133
  }
120
134
 
121
135
  return res.status(StatusCodes.NO_CONTENT).send();
@@ -21,6 +21,7 @@ const validationSchemas = {
21
21
 
22
22
  update: Joi.object({
23
23
  entityId: Joi.string().uuid(),
24
+ entityType: Joi.string(),
24
25
  schema: Joi.object({
25
26
  type: Joi.string().valid('object'),
26
27
  properties: Joi.object({
@@ -20,6 +20,56 @@ const ajv = new Ajv({
20
20
 
21
21
  addFormats(ajv);
22
22
 
23
+ /**
24
+ * Helper function to manually copy object properties
25
+ * This is more efficient for large objects and avoids excessive object creation
26
+ */
27
+ // eslint-disable-next-line prefer-object-spread
28
+ const manualObjectCopy = (sourceObj: Record<string, any>, additionalProps?: Record<string, any>): Record<string, any> =>
29
+ ({ __proto__: null, ...sourceObj, ...additionalProps });
30
+
31
+ /**
32
+ * Fetches complete custom fields for an instance by merging DB values with update values
33
+ * This is needed for partial updates to ensure all related fields are available for validation
34
+ */
35
+ const getCompleteCustomFields = async (instance, options): Promise<Record<string, any>> => {
36
+ // If we don't have an instance id or no custom fields being updated, return original fields
37
+ if (!instance.id || !instance.customFields || Object.keys(instance.customFields).length === 0) {
38
+ return instance.customFields || {};
39
+ }
40
+
41
+ try {
42
+ const ModelClass = instance.constructor;
43
+ // Only select the customFields column to minimize data transfer
44
+ const currentCustomFields = await ModelClass.findOne({
45
+ where: { id: instance.id },
46
+ attributes: ['customFields'],
47
+ transaction: options.transaction,
48
+ raw: true, // Get plain object instead of model instance for better performance
49
+ });
50
+
51
+ if (currentCustomFields?.customFields) {
52
+ // Merge existing fields with update fields using our helper function
53
+ const completeFields = manualObjectCopy(
54
+ currentCustomFields.customFields,
55
+ instance.customFields,
56
+ );
57
+
58
+ logger.debug('sadot - fetched complete custom fields for validation', {
59
+ fieldsCount: Object.keys(completeFields).length,
60
+ updateFieldsCount: Object.keys(instance.customFields).length,
61
+ });
62
+
63
+ return completeFields;
64
+ }
65
+ } catch (error) {
66
+ logger.error('sadot - error fetching complete model for validation', { error });
67
+ // Continue with partial data if we can't fetch the complete model
68
+ }
69
+
70
+ return instance.customFields || {};
71
+ };
72
+
23
73
  /**
24
74
  * Validates the model using custom validators
25
75
  */
@@ -66,22 +116,30 @@ const validateModel = async (
66
116
  }
67
117
 
68
118
  // For updates, get the previous values
69
- const originalValues = isCreate
70
- ? null
71
- : {
72
- ...instance.previous(),
73
- customFields: instance.previous('customFields') || {},
74
- };
119
+ let originalValues = null;
120
+ if (!isCreate) {
121
+ // Create originalValues with our helper function
122
+ originalValues = manualObjectCopy(instance.previous());
123
+
124
+ // Add customFields separately
125
+ originalValues.customFields = instance.previous('customFields') || {};
126
+ }
127
+
128
+ // Get complete custom fields by merging DB values with update values
129
+ // This is especially important for partial updates to ensure all related fields are available
130
+ const completeCustomFields = !isCreate
131
+ ? await getCompleteCustomFields(instance, options)
132
+ : instance.customFields || {};
75
133
 
76
134
  // For debugging in case of update
77
- if (!isCreate) {
135
+ if (!isCreate && process.env.NODE_ENV !== 'production') {
136
+ // Create after object for logging
137
+ const logAfterObj = manualObjectCopy(instance.dataValues, { customFields: completeCustomFields });
138
+
78
139
  logger.debug('sadot - validate with values', {
79
140
  before: originalValues,
80
- after: {
81
- ...instance.dataValues,
82
- ...instance.customFields,
83
- },
84
- schema: JSON.stringify(validators[0].schema),
141
+ after: logAfterObj,
142
+ schema: validators[0].schema,
85
143
  });
86
144
  }
87
145
 
@@ -91,7 +149,7 @@ const validateModel = async (
91
149
  const typedSchema = schema as Record<string, any>;
92
150
 
93
151
  logger.debug('sadot - validating with schema', {
94
- schema: JSON.stringify(schema),
152
+ schema,
95
153
  hasAfterProps: !!typedSchema.properties?.after,
96
154
  hasBeforeProps: !!typedSchema.properties?.before,
97
155
  });
@@ -107,12 +165,12 @@ const validateModel = async (
107
165
  },
108
166
  });
109
167
 
110
- const isValid = validateSchema({
168
+ const isValid = validateSchema(JSON.parse(JSON.stringify({
111
169
  after: {
112
170
  ...instance.dataValues,
113
- ...instance.customFields,
171
+ customFields: completeCustomFields,
114
172
  },
115
- });
173
+ })));
116
174
 
117
175
  if (!isValid) {
118
176
  const errorDetails = validateSchema.errors?.map((err) =>
@@ -125,28 +183,34 @@ const validateModel = async (
125
183
  // For update operations, we need both before and after
126
184
  const validateSchema = ajv.compile(typedSchema);
127
185
 
128
- const isValid = validateSchema({
186
+ // Create after object with our helper function
187
+ const afterObj = manualObjectCopy(instance.dataValues);
188
+
189
+ // Add complete custom fields
190
+ afterObj.customFields = completeCustomFields;
191
+
192
+ // Create validation payload
193
+ const payload = {
129
194
  before: originalValues,
130
- after: {
131
- ...instance.dataValues,
132
- customFields: instance.customFields,
133
- },
134
- });
195
+ after: afterObj,
196
+ };
197
+
198
+ // Validate
199
+ const isValid = validateSchema(JSON.parse(JSON.stringify(payload)));
135
200
 
136
201
  logger.info('sadot - validation result', {
137
202
  isValid,
138
203
  test: {
139
204
  before: originalValues,
140
- after: {
141
- ...instance.dataValues,
142
- ...instance.customFields,
143
- },
205
+ after: afterObj,
144
206
  },
145
207
  });
146
208
 
147
209
  if (!isValid) {
148
- const errorDetails = validateSchema.errors?.map((err) =>
149
- `${(err as any).instancePath || ''} ${(err as any).message || 'Invalid value'}`).join(', ');
210
+ const errorDetails = validateSchema.errors?.map((err) => {
211
+ logger.info('dor', err);
212
+ return `${(err as any).instancePath || ''} ${(err as any).message || 'Invalid value'}`;
213
+ }).join(', ');
150
214
 
151
215
  throw new BadRequest([new Error(`Validation failed for ${modelType}: ${errorDetails}`)]);
152
216
  }
package/src/index.ts CHANGED
@@ -17,11 +17,6 @@ export * from './utils/constants';
17
17
 
18
18
  export * from './utils/helpers';
19
19
 
20
- // Export repositories
21
- export * as DefinitionRepo from './repository/definition';
22
- export * as ValueRepo from './repository/value';
23
- export * as ValidatorRepo from './repository/validator';
24
-
25
20
  /**
26
21
  * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file
27
22
  * @see {@link 'custom-fields/config'} for configurations
@@ -6,10 +6,12 @@ import {
6
6
  DataType,
7
7
  Default,
8
8
  AfterUpsert,
9
+ DefaultScope,
9
10
  } from 'sequelize-typescript';
10
11
  import { randomUUID } from 'node:crypto';
11
12
  import { sendDimEvent } from '../events';
12
13
 
14
+ @DefaultScope(() => ({ where: { disabled: false } }))
13
15
  @Table({
14
16
  timestamps: true,
15
17
  })
@@ -68,6 +68,22 @@ const initTables = async (
68
68
  };
69
69
  });
70
70
 
71
+ CustomValidator.addScope('userScope', () => {
72
+ const user = getUser();
73
+ if (!user?.permissions) {
74
+ return {};
75
+ }
76
+ return {
77
+ where: {
78
+ entityId: [
79
+ ...Object.keys(user.permissions.fleets),
80
+ ...Object.keys(user.permissions.businessModels),
81
+ ...Object.keys(user.permissions.demandSources),
82
+ ],
83
+ },
84
+ };
85
+ });
86
+
71
87
  logger.info('custom-fields: models added');
72
88
 
73
89
  const SequelizeMeta = sequelize.define(
@@ -11,7 +11,7 @@ export interface ValidatorAttributes {
11
11
  entityId: string;
12
12
  entityType: string;
13
13
  modelType: string;
14
- schema: Record<string, unknown>;
14
+ schema: CustomValidator['schema'];
15
15
  disabled?: boolean;
16
16
  [key: string]: unknown; // Add index signature for Sequelize compatibility
17
17
  }
@@ -36,14 +36,22 @@ export const findAll = async (
36
36
 
37
37
  const { transaction, withDisabled } = options;
38
38
 
39
- const fullWhere = withDisabled
40
- ? where
41
- : { ...where, disabled: false };
42
-
43
- const validators = await CustomValidator.findAll({
44
- where: fullWhere,
45
- transaction,
46
- });
39
+ let validators;
40
+ if (withDisabled) {
41
+ // If withDisabled is true, use unscoped to ignore the default scope that filters disabled items
42
+ // Apply the userScope separately to maintain permission filtering
43
+ validators = await CustomValidator.unscoped().scope('userScope').findAll({
44
+ where,
45
+ transaction,
46
+ });
47
+ } else {
48
+ // Use defaultScope and userScope to filter both disabled and by permissions
49
+ // The defaultScope keeps only non-disabled validators
50
+ validators = await CustomValidator.scope(['defaultScope', 'userScope']).findAll({
51
+ where,
52
+ transaction,
53
+ });
54
+ }
47
55
 
48
56
  return validators;
49
57
  };
@@ -2,7 +2,7 @@ export default {
2
2
  test: {
3
3
  username: process.env.DB_USERNAME || '',
4
4
  password: process.env.DB_PASSWORD || null,
5
- database: process.env.DB_NAME || 'sadot_package_test',
5
+ database: process.env.DB_NAME || 'postgres',
6
6
  host: process.env.DB_HOST || '127.0.0.1',
7
7
  port: process.env.DB_PORT || 5432,
8
8
  dialect: process.env.DB_TYPE || 'postgres',
package/validator-test.js DELETED
@@ -1,79 +0,0 @@
1
- const Ajv = require("ajv");
2
- const addFormats = require("ajv-formats");
3
- const ajv = new Ajv({
4
- allErrors: true,
5
- strict: false, // Disable strict mode to avoid warnings
6
- strictTypes: false, // Disable strict type checking
7
- $data: true, // Enable $data references
8
- }); // options can be passed, e.g. {allErrors: true}
9
- addFormats(ajv);
10
-
11
-
12
- const schema = {
13
- "type": "object",
14
- "properties": {
15
- "after": {
16
- "type": "object",
17
- "properties": {
18
- "customFields": {
19
- "type": "object",
20
- "properties": {
21
- "actualStartTime": {
22
- "type": "string",
23
- "format": "date-time"
24
- },
25
- "actualEndTime": {
26
- "type": "string",
27
- "format": "date-time",
28
- "formatMinimum": {
29
- "$data": "/after/customFields/actualStartTime"
30
- }
31
- }
32
- }
33
- }
34
- }
35
- }
36
- }
37
- };
38
-
39
- const validate = ajv.compile(schema);
40
-
41
- const data = {
42
- "id": "c9c87cec-28c7-4a1f-9376-4d8a4ba0f49c",
43
- "typeId": "4fcd7096-4c90-46a2-a20e-91bb5bff3ced",
44
- "priorityId": null,
45
- "statusId": "51d28a37-c042-429f-a9cd-fbc81bba2b39",
46
- "subjectId": null,
47
- "subjectType": null,
48
- "title": "ff",
49
- "description": null,
50
- "dueTime": null,
51
- "startTime": null,
52
- "endTime": null,
53
- "driverId": null,
54
- "vendorId": null,
55
- "userId": null,
56
- "businessModelId": "72ecf740-42a1-46f4-81ca-8132b08c4f04",
57
- "createdAt": "2025-03-12T12:58:05.529Z",
58
- "updatedAt": "2025-03-12T12:58:05.529Z",
59
- "deletedAt": null,
60
- "actions": [],
61
- "customFields": {
62
- "actualStartTime": "2025-03-14T12:48:01.373Z",
63
- "actualEndTime": "2025-03-01T12:51:46.685Z"
64
- },
65
- "isBlocker": false
66
- };
67
-
68
- const valid = validate({after: data});
69
-
70
- if (!valid) {
71
- console.log("invalid, the errors is: ");
72
- validate.errors.forEach((error) =>
73
- console.log(error.instancePath, error.message)
74
- );
75
- } else {
76
- console.log("valid");
77
- }
78
-
79
- console.log("--------------------");