@infuro/cms-core 1.0.41 → 1.0.43
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 +5 -18
- package/dist/admin.cjs +959 -303
- package/dist/admin.d.cts +14 -2
- package/dist/admin.d.ts +14 -2
- package/dist/admin.js +959 -303
- package/dist/api.cjs +35 -35
- package/dist/api.js +3 -3
- package/dist/auth.cjs +51 -51
- package/dist/auth.js +3 -3
- package/dist/{chunk-UXMDSNIG.js → chunk-BLR6H5GL.js} +1 -1
- package/dist/{chunk-P7QCLE5W.js → chunk-DN65KDIA.js} +11 -1
- package/dist/{chunk-4BG7XYSH.js → chunk-I6NH72MO.js} +1 -1
- package/dist/{chunk-EG4ICILK.js → chunk-IX7X4ILO.js} +811 -143
- package/dist/{chunk-QU554KAZ.cjs → chunk-SCPKMZG5.cjs} +862 -182
- package/dist/{chunk-ETZN4OQI.cjs → chunk-TAHX46EI.cjs} +6 -6
- package/dist/{chunk-WMXPKKXU.cjs → chunk-X6UQFV4X.cjs} +11 -1
- package/dist/{chunk-OIGCAGH7.cjs → chunk-ZMRQ72F6.cjs} +7 -7
- package/dist/index.cjs +290 -242
- package/dist/index.d.cts +110 -5
- package/dist/index.d.ts +110 -5
- package/dist/index.js +6 -6
- package/dist/migrations/1781300000000-BrandIsCatalog.ts +61 -0
- package/dist/migrations/1781400000000-ComboEventIdNullable.ts +30 -0
- package/dist/migrations/1781500000000-ProductApprovalWorkflow.ts +30 -0
- package/dist/migrations/1781600000000-ProductApprovalStatusColumn.ts +53 -0
- package/dist/migrations/1781700000000-EventApprovalWorkflow.ts +32 -0
- package/dist/{rbac-debug-db-QWHOENBR.js → rbac-debug-db-2SGNLANF.js} +1 -1
- package/dist/{rbac-debug-db-KHG4FJC3.cjs → rbac-debug-db-4Z6A425H.cjs} +2 -2
- package/package.json +1 -1
|
@@ -7,8 +7,8 @@ var chunkXW5ATPRW_cjs = require('./chunk-XW5ATPRW.cjs');
|
|
|
7
7
|
var chunk3DZRIZOD_cjs = require('./chunk-3DZRIZOD.cjs');
|
|
8
8
|
var chunkSPQFNIYJ_cjs = require('./chunk-SPQFNIYJ.cjs');
|
|
9
9
|
var chunkXQ3QUHWR_cjs = require('./chunk-XQ3QUHWR.cjs');
|
|
10
|
-
var
|
|
11
|
-
var
|
|
10
|
+
var chunkZMRQ72F6_cjs = require('./chunk-ZMRQ72F6.cjs');
|
|
11
|
+
var chunkX6UQFV4X_cjs = require('./chunk-X6UQFV4X.cjs');
|
|
12
12
|
var chunkD5FBNKQM_cjs = require('./chunk-D5FBNKQM.cjs');
|
|
13
13
|
var chunkUPLVMVRX_cjs = require('./chunk-UPLVMVRX.cjs');
|
|
14
14
|
var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
|
|
@@ -87,7 +87,7 @@ async function loadUserVendorContext(dataSource, userId, preferredVendorId) {
|
|
|
87
87
|
`, [
|
|
88
88
|
primary.vendorRoleId
|
|
89
89
|
]);
|
|
90
|
-
vendorEntityPerms =
|
|
90
|
+
vendorEntityPerms = chunkX6UQFV4X_cjs.permissionRowsToRecord(permRows);
|
|
91
91
|
} catch (err) {
|
|
92
92
|
if (!isMissingVendorRoleSchemaError(err)) throw err;
|
|
93
93
|
}
|
|
@@ -104,6 +104,79 @@ async function loadUserVendorContext(dataSource, userId, preferredVendorId) {
|
|
|
104
104
|
}
|
|
105
105
|
chunkUSNT2KNT_cjs.__name(loadUserVendorContext, "loadUserVendorContext");
|
|
106
106
|
|
|
107
|
+
// src/lib/vendor-catalog-create-flags.ts
|
|
108
|
+
var ALL_OFF = {
|
|
109
|
+
categories: false,
|
|
110
|
+
collections: false,
|
|
111
|
+
brands: false
|
|
112
|
+
};
|
|
113
|
+
var cachedFlags = null;
|
|
114
|
+
function invalidateVendorCatalogCreateFlagsCache() {
|
|
115
|
+
cachedFlags = null;
|
|
116
|
+
}
|
|
117
|
+
chunkUSNT2KNT_cjs.__name(invalidateVendorCatalogCreateFlagsCache, "invalidateVendorCatalogCreateFlagsCache");
|
|
118
|
+
function parseTrue(value) {
|
|
119
|
+
return value === "true";
|
|
120
|
+
}
|
|
121
|
+
chunkUSNT2KNT_cjs.__name(parseTrue, "parseTrue");
|
|
122
|
+
async function isMultiVendorEnabled(dataSource) {
|
|
123
|
+
try {
|
|
124
|
+
const rows = await dataSource.query(`
|
|
125
|
+
SELECT value FROM configs
|
|
126
|
+
WHERE settings = 'multi_vendor' AND key = 'enabled' AND deleted = false
|
|
127
|
+
LIMIT 1
|
|
128
|
+
`);
|
|
129
|
+
return rows.length === 0 || rows[0].value !== "false";
|
|
130
|
+
} catch {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
chunkUSNT2KNT_cjs.__name(isMultiVendorEnabled, "isMultiVendorEnabled");
|
|
135
|
+
async function getVendorCatalogCreateFlags(dataSource) {
|
|
136
|
+
if (cachedFlags !== null) return cachedFlags;
|
|
137
|
+
const multiVendorEnabled = await isMultiVendorEnabled(dataSource);
|
|
138
|
+
if (!multiVendorEnabled) {
|
|
139
|
+
cachedFlags = {
|
|
140
|
+
...ALL_OFF
|
|
141
|
+
};
|
|
142
|
+
return cachedFlags;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const rows = await dataSource.query(`
|
|
146
|
+
SELECT key, value FROM configs
|
|
147
|
+
WHERE settings = 'multi_vendor'
|
|
148
|
+
AND key IN (
|
|
149
|
+
'vendorCanCreateCategories',
|
|
150
|
+
'vendorCanCreateCollections',
|
|
151
|
+
'vendorCanCreateBrands'
|
|
152
|
+
)
|
|
153
|
+
AND deleted = false
|
|
154
|
+
`);
|
|
155
|
+
const map = new Map(rows.map((r) => [
|
|
156
|
+
r.key,
|
|
157
|
+
r.value
|
|
158
|
+
]));
|
|
159
|
+
cachedFlags = {
|
|
160
|
+
categories: parseTrue(map.get("vendorCanCreateCategories")),
|
|
161
|
+
collections: parseTrue(map.get("vendorCanCreateCollections")),
|
|
162
|
+
brands: parseTrue(map.get("vendorCanCreateBrands"))
|
|
163
|
+
};
|
|
164
|
+
} catch {
|
|
165
|
+
cachedFlags = {
|
|
166
|
+
...ALL_OFF
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return cachedFlags;
|
|
170
|
+
}
|
|
171
|
+
chunkUSNT2KNT_cjs.__name(getVendorCatalogCreateFlags, "getVendorCatalogCreateFlags");
|
|
172
|
+
function vendorCanCreateResource(resource, flags) {
|
|
173
|
+
if (resource === "product_categories") return flags.categories;
|
|
174
|
+
if (resource === "collections") return flags.collections;
|
|
175
|
+
if (resource === "brands") return flags.brands;
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
chunkUSNT2KNT_cjs.__name(vendorCanCreateResource, "vendorCanCreateResource");
|
|
179
|
+
|
|
107
180
|
// src/lib/hydrate-vendor-session-user.ts
|
|
108
181
|
async function hydrateVendorSessionUser(dataSource, user) {
|
|
109
182
|
if (!user?.email) return user;
|
|
@@ -120,7 +193,7 @@ async function hydrateVendorSessionUser(dataSource, user) {
|
|
|
120
193
|
]);
|
|
121
194
|
const resolvedId = Number(byEmailRows[0]?.id);
|
|
122
195
|
if (!Number.isFinite(resolvedId)) {
|
|
123
|
-
|
|
196
|
+
chunkX6UQFV4X_cjs.logRbac("hydrateVendorSessionUser: unable to resolve numeric user id", {
|
|
124
197
|
email: user.email,
|
|
125
198
|
rawSessionId: user.id ?? null
|
|
126
199
|
});
|
|
@@ -140,7 +213,7 @@ async function hydrateVendorSessionUser(dataSource, user) {
|
|
|
140
213
|
const groupName = rows[0]?.groupName ?? user.groupName ?? null;
|
|
141
214
|
const groupId = rows[0]?.groupId ?? user.groupId ?? void 0;
|
|
142
215
|
const adminAccess = rows[0]?.adminAccess ?? user.adminAccess;
|
|
143
|
-
const isRBACAdmin = user.isRBACAdmin ??
|
|
216
|
+
const isRBACAdmin = user.isRBACAdmin ?? chunkX6UQFV4X_cjs.isSuperAdmin({
|
|
144
217
|
groupId,
|
|
145
218
|
groupName,
|
|
146
219
|
isRBACAdmin: user.isRBACAdmin
|
|
@@ -153,7 +226,7 @@ async function hydrateVendorSessionUser(dataSource, user) {
|
|
|
153
226
|
};
|
|
154
227
|
if (multiVendorEnabled) {
|
|
155
228
|
ctx = await loadUserVendorContext(dataSource, id, user.activeVendorId);
|
|
156
|
-
flags =
|
|
229
|
+
flags = chunkX6UQFV4X_cjs.vendorPortalFlagsFromUser({
|
|
157
230
|
email: user.email,
|
|
158
231
|
isRBACAdmin,
|
|
159
232
|
groupName,
|
|
@@ -188,7 +261,7 @@ async function hydrateVendorSessionUser(dataSource, user) {
|
|
|
188
261
|
isVendorPortal: flags.isVendorPortal,
|
|
189
262
|
isVendorOwner: flags.isVendorOwner
|
|
190
263
|
};
|
|
191
|
-
|
|
264
|
+
chunkX6UQFV4X_cjs.logRbac("hydrateVendorSessionUser", {
|
|
192
265
|
email: user.email,
|
|
193
266
|
userId: id,
|
|
194
267
|
groupName,
|
|
@@ -206,6 +279,7 @@ chunkUSNT2KNT_cjs.__name(hydrateVendorSessionUser, "hydrateVendorSessionUser");
|
|
|
206
279
|
var cachedMultiVendorEnabled = null;
|
|
207
280
|
function invalidateMultiVendorCache() {
|
|
208
281
|
cachedMultiVendorEnabled = null;
|
|
282
|
+
invalidateVendorCatalogCreateFlagsCache();
|
|
209
283
|
}
|
|
210
284
|
chunkUSNT2KNT_cjs.__name(invalidateMultiVendorCache, "invalidateMultiVendorCache");
|
|
211
285
|
async function checkMultiVendorEnabled(dataSource) {
|
|
@@ -244,6 +318,279 @@ async function checkEventsEnabled(dataSource) {
|
|
|
244
318
|
}
|
|
245
319
|
chunkUSNT2KNT_cjs.__name(checkEventsEnabled, "checkEventsEnabled");
|
|
246
320
|
|
|
321
|
+
// src/lib/product-approval.ts
|
|
322
|
+
var PRODUCT_APPROVAL_STATUSES = [
|
|
323
|
+
"pending",
|
|
324
|
+
"approved",
|
|
325
|
+
"rejected"
|
|
326
|
+
];
|
|
327
|
+
var APPROVAL_SET = new Set(PRODUCT_APPROVAL_STATUSES);
|
|
328
|
+
var PRODUCT_STATUSES = /* @__PURE__ */ new Set([
|
|
329
|
+
"draft",
|
|
330
|
+
"available",
|
|
331
|
+
"reserved",
|
|
332
|
+
"sold"
|
|
333
|
+
]);
|
|
334
|
+
var cachedRequireApproval = null;
|
|
335
|
+
function invalidateRequireProductApprovalCache() {
|
|
336
|
+
cachedRequireApproval = null;
|
|
337
|
+
}
|
|
338
|
+
chunkUSNT2KNT_cjs.__name(invalidateRequireProductApprovalCache, "invalidateRequireProductApprovalCache");
|
|
339
|
+
function parseTrue2(value) {
|
|
340
|
+
return value === "true";
|
|
341
|
+
}
|
|
342
|
+
chunkUSNT2KNT_cjs.__name(parseTrue2, "parseTrue");
|
|
343
|
+
async function getRequireProductApproval(dataSource) {
|
|
344
|
+
if (cachedRequireApproval !== null) return cachedRequireApproval;
|
|
345
|
+
const multiVendorEnabled = await checkMultiVendorEnabled(dataSource);
|
|
346
|
+
if (!multiVendorEnabled) {
|
|
347
|
+
cachedRequireApproval = false;
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
const rows = await dataSource.query(`
|
|
352
|
+
SELECT value FROM configs
|
|
353
|
+
WHERE settings = 'multi_vendor' AND key = 'requireProductApproval' AND deleted = false
|
|
354
|
+
LIMIT 1
|
|
355
|
+
`);
|
|
356
|
+
cachedRequireApproval = rows.length > 0 && parseTrue2(rows[0].value);
|
|
357
|
+
} catch {
|
|
358
|
+
cachedRequireApproval = false;
|
|
359
|
+
}
|
|
360
|
+
return cachedRequireApproval;
|
|
361
|
+
}
|
|
362
|
+
chunkUSNT2KNT_cjs.__name(getRequireProductApproval, "getRequireProductApproval");
|
|
363
|
+
function applyVendorProductCreateApproval(persistBody, opts) {
|
|
364
|
+
if (!opts.isVendor || !opts.requireApproval) return;
|
|
365
|
+
persistBody.approvalStatus = "pending";
|
|
366
|
+
if (persistBody.status === "available") persistBody.status = "draft";
|
|
367
|
+
persistBody.rejectionReason = null;
|
|
368
|
+
persistBody.rejectedAt = null;
|
|
369
|
+
persistBody.rejectedBy = null;
|
|
370
|
+
}
|
|
371
|
+
chunkUSNT2KNT_cjs.__name(applyVendorProductCreateApproval, "applyVendorProductCreateApproval");
|
|
372
|
+
function assertProductApprovalUpdate(opts) {
|
|
373
|
+
const fromApproval = opts.fromApproval == null || opts.fromApproval === "" ? null : String(opts.fromApproval);
|
|
374
|
+
const toApproval = opts.toApproval == null || opts.toApproval === "" ? null : String(opts.toApproval);
|
|
375
|
+
const fromStatus = String(opts.fromStatus || "draft");
|
|
376
|
+
const toStatus = String(opts.toStatus || fromStatus);
|
|
377
|
+
if (opts.statusChanged && !PRODUCT_STATUSES.has(toStatus)) {
|
|
378
|
+
return {
|
|
379
|
+
ok: false,
|
|
380
|
+
error: `Invalid product status: ${toStatus}`
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
if (opts.approvalChanged && toApproval != null && !APPROVAL_SET.has(toApproval)) {
|
|
384
|
+
return {
|
|
385
|
+
ok: false,
|
|
386
|
+
error: `Invalid approval status: ${toApproval}`
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
if (!opts.requireApproval) {
|
|
390
|
+
if (opts.isVendor && opts.approvalChanged) {
|
|
391
|
+
return {
|
|
392
|
+
ok: false,
|
|
393
|
+
error: "Vendors cannot change approval status"
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
return {
|
|
397
|
+
ok: true
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
if (opts.isVendor) {
|
|
401
|
+
if (opts.approvalChanged) {
|
|
402
|
+
return {
|
|
403
|
+
ok: false,
|
|
404
|
+
error: "Vendors cannot change approval status"
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
if (opts.statusChanged && toStatus === "available" && fromApproval !== "approved") {
|
|
408
|
+
return {
|
|
409
|
+
ok: false,
|
|
410
|
+
error: "Product must be approved before it can be available"
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
if (fromApproval === "rejected" && opts.statusChanged && toStatus === "available") {
|
|
414
|
+
return {
|
|
415
|
+
ok: false,
|
|
416
|
+
error: "Rejected product cannot be made available"
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
ok: true
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
if (opts.approvalChanged && toApproval === "rejected") {
|
|
424
|
+
const reason = String(opts.rejectionReason ?? "").trim();
|
|
425
|
+
if (!reason) return {
|
|
426
|
+
ok: false,
|
|
427
|
+
error: "Rejection reason is required"
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return {
|
|
431
|
+
ok: true
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
chunkUSNT2KNT_cjs.__name(assertProductApprovalUpdate, "assertProductApprovalUpdate");
|
|
435
|
+
function applyApprovalStatusSideEffects(updatePayload, opts) {
|
|
436
|
+
const to = opts.toApproval == null || opts.toApproval === "" ? null : String(opts.toApproval);
|
|
437
|
+
if (to == null) return;
|
|
438
|
+
if (to === "approved") {
|
|
439
|
+
updatePayload.approvalStatus = "approved";
|
|
440
|
+
updatePayload.status = "available";
|
|
441
|
+
updatePayload.rejectionReason = null;
|
|
442
|
+
updatePayload.rejectedAt = null;
|
|
443
|
+
updatePayload.rejectedBy = null;
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
if (to === "rejected") {
|
|
447
|
+
updatePayload.approvalStatus = "rejected";
|
|
448
|
+
updatePayload.rejectionReason = String(opts.rejectionReason ?? "").trim();
|
|
449
|
+
updatePayload.rejectedAt = /* @__PURE__ */ new Date();
|
|
450
|
+
updatePayload.rejectedBy = opts.rejectedBy != null && Number.isFinite(opts.rejectedBy) ? opts.rejectedBy : null;
|
|
451
|
+
const nextStatus = "status" in updatePayload ? String(updatePayload.status) : opts.currentStatus;
|
|
452
|
+
if (nextStatus === "available") updatePayload.status = "draft";
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (to === "pending") {
|
|
456
|
+
updatePayload.approvalStatus = "pending";
|
|
457
|
+
updatePayload.rejectionReason = null;
|
|
458
|
+
updatePayload.rejectedAt = null;
|
|
459
|
+
updatePayload.rejectedBy = null;
|
|
460
|
+
const nextStatus = "status" in updatePayload ? String(updatePayload.status) : opts.currentStatus;
|
|
461
|
+
if (nextStatus === "available") updatePayload.status = "draft";
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
chunkUSNT2KNT_cjs.__name(applyApprovalStatusSideEffects, "applyApprovalStatusSideEffects");
|
|
465
|
+
|
|
466
|
+
// src/lib/event-approval.ts
|
|
467
|
+
var EVENT_APPROVAL_STATUSES = [
|
|
468
|
+
"pending",
|
|
469
|
+
"approved",
|
|
470
|
+
"rejected"
|
|
471
|
+
];
|
|
472
|
+
var APPROVAL_SET2 = new Set(EVENT_APPROVAL_STATUSES);
|
|
473
|
+
var cachedRequireApproval2 = null;
|
|
474
|
+
function invalidateRequireEventApprovalCache() {
|
|
475
|
+
cachedRequireApproval2 = null;
|
|
476
|
+
}
|
|
477
|
+
chunkUSNT2KNT_cjs.__name(invalidateRequireEventApprovalCache, "invalidateRequireEventApprovalCache");
|
|
478
|
+
function parseTrue3(value) {
|
|
479
|
+
return value === "true";
|
|
480
|
+
}
|
|
481
|
+
chunkUSNT2KNT_cjs.__name(parseTrue3, "parseTrue");
|
|
482
|
+
async function getRequireEventApproval(dataSource) {
|
|
483
|
+
if (cachedRequireApproval2 !== null) return cachedRequireApproval2;
|
|
484
|
+
const [eventsOn, multiVendorOn] = await Promise.all([
|
|
485
|
+
checkEventsEnabled(dataSource),
|
|
486
|
+
checkMultiVendorEnabled(dataSource)
|
|
487
|
+
]);
|
|
488
|
+
if (!eventsOn || !multiVendorOn) {
|
|
489
|
+
cachedRequireApproval2 = false;
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
const rows = await dataSource.query(`
|
|
494
|
+
SELECT value FROM configs
|
|
495
|
+
WHERE settings = 'events' AND key = 'requireEventApproval' AND deleted = false
|
|
496
|
+
LIMIT 1
|
|
497
|
+
`);
|
|
498
|
+
cachedRequireApproval2 = rows.length > 0 && parseTrue3(rows[0].value);
|
|
499
|
+
} catch {
|
|
500
|
+
cachedRequireApproval2 = false;
|
|
501
|
+
}
|
|
502
|
+
return cachedRequireApproval2;
|
|
503
|
+
}
|
|
504
|
+
chunkUSNT2KNT_cjs.__name(getRequireEventApproval, "getRequireEventApproval");
|
|
505
|
+
function applyVendorEventCreateApproval(persistBody, opts) {
|
|
506
|
+
if (!opts.isVendor || !opts.requireApproval) return;
|
|
507
|
+
persistBody.approvalStatus = "pending";
|
|
508
|
+
persistBody.isActive = false;
|
|
509
|
+
persistBody.rejectionReason = null;
|
|
510
|
+
persistBody.rejectedAt = null;
|
|
511
|
+
persistBody.rejectedBy = null;
|
|
512
|
+
}
|
|
513
|
+
chunkUSNT2KNT_cjs.__name(applyVendorEventCreateApproval, "applyVendorEventCreateApproval");
|
|
514
|
+
function assertEventApprovalUpdate(opts) {
|
|
515
|
+
const fromApproval = opts.fromApproval == null || opts.fromApproval === "" ? null : String(opts.fromApproval);
|
|
516
|
+
const toApproval = opts.toApproval == null || opts.toApproval === "" ? null : String(opts.toApproval);
|
|
517
|
+
if (opts.approvalChanged && toApproval != null && !APPROVAL_SET2.has(toApproval)) {
|
|
518
|
+
return {
|
|
519
|
+
ok: false,
|
|
520
|
+
error: `Invalid approval status: ${toApproval}`
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
if (!opts.requireApproval) {
|
|
524
|
+
if (opts.isVendor && opts.approvalChanged) {
|
|
525
|
+
return {
|
|
526
|
+
ok: false,
|
|
527
|
+
error: "Vendors cannot change approval status"
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
ok: true
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
if (opts.isVendor) {
|
|
535
|
+
if (opts.approvalChanged) {
|
|
536
|
+
return {
|
|
537
|
+
ok: false,
|
|
538
|
+
error: "Vendors cannot change approval status"
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
if (opts.activeChanged && opts.toActive && fromApproval !== "approved") {
|
|
542
|
+
return {
|
|
543
|
+
ok: false,
|
|
544
|
+
error: "Event must be approved before it can be activated"
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
ok: true
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
if (opts.approvalChanged && toApproval === "rejected") {
|
|
552
|
+
const reason = String(opts.rejectionReason ?? "").trim();
|
|
553
|
+
if (!reason) return {
|
|
554
|
+
ok: false,
|
|
555
|
+
error: "Rejection reason is required"
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
ok: true
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
chunkUSNT2KNT_cjs.__name(assertEventApprovalUpdate, "assertEventApprovalUpdate");
|
|
563
|
+
function applyEventApprovalStatusSideEffects(updatePayload, opts) {
|
|
564
|
+
const to = opts.toApproval == null || opts.toApproval === "" ? null : String(opts.toApproval);
|
|
565
|
+
if (to == null) return;
|
|
566
|
+
if (to === "approved") {
|
|
567
|
+
updatePayload.approvalStatus = "approved";
|
|
568
|
+
updatePayload.isActive = true;
|
|
569
|
+
updatePayload.rejectionReason = null;
|
|
570
|
+
updatePayload.rejectedAt = null;
|
|
571
|
+
updatePayload.rejectedBy = null;
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
if (to === "rejected") {
|
|
575
|
+
updatePayload.approvalStatus = "rejected";
|
|
576
|
+
updatePayload.rejectionReason = String(opts.rejectionReason ?? "").trim();
|
|
577
|
+
updatePayload.rejectedAt = /* @__PURE__ */ new Date();
|
|
578
|
+
updatePayload.rejectedBy = opts.rejectedBy != null && Number.isFinite(opts.rejectedBy) ? opts.rejectedBy : null;
|
|
579
|
+
const nextActive = "isActive" in updatePayload ? Boolean(updatePayload.isActive) : opts.currentActive;
|
|
580
|
+
if (nextActive) updatePayload.isActive = false;
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
if (to === "pending") {
|
|
584
|
+
updatePayload.approvalStatus = "pending";
|
|
585
|
+
updatePayload.rejectionReason = null;
|
|
586
|
+
updatePayload.rejectedAt = null;
|
|
587
|
+
updatePayload.rejectedBy = null;
|
|
588
|
+
const nextActive = "isActive" in updatePayload ? Boolean(updatePayload.isActive) : opts.currentActive;
|
|
589
|
+
if (nextActive) updatePayload.isActive = false;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
chunkUSNT2KNT_cjs.__name(applyEventApprovalStatusSideEffects, "applyEventApprovalStatusSideEffects");
|
|
593
|
+
|
|
247
594
|
// src/lib/default-vendor-id.ts
|
|
248
595
|
function getDefaultVendorId() {
|
|
249
596
|
const raw = process.env.DEFAULT_VENDOR_ID;
|
|
@@ -279,17 +626,20 @@ async function assertCatalogCategoryId(dataSource, categoriesEntity, categoryId,
|
|
|
279
626
|
const row = await repo.findOne({
|
|
280
627
|
where: {
|
|
281
628
|
id,
|
|
282
|
-
deleted: false
|
|
283
|
-
isCatalog: true
|
|
629
|
+
deleted: false
|
|
284
630
|
}
|
|
285
631
|
});
|
|
286
632
|
if (!row) {
|
|
287
633
|
return "Invalid catalog category. Choose one of the platform product category types.";
|
|
288
634
|
}
|
|
289
|
-
return null;
|
|
635
|
+
if (row.isCatalog === true) return null;
|
|
636
|
+
if (options?.allowVendorId != null && Number(row.vendorId) === options.allowVendorId && row.isCatalog !== true) {
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
639
|
+
return "Invalid catalog category. Choose one of the platform product category types.";
|
|
290
640
|
}
|
|
291
641
|
chunkUSNT2KNT_cjs.__name(assertCatalogCategoryId, "assertCatalogCategoryId");
|
|
292
|
-
async function
|
|
642
|
+
async function assertCollectionForVendorProduct(dataSource, collectionsEntity, collectionId, categoryId, vendorId, options) {
|
|
293
643
|
const cid = Number(collectionId);
|
|
294
644
|
if (!Number.isFinite(cid) || cid <= 0) return null;
|
|
295
645
|
if (!collectionsEntity) return "Collections are not configured";
|
|
@@ -300,11 +650,13 @@ async function assertVendorOwnedCollectionForProduct(dataSource, collectionsEnti
|
|
|
300
650
|
deleted: false
|
|
301
651
|
}
|
|
302
652
|
});
|
|
303
|
-
if (!row
|
|
304
|
-
return "Invalid collection. Choose
|
|
653
|
+
if (!row) {
|
|
654
|
+
return "Invalid collection. Choose a valid collection in this category.";
|
|
305
655
|
}
|
|
306
|
-
|
|
307
|
-
|
|
656
|
+
const isCatalog = row.isCatalog === true;
|
|
657
|
+
const isOwn = Number(row.vendorId) === vendorId && !isCatalog;
|
|
658
|
+
if (!isCatalog && !(options?.allowVendorOwned && isOwn)) {
|
|
659
|
+
return "Invalid collection. Choose one of the platform collections (or your own if allowed).";
|
|
308
660
|
}
|
|
309
661
|
const catId = Number(categoryId);
|
|
310
662
|
if (Number.isFinite(catId) && catId > 0 && Number(row.categoryId) !== catId) {
|
|
@@ -312,7 +664,7 @@ async function assertVendorOwnedCollectionForProduct(dataSource, collectionsEnti
|
|
|
312
664
|
}
|
|
313
665
|
return null;
|
|
314
666
|
}
|
|
315
|
-
chunkUSNT2KNT_cjs.__name(
|
|
667
|
+
chunkUSNT2KNT_cjs.__name(assertCollectionForVendorProduct, "assertCollectionForVendorProduct");
|
|
316
668
|
|
|
317
669
|
// src/lib/catalog-collection.ts
|
|
318
670
|
function isCatalogCollectionRow(row) {
|
|
@@ -326,16 +678,69 @@ function applyPlatformCatalogCollectionFields(persistBody) {
|
|
|
326
678
|
}
|
|
327
679
|
chunkUSNT2KNT_cjs.__name(applyPlatformCatalogCollectionFields, "applyPlatformCatalogCollectionFields");
|
|
328
680
|
|
|
681
|
+
// src/lib/catalog-brand.ts
|
|
682
|
+
function isCatalogBrandRow(row) {
|
|
683
|
+
return row?.isCatalog === true;
|
|
684
|
+
}
|
|
685
|
+
chunkUSNT2KNT_cjs.__name(isCatalogBrandRow, "isCatalogBrandRow");
|
|
686
|
+
function applyPlatformCatalogBrandFields(persistBody) {
|
|
687
|
+
persistBody.isCatalog = true;
|
|
688
|
+
delete persistBody.vendorId;
|
|
689
|
+
persistBody.vendorId = getDefaultVendorId();
|
|
690
|
+
}
|
|
691
|
+
chunkUSNT2KNT_cjs.__name(applyPlatformCatalogBrandFields, "applyPlatformCatalogBrandFields");
|
|
692
|
+
|
|
329
693
|
// src/api/vendor-scope-crud.ts
|
|
694
|
+
var CATALOG_LIST_RESOURCES = /* @__PURE__ */ new Set([
|
|
695
|
+
"product_categories",
|
|
696
|
+
"collections",
|
|
697
|
+
"brands"
|
|
698
|
+
]);
|
|
330
699
|
function repoHasVendorIdColumn(repo) {
|
|
331
700
|
return repo.metadata.columns.some((c) => c.propertyName === "vendorId");
|
|
332
701
|
}
|
|
333
702
|
chunkUSNT2KNT_cjs.__name(repoHasVendorIdColumn, "repoHasVendorIdColumn");
|
|
334
703
|
function resourceUsesVendorScope(resource) {
|
|
335
|
-
return resource === "vendors" ||
|
|
704
|
+
return resource === "vendors" || chunkX6UQFV4X_cjs.VENDOR_SCOPED_STORE_ENTITIES.has(resource);
|
|
336
705
|
}
|
|
337
706
|
chunkUSNT2KNT_cjs.__name(resourceUsesVendorScope, "resourceUsesVendorScope");
|
|
338
|
-
function
|
|
707
|
+
function mergeWhereClause(where, extra) {
|
|
708
|
+
if (Array.isArray(where)) {
|
|
709
|
+
return where.map((w) => ({
|
|
710
|
+
...w,
|
|
711
|
+
...extra
|
|
712
|
+
}));
|
|
713
|
+
}
|
|
714
|
+
if (where && typeof where === "object" && Object.keys(where).length > 0) {
|
|
715
|
+
return {
|
|
716
|
+
...where,
|
|
717
|
+
...extra
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
return extra;
|
|
721
|
+
}
|
|
722
|
+
chunkUSNT2KNT_cjs.__name(mergeWhereClause, "mergeWhereClause");
|
|
723
|
+
function mergeCatalogOrOwnWhere(where, vendorId) {
|
|
724
|
+
const catalog = mergeWhereClause(where, {
|
|
725
|
+
isCatalog: true
|
|
726
|
+
});
|
|
727
|
+
const own = mergeWhereClause(where, {
|
|
728
|
+
vendorId,
|
|
729
|
+
isCatalog: false
|
|
730
|
+
});
|
|
731
|
+
const catalogArr = Array.isArray(catalog) ? catalog : [
|
|
732
|
+
catalog
|
|
733
|
+
];
|
|
734
|
+
const ownArr = Array.isArray(own) ? own : [
|
|
735
|
+
own
|
|
736
|
+
];
|
|
737
|
+
return [
|
|
738
|
+
...catalogArr,
|
|
739
|
+
...ownArr
|
|
740
|
+
];
|
|
741
|
+
}
|
|
742
|
+
chunkUSNT2KNT_cjs.__name(mergeCatalogOrOwnWhere, "mergeCatalogOrOwnWhere");
|
|
743
|
+
function mergeVendorScopeIntoWhere(where, scope, resource, flags) {
|
|
339
744
|
if (scope.type === "all") return where;
|
|
340
745
|
if (scope.type === "deny") {
|
|
341
746
|
if (resource === "vendors") {
|
|
@@ -352,38 +757,20 @@ function mergeVendorScopeIntoWhere(where, scope, resource) {
|
|
|
352
757
|
id: typeorm.In(scope.vendorIds)
|
|
353
758
|
});
|
|
354
759
|
}
|
|
355
|
-
if (resource
|
|
760
|
+
if (CATALOG_LIST_RESOURCES.has(resource) && scope.type === "vendor") {
|
|
761
|
+
const canCreate = flags ? vendorCanCreateResource(resource, flags) : false;
|
|
762
|
+
if (canCreate) {
|
|
763
|
+
return mergeCatalogOrOwnWhere(where, scope.vendorId);
|
|
764
|
+
}
|
|
356
765
|
return mergeWhereClause(where, {
|
|
357
766
|
isCatalog: true
|
|
358
767
|
});
|
|
359
768
|
}
|
|
360
|
-
if (resource === "collections" && scope.type === "vendor") {
|
|
361
|
-
return mergeWhereClause(where, {
|
|
362
|
-
vendorId: scope.vendorId,
|
|
363
|
-
isCatalog: false
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
769
|
return mergeWhereClause(where, {
|
|
367
770
|
vendorId: scope.vendorId
|
|
368
771
|
});
|
|
369
772
|
}
|
|
370
773
|
chunkUSNT2KNT_cjs.__name(mergeVendorScopeIntoWhere, "mergeVendorScopeIntoWhere");
|
|
371
|
-
function mergeWhereClause(where, extra) {
|
|
372
|
-
if (Array.isArray(where)) {
|
|
373
|
-
return where.map((w) => ({
|
|
374
|
-
...w,
|
|
375
|
-
...extra
|
|
376
|
-
}));
|
|
377
|
-
}
|
|
378
|
-
if (where && typeof where === "object" && Object.keys(where).length > 0) {
|
|
379
|
-
return {
|
|
380
|
-
...where,
|
|
381
|
-
...extra
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
return extra;
|
|
385
|
-
}
|
|
386
|
-
chunkUSNT2KNT_cjs.__name(mergeWhereClause, "mergeWhereClause");
|
|
387
774
|
function applyVendorScopeToQueryBuilder(qb, alias, scope) {
|
|
388
775
|
if (scope.type === "all") return;
|
|
389
776
|
if (scope.type === "deny") {
|
|
@@ -395,7 +782,7 @@ function applyVendorScopeToQueryBuilder(qb, alias, scope) {
|
|
|
395
782
|
});
|
|
396
783
|
}
|
|
397
784
|
chunkUSNT2KNT_cjs.__name(applyVendorScopeToQueryBuilder, "applyVendorScopeToQueryBuilder");
|
|
398
|
-
function rowMatchesVendorScope(row, scope, resource) {
|
|
785
|
+
function rowMatchesVendorScope(row, scope, resource, flags) {
|
|
399
786
|
if (!row) return false;
|
|
400
787
|
if (scope.type === "all") return true;
|
|
401
788
|
if (scope.type === "deny") return false;
|
|
@@ -403,27 +790,32 @@ function rowMatchesVendorScope(row, scope, resource) {
|
|
|
403
790
|
const id = Number(row.id);
|
|
404
791
|
return scope.vendorIds.includes(id);
|
|
405
792
|
}
|
|
406
|
-
if (resource
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
return Number(row.vendorId) === scope.vendorId && !
|
|
793
|
+
if (CATALOG_LIST_RESOURCES.has(resource) && scope.type === "vendor") {
|
|
794
|
+
const isCatalog = resource === "product_categories" ? isCatalogCategoryRow(row) : resource === "collections" ? isCatalogCollectionRow(row) : isCatalogBrandRow(row);
|
|
795
|
+
if (isCatalog) return true;
|
|
796
|
+
const canCreate = flags ? vendorCanCreateResource(resource, flags) : false;
|
|
797
|
+
return canCreate && Number(row.vendorId) === scope.vendorId && !isCatalog;
|
|
411
798
|
}
|
|
412
799
|
return Number(row.vendorId) === scope.vendorId;
|
|
413
800
|
}
|
|
414
801
|
chunkUSNT2KNT_cjs.__name(rowMatchesVendorScope, "rowMatchesVendorScope");
|
|
415
|
-
function
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
chunkUSNT2KNT_cjs.__name(vendorCannotMutateCatalogCategories, "vendorCannotMutateCatalogCategories");
|
|
419
|
-
function vendorCannotMutateCatalogCollections(resource, scope, body) {
|
|
420
|
-
if (resource !== "collections" || scope.type !== "vendor") return false;
|
|
802
|
+
function vendorCannotMutateCatalogResource(resource, scope, flags, body) {
|
|
803
|
+
if (scope.type !== "vendor" || !CATALOG_LIST_RESOURCES.has(resource)) return false;
|
|
804
|
+
if (!vendorCanCreateResource(resource, flags)) return true;
|
|
421
805
|
return body?.isCatalog === true;
|
|
422
806
|
}
|
|
423
|
-
chunkUSNT2KNT_cjs.__name(
|
|
424
|
-
function
|
|
807
|
+
chunkUSNT2KNT_cjs.__name(vendorCannotMutateCatalogResource, "vendorCannotMutateCatalogResource");
|
|
808
|
+
function vendorCannotMutateExistingCatalogRow(resource, scope, row) {
|
|
809
|
+
if (scope.type !== "vendor" || !CATALOG_LIST_RESOURCES.has(resource) || !row) return false;
|
|
810
|
+
if (resource === "product_categories") return isCatalogCategoryRow(row);
|
|
811
|
+
if (resource === "collections") return isCatalogCollectionRow(row);
|
|
812
|
+
if (resource === "brands") return isCatalogBrandRow(row);
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
chunkUSNT2KNT_cjs.__name(vendorCannotMutateExistingCatalogRow, "vendorCannotMutateExistingCatalogRow");
|
|
816
|
+
function vendorScopeRowAccess(row, scope, resource, flags) {
|
|
425
817
|
if (!row) return "not_found";
|
|
426
|
-
if (rowMatchesVendorScope(row, scope, resource)) return "ok";
|
|
818
|
+
if (rowMatchesVendorScope(row, scope, resource, flags)) return "ok";
|
|
427
819
|
return scope.type === "vendor" ? "forbidden" : "not_found";
|
|
428
820
|
}
|
|
429
821
|
chunkUSNT2KNT_cjs.__name(vendorScopeRowAccess, "vendorScopeRowAccess");
|
|
@@ -455,14 +847,7 @@ function requireVendorIdForScopedCreate(resource, persistBody, scope, repo, cont
|
|
|
455
847
|
ok: true
|
|
456
848
|
};
|
|
457
849
|
}
|
|
458
|
-
if (resource === "collections" && persistBody.isCatalog === true) {
|
|
459
|
-
delete persistBody.vendorId;
|
|
460
|
-
persistBody.vendorId = getDefaultVendorId();
|
|
461
|
-
return {
|
|
462
|
-
ok: true
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
if (resource === "product_categories" && persistBody.isCatalog === true) {
|
|
850
|
+
if ((resource === "collections" || resource === "product_categories" || resource === "brands") && persistBody.isCatalog === true) {
|
|
466
851
|
delete persistBody.vendorId;
|
|
467
852
|
persistBody.vendorId = getDefaultVendorId();
|
|
468
853
|
return {
|
|
@@ -474,7 +859,7 @@ function requireVendorIdForScopedCreate(resource, persistBody, scope, repo, cont
|
|
|
474
859
|
};
|
|
475
860
|
enforceVendorIdOnCreateBody(persistBody, scope, repo);
|
|
476
861
|
if (scope.type === "vendor") {
|
|
477
|
-
if (resource === "collections") {
|
|
862
|
+
if (resource === "collections" || resource === "product_categories" || resource === "brands") {
|
|
478
863
|
persistBody.isCatalog = false;
|
|
479
864
|
}
|
|
480
865
|
return {
|
|
@@ -3421,6 +3806,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3421
3806
|
const scope = await resolveScope();
|
|
3422
3807
|
const repo2 = dataSource.getRepository(entity);
|
|
3423
3808
|
const statusFilter = searchParams.get("status")?.trim();
|
|
3809
|
+
const approvalStatusFilter = searchParams.get("approvalStatus")?.trim();
|
|
3424
3810
|
const inventory = searchParams.get("inventory")?.trim();
|
|
3425
3811
|
let productWhere = {
|
|
3426
3812
|
deleted: false,
|
|
@@ -3428,6 +3814,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3428
3814
|
};
|
|
3429
3815
|
productWhere = mergeVendorScopeIntoWhere(productWhere, scope, resource);
|
|
3430
3816
|
if (statusFilter) productWhere.status = statusFilter;
|
|
3817
|
+
if (approvalStatusFilter) productWhere.approvalStatus = approvalStatusFilter;
|
|
3431
3818
|
if (inventory === "in_stock") productWhere.quantity = typeorm.MoreThan(0);
|
|
3432
3819
|
if (inventory === "out_of_stock") productWhere.quantity = 0;
|
|
3433
3820
|
for (const key of [
|
|
@@ -3728,6 +4115,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3728
4115
|
where = mergeDeletedFalseWhere(repo, where);
|
|
3729
4116
|
if (resourceUsesVendorScope(resource)) {
|
|
3730
4117
|
const scope = await resolveScope();
|
|
4118
|
+
const catalogFlags = await getVendorCatalogCreateFlags(dataSource);
|
|
3731
4119
|
if (scope.type === "deny") {
|
|
3732
4120
|
where = resource === "vendors" ? {
|
|
3733
4121
|
id: -1
|
|
@@ -3736,7 +4124,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3736
4124
|
};
|
|
3737
4125
|
} else if (resource === "collections") {
|
|
3738
4126
|
if (scope.type === "vendor") {
|
|
3739
|
-
where = mergeVendorScopeIntoWhere(where, scope, resource);
|
|
4127
|
+
where = mergeVendorScopeIntoWhere(where, scope, resource, catalogFlags);
|
|
3740
4128
|
} else if (searchParams.get("isCatalog") !== "true") {
|
|
3741
4129
|
where = mergeListWhereAnd(where, {
|
|
3742
4130
|
isCatalog: false
|
|
@@ -3744,14 +4132,22 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3744
4132
|
}
|
|
3745
4133
|
} else if (resource === "product_categories") {
|
|
3746
4134
|
if (scope.type === "vendor") {
|
|
3747
|
-
where = mergeVendorScopeIntoWhere(where, scope, resource);
|
|
4135
|
+
where = mergeVendorScopeIntoWhere(where, scope, resource, catalogFlags);
|
|
4136
|
+
} else if (searchParams.get("isCatalog") !== "false") {
|
|
4137
|
+
where = mergeListWhereAnd(where, {
|
|
4138
|
+
isCatalog: true
|
|
4139
|
+
});
|
|
4140
|
+
}
|
|
4141
|
+
} else if (resource === "brands") {
|
|
4142
|
+
if (scope.type === "vendor") {
|
|
4143
|
+
where = mergeVendorScopeIntoWhere(where, scope, resource, catalogFlags);
|
|
3748
4144
|
} else if (searchParams.get("isCatalog") !== "false") {
|
|
3749
4145
|
where = mergeListWhereAnd(where, {
|
|
3750
4146
|
isCatalog: true
|
|
3751
4147
|
});
|
|
3752
4148
|
}
|
|
3753
4149
|
} else {
|
|
3754
|
-
where = mergeVendorScopeIntoWhere(where, scope, resource);
|
|
4150
|
+
where = mergeVendorScopeIntoWhere(where, scope, resource, catalogFlags);
|
|
3755
4151
|
}
|
|
3756
4152
|
}
|
|
3757
4153
|
let data;
|
|
@@ -3821,16 +4217,11 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3821
4217
|
});
|
|
3822
4218
|
}
|
|
3823
4219
|
const body = rawPostBody;
|
|
3824
|
-
|
|
4220
|
+
const catalogFlagsPost = await getVendorCatalogCreateFlags(dataSource);
|
|
4221
|
+
if (vendorCannotMutateCatalogResource(resource, scopePost, catalogFlagsPost, body)) {
|
|
4222
|
+
const label = resource === "product_categories" ? "Categories" : resource === "collections" ? "Collections" : resource === "brands" ? "Brands" : "This resource";
|
|
3825
4223
|
return json({
|
|
3826
|
-
error:
|
|
3827
|
-
}, {
|
|
3828
|
-
status: 403
|
|
3829
|
-
});
|
|
3830
|
-
}
|
|
3831
|
-
if (vendorCannotMutateCatalogCollections(resource, scopePost, body)) {
|
|
3832
|
-
return json({
|
|
3833
|
-
error: "Collections are managed by the platform administrator"
|
|
4224
|
+
error: `${label} are managed by the platform administrator`
|
|
3834
4225
|
}, {
|
|
3835
4226
|
status: 403
|
|
3836
4227
|
});
|
|
@@ -4215,8 +4606,15 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4215
4606
|
}
|
|
4216
4607
|
if (resource === "products") {
|
|
4217
4608
|
const scopeForProduct = await resolveScope();
|
|
4609
|
+
const productFlags = await getVendorCatalogCreateFlags(dataSource);
|
|
4610
|
+
const requireApproval = await getRequireProductApproval(dataSource);
|
|
4611
|
+
applyVendorProductCreateApproval(persistBody, {
|
|
4612
|
+
isVendor: scopeForProduct.type === "vendor",
|
|
4613
|
+
requireApproval
|
|
4614
|
+
});
|
|
4218
4615
|
const categoryErr = await assertCatalogCategoryId(dataSource, entityMap.product_categories, persistBody.categoryId, {
|
|
4219
|
-
required: scopeForProduct.type === "vendor"
|
|
4616
|
+
required: scopeForProduct.type === "vendor",
|
|
4617
|
+
allowVendorId: scopeForProduct.type === "vendor" && productFlags.categories ? scopeForProduct.vendorId : void 0
|
|
4220
4618
|
});
|
|
4221
4619
|
if (categoryErr) return json({
|
|
4222
4620
|
error: categoryErr
|
|
@@ -4225,7 +4623,9 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4225
4623
|
});
|
|
4226
4624
|
if (scopeForProduct.type === "vendor") {
|
|
4227
4625
|
if (entityMap.collections && persistBody.collectionId != null && persistBody.collectionId !== "") {
|
|
4228
|
-
const collectionErr = await
|
|
4626
|
+
const collectionErr = await assertCollectionForVendorProduct(dataSource, entityMap.collections, persistBody.collectionId, persistBody.categoryId, scopeForProduct.vendorId, {
|
|
4627
|
+
allowVendorOwned: productFlags.collections
|
|
4628
|
+
});
|
|
4229
4629
|
if (collectionErr) return json({
|
|
4230
4630
|
error: collectionErr
|
|
4231
4631
|
}, {
|
|
@@ -4234,6 +4634,14 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4234
4634
|
}
|
|
4235
4635
|
}
|
|
4236
4636
|
}
|
|
4637
|
+
if (resource === "events") {
|
|
4638
|
+
const scopeForEvent = await resolveScope();
|
|
4639
|
+
const requireEventApproval = await getRequireEventApproval(dataSource);
|
|
4640
|
+
applyVendorEventCreateApproval(persistBody, {
|
|
4641
|
+
isVendor: scopeForEvent.type === "vendor",
|
|
4642
|
+
requireApproval: requireEventApproval
|
|
4643
|
+
});
|
|
4644
|
+
}
|
|
4237
4645
|
if (resource === "collections" && scopePost.type === "vendor") {
|
|
4238
4646
|
const categoryErr = await assertCatalogCategoryId(dataSource, entityMap.product_categories, persistBody.categoryId, {
|
|
4239
4647
|
required: true
|
|
@@ -4438,7 +4846,27 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4438
4846
|
}
|
|
4439
4847
|
}
|
|
4440
4848
|
}
|
|
4441
|
-
if (
|
|
4849
|
+
if (resource === "brands" && scopeCreate.type === "all") {
|
|
4850
|
+
applyPlatformCatalogBrandFields(persistBody);
|
|
4851
|
+
const slug = String(persistBody.slug ?? "").trim();
|
|
4852
|
+
if (slug) {
|
|
4853
|
+
const dup = await repo.findOne({
|
|
4854
|
+
where: {
|
|
4855
|
+
slug,
|
|
4856
|
+
isCatalog: true,
|
|
4857
|
+
deleted: false
|
|
4858
|
+
}
|
|
4859
|
+
});
|
|
4860
|
+
if (dup) {
|
|
4861
|
+
return json({
|
|
4862
|
+
error: "A catalog brand with this slug already exists"
|
|
4863
|
+
}, {
|
|
4864
|
+
status: 400
|
|
4865
|
+
});
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
}
|
|
4869
|
+
if (!((resource === "collections" || resource === "product_categories" || resource === "brands") && persistBody.isCatalog === true)) {
|
|
4442
4870
|
await tryAssignSingleVendorOnAdminCreate(resource, scopeCreate, persistBody);
|
|
4443
4871
|
}
|
|
4444
4872
|
const vendorIdCheck = requireVendorIdForScopedCreate(resource, persistBody, scopeCreate, repo, await vendorCreateContext(body));
|
|
@@ -4918,13 +5346,14 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4918
5346
|
}
|
|
4919
5347
|
chunkUSNT2KNT_cjs.__name(createCrudHandler, "createCrudHandler");
|
|
4920
5348
|
function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
4921
|
-
const { requireAuth, json, requireEntityPermission: reqPerm, getCms, getDeletedByUserId, getVendorScope } = options;
|
|
5349
|
+
const { requireAuth, json, requireEntityPermission: reqPerm, getCms, getDeletedByUserId, getVendorScope, getHydratedSessionUser } = options;
|
|
4922
5350
|
const syncContactRowToErp = makeContactErpSync(dataSource, entityMap, getCms);
|
|
4923
5351
|
const resolveScopeById = getVendorScope ?? (async () => ({
|
|
4924
5352
|
type: "all"
|
|
4925
5353
|
}));
|
|
4926
|
-
function vendorScopeAccessJson(row, scope, resource) {
|
|
4927
|
-
const
|
|
5354
|
+
async function vendorScopeAccessJson(row, scope, resource) {
|
|
5355
|
+
const flags = await getVendorCatalogCreateFlags(dataSource);
|
|
5356
|
+
const access = vendorScopeRowAccess(row, scope, resource, flags);
|
|
4928
5357
|
if (access === "ok") return null;
|
|
4929
5358
|
if (access === "forbidden") return json({
|
|
4930
5359
|
error: "Forbidden"
|
|
@@ -5004,7 +5433,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5004
5433
|
"rules"
|
|
5005
5434
|
]
|
|
5006
5435
|
});
|
|
5007
|
-
const discountDenied = vendorScopeAccessJson(discount, scope2, resource);
|
|
5436
|
+
const discountDenied = await vendorScopeAccessJson(discount, scope2, resource);
|
|
5008
5437
|
if (discountDenied) return discountDenied;
|
|
5009
5438
|
const flatRules = discount.rules ?? [];
|
|
5010
5439
|
const nestedRules = nestDiscountRules2(flatRules);
|
|
@@ -5062,7 +5491,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5062
5491
|
"payments"
|
|
5063
5492
|
]
|
|
5064
5493
|
});
|
|
5065
|
-
const orderDenied = vendorScopeAccessJson(order, scope2, resource);
|
|
5494
|
+
const orderDenied = await vendorScopeAccessJson(order, scope2, resource);
|
|
5066
5495
|
if (orderDenied) return orderDenied;
|
|
5067
5496
|
const relatedOrders = await repo.find({
|
|
5068
5497
|
where: {
|
|
@@ -5126,7 +5555,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5126
5555
|
"contact"
|
|
5127
5556
|
]
|
|
5128
5557
|
});
|
|
5129
|
-
const paymentDenied = vendorScopeAccessJson(payment, scope2, resource);
|
|
5558
|
+
const paymentDenied = await vendorScopeAccessJson(payment, scope2, resource);
|
|
5130
5559
|
if (paymentDenied) return paymentDenied;
|
|
5131
5560
|
const p = payment;
|
|
5132
5561
|
const order = p.order;
|
|
@@ -5165,7 +5594,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5165
5594
|
"attributes.attribute"
|
|
5166
5595
|
]
|
|
5167
5596
|
});
|
|
5168
|
-
const productDenied = vendorScopeAccessJson(product, scope2, resource);
|
|
5597
|
+
const productDenied = await vendorScopeAccessJson(product, scope2, resource);
|
|
5169
5598
|
if (productDenied) return productDenied;
|
|
5170
5599
|
return product ? json(hydrateProductDisplayName(product)) : json({
|
|
5171
5600
|
message: "Not found"
|
|
@@ -5183,7 +5612,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5183
5612
|
"contact"
|
|
5184
5613
|
]
|
|
5185
5614
|
});
|
|
5186
|
-
const vcDenied = vendorScopeAccessJson(row, scope2, resource);
|
|
5615
|
+
const vcDenied = await vendorScopeAccessJson(row, scope2, resource);
|
|
5187
5616
|
if (vcDenied) return vcDenied;
|
|
5188
5617
|
const contact = row.contact;
|
|
5189
5618
|
return json({
|
|
@@ -5206,7 +5635,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5206
5635
|
"items.product"
|
|
5207
5636
|
]
|
|
5208
5637
|
});
|
|
5209
|
-
const comboDenied = vendorScopeAccessJson(combo, scope2, resource);
|
|
5638
|
+
const comboDenied = await vendorScopeAccessJson(combo, scope2, resource);
|
|
5210
5639
|
if (comboDenied) return comboDenied;
|
|
5211
5640
|
return combo ? json(combo) : json({
|
|
5212
5641
|
message: "Not found"
|
|
@@ -5243,7 +5672,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5243
5672
|
where: idWhere
|
|
5244
5673
|
});
|
|
5245
5674
|
if (resourceUsesVendorScope(resource)) {
|
|
5246
|
-
const itemDenied = vendorScopeAccessJson(item, scope, resource);
|
|
5675
|
+
const itemDenied = await vendorScopeAccessJson(item, scope, resource);
|
|
5247
5676
|
if (itemDenied) return itemDenied;
|
|
5248
5677
|
} else if (!item) {
|
|
5249
5678
|
return json({
|
|
@@ -5272,16 +5701,11 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5272
5701
|
}
|
|
5273
5702
|
const rawBody = await req.json();
|
|
5274
5703
|
const scopePutEarly = await resolveScopeById();
|
|
5275
|
-
|
|
5704
|
+
const catalogFlagsPut = await getVendorCatalogCreateFlags(dataSource);
|
|
5705
|
+
if (vendorCannotMutateCatalogResource(resource, scopePutEarly, catalogFlagsPut, rawBody ?? void 0)) {
|
|
5706
|
+
const label = resource === "product_categories" ? "Categories" : resource === "collections" ? "Collections" : resource === "brands" ? "Brands" : "This resource";
|
|
5276
5707
|
return json({
|
|
5277
|
-
error:
|
|
5278
|
-
}, {
|
|
5279
|
-
status: 403
|
|
5280
|
-
});
|
|
5281
|
-
}
|
|
5282
|
-
if (vendorCannotMutateCatalogCollections(resource, scopePutEarly, rawBody ?? void 0)) {
|
|
5283
|
-
return json({
|
|
5284
|
-
error: "Collections are managed by the platform administrator"
|
|
5708
|
+
error: `${label} are managed by the platform administrator`
|
|
5285
5709
|
}, {
|
|
5286
5710
|
status: 403
|
|
5287
5711
|
});
|
|
@@ -5647,7 +6071,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5647
6071
|
id: numericId
|
|
5648
6072
|
}
|
|
5649
6073
|
});
|
|
5650
|
-
const discountPutDenied = vendorScopeAccessJson(existing, scopePut2, resource);
|
|
6074
|
+
const discountPutDenied = await vendorScopeAccessJson(existing, scopePut2, resource);
|
|
5651
6075
|
if (discountPutDenied) return discountPutDenied;
|
|
5652
6076
|
const updatePayload2 = pickColumnUpdates(repo, rawBody);
|
|
5653
6077
|
delete updatePayload2.vendorId;
|
|
@@ -5705,8 +6129,16 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5705
6129
|
const existingScope = await repo.findOne({
|
|
5706
6130
|
where: idWhereCheck
|
|
5707
6131
|
});
|
|
5708
|
-
const scopePutDenied = vendorScopeAccessJson(existingScope, scopePut, resource);
|
|
6132
|
+
const scopePutDenied = await vendorScopeAccessJson(existingScope, scopePut, resource);
|
|
5709
6133
|
if (scopePutDenied) return scopePutDenied;
|
|
6134
|
+
if (vendorCannotMutateExistingCatalogRow(resource, scopePut, existingScope)) {
|
|
6135
|
+
const label = resource === "product_categories" ? "Categories" : resource === "collections" ? "Collections" : "Brands";
|
|
6136
|
+
return json({
|
|
6137
|
+
error: `${label} are managed by the platform administrator`
|
|
6138
|
+
}, {
|
|
6139
|
+
status: 403
|
|
6140
|
+
});
|
|
6141
|
+
}
|
|
5710
6142
|
}
|
|
5711
6143
|
const updatePayload = rawBody && typeof rawBody === "object" ? pickColumnUpdates(repo, rawBody) : {};
|
|
5712
6144
|
if (resourceUsesVendorScope(resource)) {
|
|
@@ -5853,7 +6285,8 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5853
6285
|
});
|
|
5854
6286
|
const mergedCategoryId = "categoryId" in updatePayload ? updatePayload.categoryId : currentRow.categoryId;
|
|
5855
6287
|
const categoryErr = await assertCatalogCategoryId(dataSource, entityMap.product_categories, "categoryId" in updatePayload ? updatePayload.categoryId : mergedCategoryId, {
|
|
5856
|
-
required: scopePut.type === "vendor"
|
|
6288
|
+
required: scopePut.type === "vendor",
|
|
6289
|
+
allowVendorId: scopePut.type === "vendor" && catalogFlagsPut.categories ? scopePut.vendorId : void 0
|
|
5857
6290
|
});
|
|
5858
6291
|
if (categoryErr) return json({
|
|
5859
6292
|
error: categoryErr
|
|
@@ -5862,7 +6295,9 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5862
6295
|
});
|
|
5863
6296
|
if (scopePut.type === "vendor") {
|
|
5864
6297
|
if (entityMap.collections && "collectionId" in updatePayload && updatePayload.collectionId != null) {
|
|
5865
|
-
const collectionErr = await
|
|
6298
|
+
const collectionErr = await assertCollectionForVendorProduct(dataSource, entityMap.collections, updatePayload.collectionId, mergedCategoryId, scopePut.vendorId, {
|
|
6299
|
+
allowVendorOwned: catalogFlagsPut.collections
|
|
6300
|
+
});
|
|
5866
6301
|
if (collectionErr) return json({
|
|
5867
6302
|
error: collectionErr
|
|
5868
6303
|
}, {
|
|
@@ -5870,6 +6305,88 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5870
6305
|
});
|
|
5871
6306
|
}
|
|
5872
6307
|
}
|
|
6308
|
+
if ("status" in updatePayload || "approvalStatus" in updatePayload || "rejectionReason" in updatePayload) {
|
|
6309
|
+
const fromStatus = String(currentRow.status ?? "draft");
|
|
6310
|
+
const toStatus = String("status" in updatePayload ? updatePayload.status ?? fromStatus : fromStatus);
|
|
6311
|
+
const fromApproval = currentRow.approvalStatus;
|
|
6312
|
+
const toApproval = "approvalStatus" in updatePayload ? updatePayload.approvalStatus : fromApproval;
|
|
6313
|
+
const requireApproval = await getRequireProductApproval(dataSource);
|
|
6314
|
+
const reasonFromBody = "rejectionReason" in updatePayload ? updatePayload.rejectionReason : currentRow.rejectionReason;
|
|
6315
|
+
const reasonStr = typeof reasonFromBody === "string" ? reasonFromBody : reasonFromBody == null ? null : String(reasonFromBody);
|
|
6316
|
+
const transition = assertProductApprovalUpdate({
|
|
6317
|
+
fromApproval,
|
|
6318
|
+
toApproval,
|
|
6319
|
+
fromStatus,
|
|
6320
|
+
toStatus,
|
|
6321
|
+
isVendor: scopePut.type === "vendor",
|
|
6322
|
+
requireApproval,
|
|
6323
|
+
approvalChanged: "approvalStatus" in updatePayload,
|
|
6324
|
+
statusChanged: "status" in updatePayload,
|
|
6325
|
+
rejectionReason: reasonStr
|
|
6326
|
+
});
|
|
6327
|
+
if (!transition.ok) return json({
|
|
6328
|
+
error: transition.error
|
|
6329
|
+
}, {
|
|
6330
|
+
status: 400
|
|
6331
|
+
});
|
|
6332
|
+
if ("approvalStatus" in updatePayload && scopePut.type !== "vendor") {
|
|
6333
|
+
const session = await getHydratedSessionUser?.() ?? null;
|
|
6334
|
+
const rejectedByRaw = session?.id != null ? Number(session.id) : null;
|
|
6335
|
+
applyApprovalStatusSideEffects(updatePayload, {
|
|
6336
|
+
toApproval,
|
|
6337
|
+
currentStatus: fromStatus,
|
|
6338
|
+
rejectionReason: reasonStr,
|
|
6339
|
+
rejectedBy: Number.isFinite(rejectedByRaw) ? rejectedByRaw : null
|
|
6340
|
+
});
|
|
6341
|
+
}
|
|
6342
|
+
}
|
|
6343
|
+
}
|
|
6344
|
+
if (resource === "events") {
|
|
6345
|
+
const currentEvent = await repo.findOne({
|
|
6346
|
+
where: {
|
|
6347
|
+
id: numericId,
|
|
6348
|
+
deleted: false
|
|
6349
|
+
}
|
|
6350
|
+
});
|
|
6351
|
+
if (!currentEvent) return json({
|
|
6352
|
+
message: "Not found"
|
|
6353
|
+
}, {
|
|
6354
|
+
status: 404
|
|
6355
|
+
});
|
|
6356
|
+
if ("isActive" in updatePayload || "approvalStatus" in updatePayload || "rejectionReason" in updatePayload) {
|
|
6357
|
+
const fromActive = Boolean(currentEvent.isActive);
|
|
6358
|
+
const toActive = "isActive" in updatePayload ? Boolean(updatePayload.isActive) : fromActive;
|
|
6359
|
+
const fromApproval = currentEvent.approvalStatus;
|
|
6360
|
+
const toApproval = "approvalStatus" in updatePayload ? updatePayload.approvalStatus : fromApproval;
|
|
6361
|
+
const requireEventApproval = await getRequireEventApproval(dataSource);
|
|
6362
|
+
const reasonFromBody = "rejectionReason" in updatePayload ? updatePayload.rejectionReason : currentEvent.rejectionReason;
|
|
6363
|
+
const reasonStr = typeof reasonFromBody === "string" ? reasonFromBody : reasonFromBody == null ? null : String(reasonFromBody);
|
|
6364
|
+
const transition = assertEventApprovalUpdate({
|
|
6365
|
+
fromApproval,
|
|
6366
|
+
toApproval,
|
|
6367
|
+
toActive,
|
|
6368
|
+
isVendor: scopePut.type === "vendor",
|
|
6369
|
+
requireApproval: requireEventApproval,
|
|
6370
|
+
approvalChanged: "approvalStatus" in updatePayload,
|
|
6371
|
+
activeChanged: "isActive" in updatePayload,
|
|
6372
|
+
rejectionReason: reasonStr
|
|
6373
|
+
});
|
|
6374
|
+
if (!transition.ok) return json({
|
|
6375
|
+
error: transition.error
|
|
6376
|
+
}, {
|
|
6377
|
+
status: 400
|
|
6378
|
+
});
|
|
6379
|
+
if ("approvalStatus" in updatePayload && scopePut.type !== "vendor") {
|
|
6380
|
+
const session = await getHydratedSessionUser?.() ?? null;
|
|
6381
|
+
const rejectedByRaw = session?.id != null ? Number(session.id) : null;
|
|
6382
|
+
applyEventApprovalStatusSideEffects(updatePayload, {
|
|
6383
|
+
toApproval,
|
|
6384
|
+
currentActive: fromActive,
|
|
6385
|
+
rejectionReason: reasonStr,
|
|
6386
|
+
rejectedBy: Number.isFinite(rejectedByRaw) ? rejectedByRaw : null
|
|
6387
|
+
});
|
|
6388
|
+
}
|
|
6389
|
+
}
|
|
5873
6390
|
}
|
|
5874
6391
|
if (resource === "product_categories" && scopePut.type === "all") {
|
|
5875
6392
|
const existingCatalogCat = await repo.findOne({
|
|
@@ -5927,6 +6444,34 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5927
6444
|
}
|
|
5928
6445
|
}
|
|
5929
6446
|
}
|
|
6447
|
+
if (resource === "brands" && scopePut.type === "all") {
|
|
6448
|
+
const existingCatalogBrand = await repo.findOne({
|
|
6449
|
+
where: {
|
|
6450
|
+
id: numericId,
|
|
6451
|
+
deleted: false
|
|
6452
|
+
}
|
|
6453
|
+
});
|
|
6454
|
+
if (existingCatalogBrand && existingCatalogBrand.isCatalog === true) {
|
|
6455
|
+
applyPlatformCatalogBrandFields(updatePayload);
|
|
6456
|
+
const slug = String(updatePayload.slug ?? existingCatalogBrand.slug ?? "").trim();
|
|
6457
|
+
if (slug && "slug" in updatePayload) {
|
|
6458
|
+
const dup = await repo.findOne({
|
|
6459
|
+
where: {
|
|
6460
|
+
slug,
|
|
6461
|
+
isCatalog: true,
|
|
6462
|
+
deleted: false
|
|
6463
|
+
}
|
|
6464
|
+
});
|
|
6465
|
+
if (dup && Number(dup.id) !== numericId) {
|
|
6466
|
+
return json({
|
|
6467
|
+
error: "A catalog brand with this slug already exists"
|
|
6468
|
+
}, {
|
|
6469
|
+
status: 400
|
|
6470
|
+
});
|
|
6471
|
+
}
|
|
6472
|
+
}
|
|
6473
|
+
}
|
|
6474
|
+
}
|
|
5930
6475
|
if (resource === "addresses" && Object.keys(updatePayload).length > 0) {
|
|
5931
6476
|
const currentRow = await repo.findOne({
|
|
5932
6477
|
where: {
|
|
@@ -6082,9 +6627,11 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6082
6627
|
const authError = await authz(req, resource, "delete");
|
|
6083
6628
|
if (authError) return authError;
|
|
6084
6629
|
const scopeDeleteEarly = await resolveScopeById();
|
|
6085
|
-
|
|
6630
|
+
const catalogFlagsDelete = await getVendorCatalogCreateFlags(dataSource);
|
|
6631
|
+
if (vendorCannotMutateCatalogResource(resource, scopeDeleteEarly, catalogFlagsDelete)) {
|
|
6632
|
+
const label = resource === "product_categories" ? "Categories" : resource === "collections" ? "Collections" : resource === "brands" ? "Brands" : "This resource";
|
|
6086
6633
|
return json({
|
|
6087
|
-
error:
|
|
6634
|
+
error: `${label} are managed by the platform administrator`
|
|
6088
6635
|
}, {
|
|
6089
6636
|
status: 403
|
|
6090
6637
|
});
|
|
@@ -6113,7 +6660,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6113
6660
|
}
|
|
6114
6661
|
});
|
|
6115
6662
|
if (resourceUsesVendorScope(resource)) {
|
|
6116
|
-
const deleteDenied = vendorScopeAccessJson(existing, scopeDelete, resource);
|
|
6663
|
+
const deleteDenied = await vendorScopeAccessJson(existing, scopeDelete, resource);
|
|
6117
6664
|
if (deleteDenied) return deleteDenied;
|
|
6118
6665
|
} else if (!existing) {
|
|
6119
6666
|
return json({
|
|
@@ -6171,7 +6718,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6171
6718
|
id: numericId
|
|
6172
6719
|
}
|
|
6173
6720
|
});
|
|
6174
|
-
const hardDeleteDenied = vendorScopeAccessJson(existingHard, scopeDelete, resource);
|
|
6721
|
+
const hardDeleteDenied = await vendorScopeAccessJson(existingHard, scopeDelete, resource);
|
|
6175
6722
|
if (hardDeleteDenied) return hardDeleteDenied;
|
|
6176
6723
|
}
|
|
6177
6724
|
const result = await repo.delete(numericId);
|
|
@@ -7649,7 +8196,7 @@ function createVendorDashboardHandler(config) {
|
|
|
7649
8196
|
if (pe) return pe;
|
|
7650
8197
|
}
|
|
7651
8198
|
const user = await getSessionUser();
|
|
7652
|
-
if (!user || !
|
|
8199
|
+
if (!user || !chunkX6UQFV4X_cjs.isVendorPortalUser(user)) {
|
|
7653
8200
|
return json({
|
|
7654
8201
|
error: "Forbidden"
|
|
7655
8202
|
}, {
|
|
@@ -8088,6 +8635,12 @@ function createUploadHandler(config) {
|
|
|
8088
8635
|
parentId
|
|
8089
8636
|
});
|
|
8090
8637
|
} catch (err) {
|
|
8638
|
+
console.error("[upload] File upload failed", {
|
|
8639
|
+
error: err instanceof Error ? err.message : String(err),
|
|
8640
|
+
stack: err instanceof Error ? err.stack : void 0,
|
|
8641
|
+
name: err instanceof Error ? err.name : void 0,
|
|
8642
|
+
metadata: err && typeof err === "object" && "$metadata" in err ? err.$metadata : void 0
|
|
8643
|
+
});
|
|
8091
8644
|
return json({
|
|
8092
8645
|
error: "File upload failed"
|
|
8093
8646
|
}, {
|
|
@@ -8793,41 +9346,68 @@ function createUsersApiHandlers(config) {
|
|
|
8793
9346
|
const page = Math.max(1, parseInt(url.searchParams.get("page") || "1", 10));
|
|
8794
9347
|
const limit = Math.min(100, parseInt(url.searchParams.get("limit") || "10", 10));
|
|
8795
9348
|
const skip = (page - 1) * limit;
|
|
8796
|
-
const
|
|
9349
|
+
const sortFieldRaw = url.searchParams.get("sortField") || "createdAt";
|
|
9350
|
+
const allowedSort = /* @__PURE__ */ new Set([
|
|
9351
|
+
"createdAt",
|
|
9352
|
+
"updatedAt",
|
|
9353
|
+
"name",
|
|
9354
|
+
"email",
|
|
9355
|
+
"id",
|
|
9356
|
+
"blocked"
|
|
9357
|
+
]);
|
|
9358
|
+
const sortField = allowedSort.has(sortFieldRaw) ? sortFieldRaw : "createdAt";
|
|
8797
9359
|
const sortOrder = url.searchParams.get("sortOrder") === "desc" ? "DESC" : "ASC";
|
|
8798
|
-
const search = url.searchParams.get("search");
|
|
8799
|
-
const
|
|
8800
|
-
|
|
8801
|
-
name: typeorm.ILike(`%${search}%`),
|
|
8802
|
-
deleted: false
|
|
8803
|
-
},
|
|
8804
|
-
{
|
|
8805
|
-
email: typeorm.ILike(`%${search}%`),
|
|
8806
|
-
deleted: false
|
|
8807
|
-
}
|
|
8808
|
-
] : {
|
|
9360
|
+
const search = url.searchParams.get("search")?.trim() || "";
|
|
9361
|
+
const groupName = url.searchParams.get("groupName")?.trim() || "";
|
|
9362
|
+
const qb = userRepo().createQueryBuilder("u").leftJoinAndSelect("u.group", "g").where("u.deleted = :deleted", {
|
|
8809
9363
|
deleted: false
|
|
8810
|
-
}
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
9364
|
+
}).orderBy(`u.${sortField}`, sortOrder).skip(skip).take(limit).select([
|
|
9365
|
+
"u.id",
|
|
9366
|
+
"u.name",
|
|
9367
|
+
"u.email",
|
|
9368
|
+
"u.blocked",
|
|
9369
|
+
"u.createdAt",
|
|
9370
|
+
"u.updatedAt",
|
|
9371
|
+
"u.groupId",
|
|
9372
|
+
"g.id",
|
|
9373
|
+
"g.name"
|
|
9374
|
+
]);
|
|
9375
|
+
if (search) {
|
|
9376
|
+
qb.andWhere("(u.name ILIKE :search OR u.email ILIKE :search)", {
|
|
9377
|
+
search: `%${search}%`
|
|
9378
|
+
});
|
|
9379
|
+
}
|
|
9380
|
+
if (groupName) {
|
|
9381
|
+
if (!entityMap.user_groups) {
|
|
9382
|
+
return json({
|
|
9383
|
+
total: 0,
|
|
9384
|
+
page,
|
|
9385
|
+
limit,
|
|
9386
|
+
totalPages: 0,
|
|
9387
|
+
data: []
|
|
9388
|
+
});
|
|
9389
|
+
}
|
|
9390
|
+
const groupRepo = dataSource.getRepository(entityMap.user_groups);
|
|
9391
|
+
const group = await groupRepo.findOne({
|
|
9392
|
+
where: {
|
|
9393
|
+
name: groupName,
|
|
9394
|
+
deleted: false
|
|
9395
|
+
}
|
|
9396
|
+
});
|
|
9397
|
+
if (!group) {
|
|
9398
|
+
return json({
|
|
9399
|
+
total: 0,
|
|
9400
|
+
page,
|
|
9401
|
+
limit,
|
|
9402
|
+
totalPages: 0,
|
|
9403
|
+
data: []
|
|
9404
|
+
});
|
|
9405
|
+
}
|
|
9406
|
+
qb.andWhere("u.groupId = :groupId", {
|
|
9407
|
+
groupId: Number(group.id)
|
|
9408
|
+
});
|
|
9409
|
+
}
|
|
9410
|
+
const [data, total] = await qb.getManyAndCount();
|
|
8831
9411
|
return json({
|
|
8832
9412
|
total,
|
|
8833
9413
|
page,
|
|
@@ -11468,7 +12048,7 @@ chunkUSNT2KNT_cjs.__name(findActiveRefundPolicyForVendor, "findActiveRefundPolic
|
|
|
11468
12048
|
// src/api/admin-roles-handlers.ts
|
|
11469
12049
|
function createAdminRolesHandlers(config) {
|
|
11470
12050
|
const { dataSource, entityMap, json, getSessionUser } = config;
|
|
11471
|
-
const baseEntities =
|
|
12051
|
+
const baseEntities = chunkX6UQFV4X_cjs.getPermissionableEntityKeys(entityMap);
|
|
11472
12052
|
const allowEntities = /* @__PURE__ */ new Set([
|
|
11473
12053
|
...baseEntities,
|
|
11474
12054
|
"users"
|
|
@@ -11483,7 +12063,7 @@ function createAdminRolesHandlers(config) {
|
|
|
11483
12063
|
}, {
|
|
11484
12064
|
status: 401
|
|
11485
12065
|
});
|
|
11486
|
-
if (!
|
|
12066
|
+
if (!chunkZMRQ72F6_cjs.canManageRoles(u) && !chunkX6UQFV4X_cjs.canManageVendorRoles(u)) {
|
|
11487
12067
|
return json({
|
|
11488
12068
|
error: "Forbidden"
|
|
11489
12069
|
}, {
|
|
@@ -11494,11 +12074,11 @@ function createAdminRolesHandlers(config) {
|
|
|
11494
12074
|
}
|
|
11495
12075
|
chunkUSNT2KNT_cjs.__name(gate, "gate");
|
|
11496
12076
|
function isVendorRolesOnly(u) {
|
|
11497
|
-
return
|
|
12077
|
+
return chunkX6UQFV4X_cjs.canManageVendorRoles(u) && !chunkZMRQ72F6_cjs.canManageRoles(u);
|
|
11498
12078
|
}
|
|
11499
12079
|
chunkUSNT2KNT_cjs.__name(isVendorRolesOnly, "isVendorRolesOnly");
|
|
11500
12080
|
const vendorRoleEntities = [
|
|
11501
|
-
...
|
|
12081
|
+
...chunkX6UQFV4X_cjs.VENDOR_STORE_RBAC_ENTITIES,
|
|
11502
12082
|
"dashboard",
|
|
11503
12083
|
"settings"
|
|
11504
12084
|
].sort();
|
|
@@ -11655,7 +12235,7 @@ function createAdminRolesHandlers(config) {
|
|
|
11655
12235
|
}, {
|
|
11656
12236
|
status: 404
|
|
11657
12237
|
});
|
|
11658
|
-
if (
|
|
12238
|
+
if (chunkX6UQFV4X_cjs.isSuperAdminGroupName(g.name) && !chunkX6UQFV4X_cjs.isSuperAdminGroupName(name)) {
|
|
11659
12239
|
return json({
|
|
11660
12240
|
error: "Cannot rename the administrator group"
|
|
11661
12241
|
}, {
|
|
@@ -11712,7 +12292,7 @@ function createAdminRolesHandlers(config) {
|
|
|
11712
12292
|
}, {
|
|
11713
12293
|
status: 404
|
|
11714
12294
|
});
|
|
11715
|
-
if (
|
|
12295
|
+
if (chunkX6UQFV4X_cjs.isSuperAdminGroupName(g.name)) return json({
|
|
11716
12296
|
error: "Cannot delete the administrator group"
|
|
11717
12297
|
}, {
|
|
11718
12298
|
status: 400
|
|
@@ -11880,7 +12460,7 @@ chunkUSNT2KNT_cjs.__name(sendVendorOnboardEmails, "sendVendorOnboardEmails");
|
|
|
11880
12460
|
|
|
11881
12461
|
// src/lib/seed-vendor-roles.ts
|
|
11882
12462
|
async function insertRolePermissions(exec, vendorRoleId, permissions) {
|
|
11883
|
-
for (const entity of
|
|
12463
|
+
for (const entity of chunkX6UQFV4X_cjs.VENDOR_RBAC_ENTITIES) {
|
|
11884
12464
|
const flags = permissions[entity];
|
|
11885
12465
|
if (!flags) continue;
|
|
11886
12466
|
await exec.query(`
|
|
@@ -11911,7 +12491,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
|
|
|
11911
12491
|
for (const r of existing) {
|
|
11912
12492
|
roleIdsByName2[r.name] = Number(r.id);
|
|
11913
12493
|
if (r.isOwnerRole) ownerRoleId2 = Number(r.id);
|
|
11914
|
-
if (r.name ===
|
|
12494
|
+
if (r.name === chunkX6UQFV4X_cjs.VENDOR_VIEWER_ROLE_NAME) viewerRoleId2 = Number(r.id);
|
|
11915
12495
|
}
|
|
11916
12496
|
return {
|
|
11917
12497
|
roleIdsByName: roleIdsByName2,
|
|
@@ -11922,7 +12502,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
|
|
|
11922
12502
|
const roleIdsByName = {};
|
|
11923
12503
|
let ownerRoleId = 0;
|
|
11924
12504
|
let viewerRoleId = 0;
|
|
11925
|
-
for (const def of
|
|
12505
|
+
for (const def of chunkX6UQFV4X_cjs.DEFAULT_VENDOR_ROLE_DEFS) {
|
|
11926
12506
|
const inserted = await exec.query(`
|
|
11927
12507
|
INSERT INTO "vendor_roles"
|
|
11928
12508
|
("vendorId", "name", "description", "isSystem", "isOwnerRole")
|
|
@@ -11939,7 +12519,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
|
|
|
11939
12519
|
if (!roleId) continue;
|
|
11940
12520
|
roleIdsByName[def.name] = roleId;
|
|
11941
12521
|
if (def.isOwnerRole) ownerRoleId = roleId;
|
|
11942
|
-
if (def.name ===
|
|
12522
|
+
if (def.name === chunkX6UQFV4X_cjs.VENDOR_VIEWER_ROLE_NAME) viewerRoleId = roleId;
|
|
11943
12523
|
await insertRolePermissions(exec, roleId, def.permissions);
|
|
11944
12524
|
}
|
|
11945
12525
|
return {
|
|
@@ -11960,7 +12540,7 @@ async function backfillVendorUserRoleIds(em, vendorId, seeded) {
|
|
|
11960
12540
|
vendorId
|
|
11961
12541
|
]);
|
|
11962
12542
|
}
|
|
11963
|
-
const viewerId = seeded.viewerRoleId || seeded.roleIdsByName[
|
|
12543
|
+
const viewerId = seeded.viewerRoleId || seeded.roleIdsByName[chunkX6UQFV4X_cjs.VENDOR_VIEWER_ROLE_NAME];
|
|
11964
12544
|
if (viewerId) {
|
|
11965
12545
|
await em.query(`
|
|
11966
12546
|
UPDATE "vendor_users"
|
|
@@ -11986,7 +12566,7 @@ async function getDefaultStaffRoleIdForVendor(em, vendorId) {
|
|
|
11986
12566
|
LIMIT 1
|
|
11987
12567
|
`, [
|
|
11988
12568
|
vendorId,
|
|
11989
|
-
|
|
12569
|
+
chunkX6UQFV4X_cjs.VENDOR_VIEWER_ROLE_NAME
|
|
11990
12570
|
]);
|
|
11991
12571
|
const id = rows[0]?.id;
|
|
11992
12572
|
return id != null ? Number(id) : null;
|
|
@@ -12162,7 +12742,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12162
12742
|
}, {
|
|
12163
12743
|
status: 401
|
|
12164
12744
|
});
|
|
12165
|
-
if (!
|
|
12745
|
+
if (!chunkX6UQFV4X_cjs.isPlatformAdministrator(u)) return json({
|
|
12166
12746
|
error: "Forbidden",
|
|
12167
12747
|
reason: "admin_only"
|
|
12168
12748
|
}, {
|
|
@@ -12172,7 +12752,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12172
12752
|
}
|
|
12173
12753
|
chunkUSNT2KNT_cjs.__name(gateAdmin, "gateAdmin");
|
|
12174
12754
|
async function resolveActiveVendorId(u) {
|
|
12175
|
-
const scope =
|
|
12755
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u);
|
|
12176
12756
|
if (scope.type === "vendor") return scope.vendorId;
|
|
12177
12757
|
if (scope.type === "all") {
|
|
12178
12758
|
const id = u.activeVendorId ?? u.vendorIds?.[0];
|
|
@@ -12188,7 +12768,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12188
12768
|
}, {
|
|
12189
12769
|
status: 401
|
|
12190
12770
|
});
|
|
12191
|
-
if (!
|
|
12771
|
+
if (!chunkX6UQFV4X_cjs.canManageVendorTeam(u)) return json({
|
|
12192
12772
|
error: "Forbidden"
|
|
12193
12773
|
}, {
|
|
12194
12774
|
status: 403
|
|
@@ -12304,19 +12884,19 @@ function createVendorOnboardHandlers(config) {
|
|
|
12304
12884
|
if (dupVendor) throw new Error("VENDOR_SLUG_EXISTS");
|
|
12305
12885
|
let ownerGroup = await groupRepo.findOne({
|
|
12306
12886
|
where: {
|
|
12307
|
-
name:
|
|
12887
|
+
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
12308
12888
|
deleted: false
|
|
12309
12889
|
}
|
|
12310
12890
|
});
|
|
12311
12891
|
if (!ownerGroup) {
|
|
12312
12892
|
try {
|
|
12313
12893
|
await groupRepo.save(groupRepo.create({
|
|
12314
|
-
name:
|
|
12894
|
+
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
12315
12895
|
deleted: false
|
|
12316
12896
|
}));
|
|
12317
12897
|
ownerGroup = await groupRepo.findOne({
|
|
12318
12898
|
where: {
|
|
12319
|
-
name:
|
|
12899
|
+
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
12320
12900
|
deleted: false
|
|
12321
12901
|
}
|
|
12322
12902
|
});
|
|
@@ -12776,7 +13356,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12776
13356
|
if (!groupId) {
|
|
12777
13357
|
const g = await groupRepo.findOne({
|
|
12778
13358
|
where: {
|
|
12779
|
-
name:
|
|
13359
|
+
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
12780
13360
|
deleted: false
|
|
12781
13361
|
}
|
|
12782
13362
|
});
|
|
@@ -13086,10 +13666,10 @@ chunkUSNT2KNT_cjs.__name(createVendorOnboardHandlers, "createVendorOnboardHandle
|
|
|
13086
13666
|
function createVendorRolesHandlers(config) {
|
|
13087
13667
|
const { dataSource, entityMap, json, getSessionUser } = config;
|
|
13088
13668
|
const vendorRoleEntities = [
|
|
13089
|
-
...
|
|
13669
|
+
...chunkX6UQFV4X_cjs.VENDOR_RBAC_ENTITIES
|
|
13090
13670
|
].sort();
|
|
13091
13671
|
async function resolveActiveVendorId(u) {
|
|
13092
|
-
const scope =
|
|
13672
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u);
|
|
13093
13673
|
if (scope.type === "vendor") return scope.vendorId;
|
|
13094
13674
|
if (scope.type === "all") {
|
|
13095
13675
|
const id = u.activeVendorId ?? u.vendorIds?.[0];
|
|
@@ -13105,7 +13685,7 @@ function createVendorRolesHandlers(config) {
|
|
|
13105
13685
|
}, {
|
|
13106
13686
|
status: 401
|
|
13107
13687
|
});
|
|
13108
|
-
if (!
|
|
13688
|
+
if (!chunkX6UQFV4X_cjs.canManageVendorRoles(u)) return json({
|
|
13109
13689
|
error: "Forbidden"
|
|
13110
13690
|
}, {
|
|
13111
13691
|
status: 403
|
|
@@ -17044,6 +17624,7 @@ exports.Brand = class Brand {
|
|
|
17044
17624
|
chunkUSNT2KNT_cjs.__name(this, "Brand");
|
|
17045
17625
|
}
|
|
17046
17626
|
id;
|
|
17627
|
+
/** Null for platform catalog brands (`isCatalog`). */
|
|
17047
17628
|
vendorId;
|
|
17048
17629
|
name;
|
|
17049
17630
|
slug;
|
|
@@ -17051,6 +17632,8 @@ exports.Brand = class Brand {
|
|
|
17051
17632
|
metadata;
|
|
17052
17633
|
description;
|
|
17053
17634
|
active;
|
|
17635
|
+
/** Platform-wide catalog brand — vendors pick these on products unless allowed to create their own. */
|
|
17636
|
+
isCatalog;
|
|
17054
17637
|
sortOrder;
|
|
17055
17638
|
createdAt;
|
|
17056
17639
|
updatedAt;
|
|
@@ -17070,8 +17653,10 @@ _ts_decorate30([
|
|
|
17070
17653
|
_ts_metadata30("design:type", Number)
|
|
17071
17654
|
], exports.Brand.prototype, "id", void 0);
|
|
17072
17655
|
_ts_decorate30([
|
|
17073
|
-
typeorm.Column("int"
|
|
17074
|
-
|
|
17656
|
+
typeorm.Column("int", {
|
|
17657
|
+
nullable: true
|
|
17658
|
+
}),
|
|
17659
|
+
_ts_metadata30("design:type", Object)
|
|
17075
17660
|
], exports.Brand.prototype, "vendorId", void 0);
|
|
17076
17661
|
_ts_decorate30([
|
|
17077
17662
|
typeorm.Column("varchar"),
|
|
@@ -17105,6 +17690,12 @@ _ts_decorate30([
|
|
|
17105
17690
|
}),
|
|
17106
17691
|
_ts_metadata30("design:type", Boolean)
|
|
17107
17692
|
], exports.Brand.prototype, "active", void 0);
|
|
17693
|
+
_ts_decorate30([
|
|
17694
|
+
typeorm.Column("boolean", {
|
|
17695
|
+
default: false
|
|
17696
|
+
}),
|
|
17697
|
+
_ts_metadata30("design:type", Boolean)
|
|
17698
|
+
], exports.Brand.prototype, "isCatalog", void 0);
|
|
17108
17699
|
_ts_decorate30([
|
|
17109
17700
|
typeorm.Column("int", {
|
|
17110
17701
|
default: 0
|
|
@@ -17164,12 +17755,13 @@ _ts_decorate30([
|
|
|
17164
17755
|
], exports.Brand.prototype, "seoId", void 0);
|
|
17165
17756
|
_ts_decorate30([
|
|
17166
17757
|
typeorm.ManyToOne(() => exports.Vendor, {
|
|
17167
|
-
onDelete: "RESTRICT"
|
|
17758
|
+
onDelete: "RESTRICT",
|
|
17759
|
+
nullable: true
|
|
17168
17760
|
}),
|
|
17169
17761
|
typeorm.JoinColumn({
|
|
17170
17762
|
name: "vendorId"
|
|
17171
17763
|
}),
|
|
17172
|
-
_ts_metadata30("design:type",
|
|
17764
|
+
_ts_metadata30("design:type", Object)
|
|
17173
17765
|
], exports.Brand.prototype, "vendor", void 0);
|
|
17174
17766
|
_ts_decorate30([
|
|
17175
17767
|
typeorm.ManyToOne(() => exports.Seo, {
|
|
@@ -17453,6 +18045,14 @@ exports.Product = class Product {
|
|
|
17453
18045
|
currencyPrices;
|
|
17454
18046
|
quantity;
|
|
17455
18047
|
status;
|
|
18048
|
+
/**
|
|
18049
|
+
* Separate from catalog status. Used when multi_vendor.requireProductApproval is on.
|
|
18050
|
+
* `approved` also forces `status = available` (live).
|
|
18051
|
+
*/
|
|
18052
|
+
approvalStatus;
|
|
18053
|
+
rejectionReason;
|
|
18054
|
+
rejectedAt;
|
|
18055
|
+
rejectedBy;
|
|
17456
18056
|
featured;
|
|
17457
18057
|
metadata;
|
|
17458
18058
|
createdAt;
|
|
@@ -17576,6 +18176,31 @@ _ts_decorate32([
|
|
|
17576
18176
|
}),
|
|
17577
18177
|
_ts_metadata32("design:type", String)
|
|
17578
18178
|
], exports.Product.prototype, "status", void 0);
|
|
18179
|
+
_ts_decorate32([
|
|
18180
|
+
typeorm.Column("varchar", {
|
|
18181
|
+
nullable: true
|
|
18182
|
+
}),
|
|
18183
|
+
_ts_metadata32("design:type", Object)
|
|
18184
|
+
], exports.Product.prototype, "approvalStatus", void 0);
|
|
18185
|
+
_ts_decorate32([
|
|
18186
|
+
typeorm.Column("text", {
|
|
18187
|
+
nullable: true
|
|
18188
|
+
}),
|
|
18189
|
+
_ts_metadata32("design:type", Object)
|
|
18190
|
+
], exports.Product.prototype, "rejectionReason", void 0);
|
|
18191
|
+
_ts_decorate32([
|
|
18192
|
+
typeorm.Column({
|
|
18193
|
+
type: "timestamptz",
|
|
18194
|
+
nullable: true
|
|
18195
|
+
}),
|
|
18196
|
+
_ts_metadata32("design:type", Object)
|
|
18197
|
+
], exports.Product.prototype, "rejectedAt", void 0);
|
|
18198
|
+
_ts_decorate32([
|
|
18199
|
+
typeorm.Column("int", {
|
|
18200
|
+
nullable: true
|
|
18201
|
+
}),
|
|
18202
|
+
_ts_metadata32("design:type", Object)
|
|
18203
|
+
], exports.Product.prototype, "rejectedBy", void 0);
|
|
17579
18204
|
_ts_decorate32([
|
|
17580
18205
|
typeorm.Column("boolean", {
|
|
17581
18206
|
default: false
|
|
@@ -20664,6 +21289,14 @@ exports.Event = class Event {
|
|
|
20664
21289
|
expectedSpeakers;
|
|
20665
21290
|
expectedParticipants;
|
|
20666
21291
|
isActive;
|
|
21292
|
+
/**
|
|
21293
|
+
* Separate from isActive. Used when events.requireEventApproval is on.
|
|
21294
|
+
* `approved` also forces `isActive = true` (live).
|
|
21295
|
+
*/
|
|
21296
|
+
approvalStatus;
|
|
21297
|
+
rejectionReason;
|
|
21298
|
+
rejectedAt;
|
|
21299
|
+
rejectedBy;
|
|
20667
21300
|
comingSoon;
|
|
20668
21301
|
bannerImageUrl;
|
|
20669
21302
|
logoUrl;
|
|
@@ -20758,6 +21391,31 @@ _ts_decorate60([
|
|
|
20758
21391
|
}),
|
|
20759
21392
|
_ts_metadata60("design:type", Boolean)
|
|
20760
21393
|
], exports.Event.prototype, "isActive", void 0);
|
|
21394
|
+
_ts_decorate60([
|
|
21395
|
+
typeorm.Column("varchar", {
|
|
21396
|
+
nullable: true
|
|
21397
|
+
}),
|
|
21398
|
+
_ts_metadata60("design:type", Object)
|
|
21399
|
+
], exports.Event.prototype, "approvalStatus", void 0);
|
|
21400
|
+
_ts_decorate60([
|
|
21401
|
+
typeorm.Column("text", {
|
|
21402
|
+
nullable: true
|
|
21403
|
+
}),
|
|
21404
|
+
_ts_metadata60("design:type", Object)
|
|
21405
|
+
], exports.Event.prototype, "rejectionReason", void 0);
|
|
21406
|
+
_ts_decorate60([
|
|
21407
|
+
typeorm.Column({
|
|
21408
|
+
type: "timestamptz",
|
|
21409
|
+
nullable: true
|
|
21410
|
+
}),
|
|
21411
|
+
_ts_metadata60("design:type", Object)
|
|
21412
|
+
], exports.Event.prototype, "rejectedAt", void 0);
|
|
21413
|
+
_ts_decorate60([
|
|
21414
|
+
typeorm.Column("int", {
|
|
21415
|
+
nullable: true
|
|
21416
|
+
}),
|
|
21417
|
+
_ts_metadata60("design:type", Object)
|
|
21418
|
+
], exports.Event.prototype, "rejectedBy", void 0);
|
|
20761
21419
|
_ts_decorate60([
|
|
20762
21420
|
typeorm.Column("boolean", {
|
|
20763
21421
|
default: false
|
|
@@ -21318,18 +21976,20 @@ _ts_decorate63([
|
|
|
21318
21976
|
], exports.Combo.prototype, "desc", void 0);
|
|
21319
21977
|
_ts_decorate63([
|
|
21320
21978
|
typeorm.Column({
|
|
21321
|
-
type: "integer"
|
|
21979
|
+
type: "integer",
|
|
21980
|
+
nullable: true
|
|
21322
21981
|
}),
|
|
21323
|
-
_ts_metadata63("design:type",
|
|
21982
|
+
_ts_metadata63("design:type", Object)
|
|
21324
21983
|
], exports.Combo.prototype, "eventId", void 0);
|
|
21325
21984
|
_ts_decorate63([
|
|
21326
21985
|
typeorm.ManyToOne(() => exports.Event, {
|
|
21327
|
-
onDelete: "CASCADE"
|
|
21986
|
+
onDelete: "CASCADE",
|
|
21987
|
+
nullable: true
|
|
21328
21988
|
}),
|
|
21329
21989
|
typeorm.JoinColumn({
|
|
21330
21990
|
name: "eventId"
|
|
21331
21991
|
}),
|
|
21332
|
-
_ts_metadata63("design:type",
|
|
21992
|
+
_ts_metadata63("design:type", Object)
|
|
21333
21993
|
], exports.Combo.prototype, "event", void 0);
|
|
21334
21994
|
_ts_decorate63([
|
|
21335
21995
|
typeorm.Column({
|
|
@@ -25589,7 +26249,7 @@ function createCmsApiHandler(config) {
|
|
|
25589
26249
|
] : baseCrudResources;
|
|
25590
26250
|
const requireEntityPermissionEffective = /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async (_req, entity, action) => {
|
|
25591
26251
|
if (!resolveSessionUser) {
|
|
25592
|
-
|
|
26252
|
+
chunkX6UQFV4X_cjs.logRbac("requireEntityPermission: getSessionUser not passed \u2014 vendor store APIs may 403", {
|
|
25593
26253
|
entity,
|
|
25594
26254
|
action,
|
|
25595
26255
|
hint: "Pass getSessionUser: auth.getAuthenticatedUser from createCmsAuthBundle()"
|
|
@@ -25599,7 +26259,7 @@ function createCmsApiHandler(config) {
|
|
|
25599
26259
|
const raw = await resolveSessionUser();
|
|
25600
26260
|
const u = await hydrateVendorSessionUser(dataSource, raw);
|
|
25601
26261
|
if (!u?.email) {
|
|
25602
|
-
|
|
26262
|
+
chunkX6UQFV4X_cjs.logRbac("requireEntityPermission: no session user", {
|
|
25603
26263
|
entity,
|
|
25604
26264
|
action
|
|
25605
26265
|
});
|
|
@@ -25609,13 +26269,13 @@ function createCmsApiHandler(config) {
|
|
|
25609
26269
|
status: 401
|
|
25610
26270
|
});
|
|
25611
26271
|
}
|
|
25612
|
-
const allowed =
|
|
25613
|
-
await
|
|
26272
|
+
const allowed = chunkZMRQ72F6_cjs.sessionHasEntityAccess(u, entity, action);
|
|
26273
|
+
await chunkX6UQFV4X_cjs.logEntityAccessDecision(dataSource, "cmsApi.requireEntityPermission", u, entity, action, {
|
|
25614
26274
|
allowed,
|
|
25615
26275
|
resolvePath: "hydrated_session"
|
|
25616
26276
|
});
|
|
25617
26277
|
if (allowed) return null;
|
|
25618
|
-
const { reason } =
|
|
26278
|
+
const { reason } = chunkX6UQFV4X_cjs.explainSessionEntityAccess(u, entity, action);
|
|
25619
26279
|
return config.json({
|
|
25620
26280
|
error: "Forbidden",
|
|
25621
26281
|
entity,
|
|
@@ -25626,7 +26286,7 @@ function createCmsApiHandler(config) {
|
|
|
25626
26286
|
});
|
|
25627
26287
|
}
|
|
25628
26288
|
if (userRequireEntityPermission) {
|
|
25629
|
-
|
|
26289
|
+
chunkX6UQFV4X_cjs.logRbac("requireEntityPermission: using app callback only (no getSessionUser)", {
|
|
25630
26290
|
entity,
|
|
25631
26291
|
action
|
|
25632
26292
|
});
|
|
@@ -25713,10 +26373,10 @@ function createCmsApiHandler(config) {
|
|
|
25713
26373
|
getVendorScope: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => {
|
|
25714
26374
|
const multiVendorEnabled = await checkMultiVendorEnabled(dataSource);
|
|
25715
26375
|
if (!multiVendorEnabled) {
|
|
25716
|
-
return
|
|
26376
|
+
return chunkX6UQFV4X_cjs.resolveDisabledMultiVendorScope(dataSource);
|
|
25717
26377
|
}
|
|
25718
26378
|
const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
|
|
25719
|
-
return
|
|
26379
|
+
return chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u ?? null);
|
|
25720
26380
|
}, "getVendorScope"),
|
|
25721
26381
|
getHydratedSessionUser: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => {
|
|
25722
26382
|
const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
|
|
@@ -26642,16 +27302,24 @@ function createCmsApiHandler(config) {
|
|
|
26642
27302
|
if (pe) return pe;
|
|
26643
27303
|
if (group === "multi_vendor") {
|
|
26644
27304
|
invalidateMultiVendorCache();
|
|
27305
|
+
invalidateVendorCatalogCreateFlagsCache();
|
|
27306
|
+
invalidateRequireProductApprovalCache();
|
|
27307
|
+
invalidateRequireEventApprovalCache();
|
|
26645
27308
|
}
|
|
26646
27309
|
if (group === "events") {
|
|
26647
27310
|
invalidateEventsCache();
|
|
27311
|
+
invalidateRequireEventApprovalCache();
|
|
26648
27312
|
}
|
|
26649
27313
|
const res = await settingsHandlers.PUT(req, group);
|
|
26650
27314
|
if (group === "multi_vendor") {
|
|
26651
27315
|
invalidateMultiVendorCache();
|
|
27316
|
+
invalidateVendorCatalogCreateFlagsCache();
|
|
27317
|
+
invalidateRequireProductApprovalCache();
|
|
27318
|
+
invalidateRequireEventApprovalCache();
|
|
26652
27319
|
}
|
|
26653
27320
|
if (group === "events") {
|
|
26654
27321
|
invalidateEventsCache();
|
|
27322
|
+
invalidateRequireEventApprovalCache();
|
|
26655
27323
|
}
|
|
26656
27324
|
return res;
|
|
26657
27325
|
}
|
|
@@ -26975,7 +27643,7 @@ function createCmsApiHandler(config) {
|
|
|
26975
27643
|
let vendorId = null;
|
|
26976
27644
|
if (resolveSessionUser) {
|
|
26977
27645
|
const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
|
|
26978
|
-
const scope =
|
|
27646
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u ?? null);
|
|
26979
27647
|
if (scope.type === "vendor") vendorId = scope.vendorId;
|
|
26980
27648
|
}
|
|
26981
27649
|
const result = await validateCoupon(dataSource, entityMap, couponCode, orderLinesNorm, currency, contactId, isAutomatic, discountId ?? void 0, vendorId);
|
|
@@ -27055,7 +27723,7 @@ function createCmsApiHandler(config) {
|
|
|
27055
27723
|
let vendorId = null;
|
|
27056
27724
|
if (resolveSessionUser) {
|
|
27057
27725
|
const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
|
|
27058
|
-
const scope =
|
|
27726
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u ?? null);
|
|
27059
27727
|
if (scope.type === "vendor") vendorId = scope.vendorId;
|
|
27060
27728
|
}
|
|
27061
27729
|
const orderLinesNorm = normalizeOrderLinesInput(body?.orderLines);
|
|
@@ -27669,7 +28337,7 @@ function createCmsApiHandler(config) {
|
|
|
27669
28337
|
if (resolveSessionUser) {
|
|
27670
28338
|
const raw = await resolveSessionUser();
|
|
27671
28339
|
const u = await hydrateVendorSessionUser(dataSource, raw);
|
|
27672
|
-
const scope =
|
|
28340
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u ?? null);
|
|
27673
28341
|
if (scope.type === "vendor") {
|
|
27674
28342
|
scopedVendorIds = scope.vendorIds;
|
|
27675
28343
|
}
|
|
@@ -30968,10 +31636,16 @@ exports.BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG = BLOG_METADATA_ENRICHER_LLM_AGENT
|
|
|
30968
31636
|
exports.BlogGeneratorService = BlogGeneratorService;
|
|
30969
31637
|
exports.CMS_ENTITY_MAP = CMS_ENTITY_MAP;
|
|
30970
31638
|
exports.ZIP_MIME_TYPES = ZIP_MIME_TYPES;
|
|
31639
|
+
exports.applyApprovalStatusSideEffects = applyApprovalStatusSideEffects;
|
|
31640
|
+
exports.applyEventApprovalStatusSideEffects = applyEventApprovalStatusSideEffects;
|
|
30971
31641
|
exports.applyRotatingVendorInvite = applyRotatingVendorInvite;
|
|
30972
31642
|
exports.applyVendorCustomersContactFilter = applyVendorCustomersContactFilter;
|
|
31643
|
+
exports.applyVendorEventCreateApproval = applyVendorEventCreateApproval;
|
|
31644
|
+
exports.applyVendorProductCreateApproval = applyVendorProductCreateApproval;
|
|
30973
31645
|
exports.assertCaptchaOk = assertCaptchaOk;
|
|
30974
31646
|
exports.assertContactAllowedForVendorOrder = assertContactAllowedForVendorOrder;
|
|
31647
|
+
exports.assertEventApprovalUpdate = assertEventApprovalUpdate;
|
|
31648
|
+
exports.assertProductApprovalUpdate = assertProductApprovalUpdate;
|
|
30975
31649
|
exports.buildBlogMetadataUserPrompt = buildBlogMetadataUserPrompt;
|
|
30976
31650
|
exports.buildCronFromSchedule = buildCronFromSchedule;
|
|
30977
31651
|
exports.buildRssUserPromptFromFeeds = buildRssUserPromptFromFeeds;
|
|
@@ -31024,11 +31698,17 @@ exports.findVendorByInviteToken = findVendorByInviteToken;
|
|
|
31024
31698
|
exports.formatTierRange = formatTierRange;
|
|
31025
31699
|
exports.generateNumericOtp = generateNumericOtp;
|
|
31026
31700
|
exports.getPublicSettingsGroup = getPublicSettingsGroup;
|
|
31701
|
+
exports.getRequireEventApproval = getRequireEventApproval;
|
|
31702
|
+
exports.getRequireProductApproval = getRequireProductApproval;
|
|
31027
31703
|
exports.getRssArticleSummaryFromItem = getRssArticleSummaryFromItem;
|
|
31704
|
+
exports.getVendorCatalogCreateFlags = getVendorCatalogCreateFlags;
|
|
31028
31705
|
exports.hashOtpCode = hashOtpCode;
|
|
31029
31706
|
exports.hydrateVendorSessionUser = hydrateVendorSessionUser;
|
|
31030
31707
|
exports.invalidateEventsCache = invalidateEventsCache;
|
|
31031
31708
|
exports.invalidateMultiVendorCache = invalidateMultiVendorCache;
|
|
31709
|
+
exports.invalidateRequireEventApprovalCache = invalidateRequireEventApprovalCache;
|
|
31710
|
+
exports.invalidateRequireProductApprovalCache = invalidateRequireProductApprovalCache;
|
|
31711
|
+
exports.invalidateVendorCatalogCreateFlagsCache = invalidateVendorCatalogCreateFlagsCache;
|
|
31032
31712
|
exports.isCustomerTypeContact = isCustomerTypeContact;
|
|
31033
31713
|
exports.isZipMedia = isZipMedia;
|
|
31034
31714
|
exports.linkUnclaimedContactToUser = linkUnclaimedContactToUser;
|