@infuro/cms-core 1.0.40 → 1.0.42
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 +1009 -393
- package/dist/admin.d.cts +11 -1
- package/dist/admin.d.ts +11 -1
- package/dist/admin.js +1009 -393
- 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-T7GCOO5Y.cjs → chunk-GINYYPXK.cjs} +828 -219
- package/dist/{chunk-4BG7XYSH.js → chunk-I6NH72MO.js} +1 -1
- package/dist/{chunk-ETZN4OQI.cjs → chunk-TAHX46EI.cjs} +6 -6
- package/dist/{chunk-RCMUL6SZ.js → chunk-W2NL365N.js} +777 -180
- 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 +2 -2
|
@@ -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
|
}, {
|
|
@@ -11468,7 +12015,7 @@ chunkUSNT2KNT_cjs.__name(findActiveRefundPolicyForVendor, "findActiveRefundPolic
|
|
|
11468
12015
|
// src/api/admin-roles-handlers.ts
|
|
11469
12016
|
function createAdminRolesHandlers(config) {
|
|
11470
12017
|
const { dataSource, entityMap, json, getSessionUser } = config;
|
|
11471
|
-
const baseEntities =
|
|
12018
|
+
const baseEntities = chunkX6UQFV4X_cjs.getPermissionableEntityKeys(entityMap);
|
|
11472
12019
|
const allowEntities = /* @__PURE__ */ new Set([
|
|
11473
12020
|
...baseEntities,
|
|
11474
12021
|
"users"
|
|
@@ -11483,7 +12030,7 @@ function createAdminRolesHandlers(config) {
|
|
|
11483
12030
|
}, {
|
|
11484
12031
|
status: 401
|
|
11485
12032
|
});
|
|
11486
|
-
if (!
|
|
12033
|
+
if (!chunkZMRQ72F6_cjs.canManageRoles(u) && !chunkX6UQFV4X_cjs.canManageVendorRoles(u)) {
|
|
11487
12034
|
return json({
|
|
11488
12035
|
error: "Forbidden"
|
|
11489
12036
|
}, {
|
|
@@ -11494,11 +12041,11 @@ function createAdminRolesHandlers(config) {
|
|
|
11494
12041
|
}
|
|
11495
12042
|
chunkUSNT2KNT_cjs.__name(gate, "gate");
|
|
11496
12043
|
function isVendorRolesOnly(u) {
|
|
11497
|
-
return
|
|
12044
|
+
return chunkX6UQFV4X_cjs.canManageVendorRoles(u) && !chunkZMRQ72F6_cjs.canManageRoles(u);
|
|
11498
12045
|
}
|
|
11499
12046
|
chunkUSNT2KNT_cjs.__name(isVendorRolesOnly, "isVendorRolesOnly");
|
|
11500
12047
|
const vendorRoleEntities = [
|
|
11501
|
-
...
|
|
12048
|
+
...chunkX6UQFV4X_cjs.VENDOR_STORE_RBAC_ENTITIES,
|
|
11502
12049
|
"dashboard",
|
|
11503
12050
|
"settings"
|
|
11504
12051
|
].sort();
|
|
@@ -11655,7 +12202,7 @@ function createAdminRolesHandlers(config) {
|
|
|
11655
12202
|
}, {
|
|
11656
12203
|
status: 404
|
|
11657
12204
|
});
|
|
11658
|
-
if (
|
|
12205
|
+
if (chunkX6UQFV4X_cjs.isSuperAdminGroupName(g.name) && !chunkX6UQFV4X_cjs.isSuperAdminGroupName(name)) {
|
|
11659
12206
|
return json({
|
|
11660
12207
|
error: "Cannot rename the administrator group"
|
|
11661
12208
|
}, {
|
|
@@ -11712,7 +12259,7 @@ function createAdminRolesHandlers(config) {
|
|
|
11712
12259
|
}, {
|
|
11713
12260
|
status: 404
|
|
11714
12261
|
});
|
|
11715
|
-
if (
|
|
12262
|
+
if (chunkX6UQFV4X_cjs.isSuperAdminGroupName(g.name)) return json({
|
|
11716
12263
|
error: "Cannot delete the administrator group"
|
|
11717
12264
|
}, {
|
|
11718
12265
|
status: 400
|
|
@@ -11880,7 +12427,7 @@ chunkUSNT2KNT_cjs.__name(sendVendorOnboardEmails, "sendVendorOnboardEmails");
|
|
|
11880
12427
|
|
|
11881
12428
|
// src/lib/seed-vendor-roles.ts
|
|
11882
12429
|
async function insertRolePermissions(exec, vendorRoleId, permissions) {
|
|
11883
|
-
for (const entity of
|
|
12430
|
+
for (const entity of chunkX6UQFV4X_cjs.VENDOR_RBAC_ENTITIES) {
|
|
11884
12431
|
const flags = permissions[entity];
|
|
11885
12432
|
if (!flags) continue;
|
|
11886
12433
|
await exec.query(`
|
|
@@ -11911,7 +12458,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
|
|
|
11911
12458
|
for (const r of existing) {
|
|
11912
12459
|
roleIdsByName2[r.name] = Number(r.id);
|
|
11913
12460
|
if (r.isOwnerRole) ownerRoleId2 = Number(r.id);
|
|
11914
|
-
if (r.name ===
|
|
12461
|
+
if (r.name === chunkX6UQFV4X_cjs.VENDOR_VIEWER_ROLE_NAME) viewerRoleId2 = Number(r.id);
|
|
11915
12462
|
}
|
|
11916
12463
|
return {
|
|
11917
12464
|
roleIdsByName: roleIdsByName2,
|
|
@@ -11922,7 +12469,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
|
|
|
11922
12469
|
const roleIdsByName = {};
|
|
11923
12470
|
let ownerRoleId = 0;
|
|
11924
12471
|
let viewerRoleId = 0;
|
|
11925
|
-
for (const def of
|
|
12472
|
+
for (const def of chunkX6UQFV4X_cjs.DEFAULT_VENDOR_ROLE_DEFS) {
|
|
11926
12473
|
const inserted = await exec.query(`
|
|
11927
12474
|
INSERT INTO "vendor_roles"
|
|
11928
12475
|
("vendorId", "name", "description", "isSystem", "isOwnerRole")
|
|
@@ -11939,7 +12486,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
|
|
|
11939
12486
|
if (!roleId) continue;
|
|
11940
12487
|
roleIdsByName[def.name] = roleId;
|
|
11941
12488
|
if (def.isOwnerRole) ownerRoleId = roleId;
|
|
11942
|
-
if (def.name ===
|
|
12489
|
+
if (def.name === chunkX6UQFV4X_cjs.VENDOR_VIEWER_ROLE_NAME) viewerRoleId = roleId;
|
|
11943
12490
|
await insertRolePermissions(exec, roleId, def.permissions);
|
|
11944
12491
|
}
|
|
11945
12492
|
return {
|
|
@@ -11960,7 +12507,7 @@ async function backfillVendorUserRoleIds(em, vendorId, seeded) {
|
|
|
11960
12507
|
vendorId
|
|
11961
12508
|
]);
|
|
11962
12509
|
}
|
|
11963
|
-
const viewerId = seeded.viewerRoleId || seeded.roleIdsByName[
|
|
12510
|
+
const viewerId = seeded.viewerRoleId || seeded.roleIdsByName[chunkX6UQFV4X_cjs.VENDOR_VIEWER_ROLE_NAME];
|
|
11964
12511
|
if (viewerId) {
|
|
11965
12512
|
await em.query(`
|
|
11966
12513
|
UPDATE "vendor_users"
|
|
@@ -11986,7 +12533,7 @@ async function getDefaultStaffRoleIdForVendor(em, vendorId) {
|
|
|
11986
12533
|
LIMIT 1
|
|
11987
12534
|
`, [
|
|
11988
12535
|
vendorId,
|
|
11989
|
-
|
|
12536
|
+
chunkX6UQFV4X_cjs.VENDOR_VIEWER_ROLE_NAME
|
|
11990
12537
|
]);
|
|
11991
12538
|
const id = rows[0]?.id;
|
|
11992
12539
|
return id != null ? Number(id) : null;
|
|
@@ -12162,7 +12709,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12162
12709
|
}, {
|
|
12163
12710
|
status: 401
|
|
12164
12711
|
});
|
|
12165
|
-
if (!
|
|
12712
|
+
if (!chunkX6UQFV4X_cjs.isPlatformAdministrator(u)) return json({
|
|
12166
12713
|
error: "Forbidden",
|
|
12167
12714
|
reason: "admin_only"
|
|
12168
12715
|
}, {
|
|
@@ -12172,7 +12719,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12172
12719
|
}
|
|
12173
12720
|
chunkUSNT2KNT_cjs.__name(gateAdmin, "gateAdmin");
|
|
12174
12721
|
async function resolveActiveVendorId(u) {
|
|
12175
|
-
const scope =
|
|
12722
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u);
|
|
12176
12723
|
if (scope.type === "vendor") return scope.vendorId;
|
|
12177
12724
|
if (scope.type === "all") {
|
|
12178
12725
|
const id = u.activeVendorId ?? u.vendorIds?.[0];
|
|
@@ -12188,7 +12735,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12188
12735
|
}, {
|
|
12189
12736
|
status: 401
|
|
12190
12737
|
});
|
|
12191
|
-
if (!
|
|
12738
|
+
if (!chunkX6UQFV4X_cjs.canManageVendorTeam(u)) return json({
|
|
12192
12739
|
error: "Forbidden"
|
|
12193
12740
|
}, {
|
|
12194
12741
|
status: 403
|
|
@@ -12266,6 +12813,13 @@ function createVendorOnboardHandlers(config) {
|
|
|
12266
12813
|
status: 400
|
|
12267
12814
|
});
|
|
12268
12815
|
}
|
|
12816
|
+
if (body.activation === "password" || body.user?.password) {
|
|
12817
|
+
return json({
|
|
12818
|
+
error: "Setting a password during vendor onboard is no longer supported. Create the vendor, then send an invite or copy the invite link so the owner can set their own password."
|
|
12819
|
+
}, {
|
|
12820
|
+
status: 400
|
|
12821
|
+
});
|
|
12822
|
+
}
|
|
12269
12823
|
const profile = parseVendorProfileFromBody(body.vendor, {
|
|
12270
12824
|
defaultRegistrationStatus: "approved"
|
|
12271
12825
|
});
|
|
@@ -12275,34 +12829,8 @@ function createVendorOnboardHandlers(config) {
|
|
|
12275
12829
|
}, {
|
|
12276
12830
|
status: 400
|
|
12277
12831
|
});
|
|
12278
|
-
const activation =
|
|
12279
|
-
const
|
|
12280
|
-
let ownerPasswordHash = null;
|
|
12281
|
-
if (activation === "password") {
|
|
12282
|
-
const plain = body.user?.password?.trim();
|
|
12283
|
-
if (!plain) {
|
|
12284
|
-
return json({
|
|
12285
|
-
error: "Password is required when activating with a set password"
|
|
12286
|
-
}, {
|
|
12287
|
-
status: 400
|
|
12288
|
-
});
|
|
12289
|
-
}
|
|
12290
|
-
if (plain.length < minPasswordLength) {
|
|
12291
|
-
return json({
|
|
12292
|
-
error: `Password must be at least ${minPasswordLength} characters`
|
|
12293
|
-
}, {
|
|
12294
|
-
status: 400
|
|
12295
|
-
});
|
|
12296
|
-
}
|
|
12297
|
-
if (!hashPassword) {
|
|
12298
|
-
return json({
|
|
12299
|
-
error: "Password hashing is not configured on the server"
|
|
12300
|
-
}, {
|
|
12301
|
-
status: 501
|
|
12302
|
-
});
|
|
12303
|
-
}
|
|
12304
|
-
ownerPasswordHash = await hashPassword(plain);
|
|
12305
|
-
}
|
|
12832
|
+
const activation = "invite";
|
|
12833
|
+
const ownerPasswordHash = null;
|
|
12306
12834
|
const slug = trimOrNull(body.vendor?.slug) || slugify(vendorName);
|
|
12307
12835
|
if (!slug) return json({
|
|
12308
12836
|
error: "Could not derive vendor slug"
|
|
@@ -12323,19 +12851,19 @@ function createVendorOnboardHandlers(config) {
|
|
|
12323
12851
|
if (dupVendor) throw new Error("VENDOR_SLUG_EXISTS");
|
|
12324
12852
|
let ownerGroup = await groupRepo.findOne({
|
|
12325
12853
|
where: {
|
|
12326
|
-
name:
|
|
12854
|
+
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
12327
12855
|
deleted: false
|
|
12328
12856
|
}
|
|
12329
12857
|
});
|
|
12330
12858
|
if (!ownerGroup) {
|
|
12331
12859
|
try {
|
|
12332
12860
|
await groupRepo.save(groupRepo.create({
|
|
12333
|
-
name:
|
|
12861
|
+
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
12334
12862
|
deleted: false
|
|
12335
12863
|
}));
|
|
12336
12864
|
ownerGroup = await groupRepo.findOne({
|
|
12337
12865
|
where: {
|
|
12338
|
-
name:
|
|
12866
|
+
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
12339
12867
|
deleted: false
|
|
12340
12868
|
}
|
|
12341
12869
|
});
|
|
@@ -12359,7 +12887,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12359
12887
|
email: userEmail,
|
|
12360
12888
|
phone: ownerPhone,
|
|
12361
12889
|
password: ownerPasswordHash,
|
|
12362
|
-
blocked:
|
|
12890
|
+
blocked: true,
|
|
12363
12891
|
groupId: ownerGroup.id,
|
|
12364
12892
|
adminAccess: true,
|
|
12365
12893
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -12376,15 +12904,14 @@ function createVendorOnboardHandlers(config) {
|
|
|
12376
12904
|
email: userEmail,
|
|
12377
12905
|
phone: ownerPhone,
|
|
12378
12906
|
password: ownerPasswordHash,
|
|
12379
|
-
blocked:
|
|
12907
|
+
blocked: true,
|
|
12380
12908
|
groupId: ownerGroup.id,
|
|
12381
12909
|
adminAccess: true
|
|
12382
12910
|
}));
|
|
12383
|
-
const
|
|
12911
|
+
const metadata = applyRotatingVendorInvite(buildVendorMetadata(null, {
|
|
12384
12912
|
ownerDesignation,
|
|
12385
12913
|
termsAccepted: true
|
|
12386
|
-
});
|
|
12387
|
-
const metadata = activation === "invite" ? applyRotatingVendorInvite(baseMetadata) : baseMetadata;
|
|
12914
|
+
}));
|
|
12388
12915
|
const vendor = await vendorRepo.save(vendorRepo.create({
|
|
12389
12916
|
name: vendorName,
|
|
12390
12917
|
slug,
|
|
@@ -12452,39 +12979,14 @@ function createVendorOnboardHandlers(config) {
|
|
|
12452
12979
|
};
|
|
12453
12980
|
});
|
|
12454
12981
|
let inviteLink;
|
|
12455
|
-
|
|
12456
|
-
if (
|
|
12457
|
-
|
|
12458
|
-
if (token) {
|
|
12459
|
-
inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
12460
|
-
}
|
|
12461
|
-
}
|
|
12462
|
-
if (sendOwnerEmail) {
|
|
12463
|
-
emailSent = await trySendVendorOnboardEmails({
|
|
12464
|
-
vendorName,
|
|
12465
|
-
vendorSlug: slug,
|
|
12466
|
-
ownerName: userName,
|
|
12467
|
-
ownerEmail: userEmail,
|
|
12468
|
-
activation,
|
|
12469
|
-
inviteLink,
|
|
12470
|
-
sendToOwner: true
|
|
12471
|
-
});
|
|
12472
|
-
} else if (getCms) {
|
|
12473
|
-
await trySendVendorOnboardEmails({
|
|
12474
|
-
vendorName,
|
|
12475
|
-
vendorSlug: slug,
|
|
12476
|
-
ownerName: userName,
|
|
12477
|
-
ownerEmail: userEmail,
|
|
12478
|
-
activation,
|
|
12479
|
-
inviteLink,
|
|
12480
|
-
sendToOwner: false
|
|
12481
|
-
});
|
|
12982
|
+
const token = readVendorInviteToken(result.vendor.metadata);
|
|
12983
|
+
if (token) {
|
|
12984
|
+
inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
12482
12985
|
}
|
|
12483
|
-
const message = activation === "password" ? emailSent ? "Vendor onboarded successfully. Welcome email sent to the owner." : sendOwnerEmail ? "Vendor onboarded successfully. Owner can sign in with the password you set (welcome email may not have been sent \u2014 check email plugin)." : "Vendor onboarded successfully. Owner can sign in with the password you set." : emailSent ? "Vendor onboarded successfully. Invite email sent." : sendOwnerEmail ? "Vendor onboarded successfully. Invite link created (email may not have been sent \u2014 check email plugin)." : "Vendor onboarded successfully. Share the invite link with the owner.";
|
|
12484
12986
|
return json({
|
|
12485
|
-
message,
|
|
12987
|
+
message: "Vendor created successfully.",
|
|
12486
12988
|
activation,
|
|
12487
|
-
emailSent,
|
|
12989
|
+
emailSent: false,
|
|
12488
12990
|
vendor: result.vendor,
|
|
12489
12991
|
user: {
|
|
12490
12992
|
id: result.user.id,
|
|
@@ -12519,9 +13021,11 @@ function createVendorOnboardHandlers(config) {
|
|
|
12519
13021
|
});
|
|
12520
13022
|
}
|
|
12521
13023
|
let sendEmail = true;
|
|
13024
|
+
let rotate = true;
|
|
12522
13025
|
try {
|
|
12523
13026
|
const body = await req.json().catch(() => ({}));
|
|
12524
13027
|
if (body.sendEmail === false) sendEmail = false;
|
|
13028
|
+
if (body.rotate === false) rotate = false;
|
|
12525
13029
|
} catch {
|
|
12526
13030
|
}
|
|
12527
13031
|
try {
|
|
@@ -12587,12 +13091,16 @@ function createVendorOnboardHandlers(config) {
|
|
|
12587
13091
|
status: 400
|
|
12588
13092
|
});
|
|
12589
13093
|
}
|
|
12590
|
-
const
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
|
|
12594
|
-
|
|
12595
|
-
|
|
13094
|
+
const nextMetadata = rotate ? applyRotatingVendorInvite(v.metadata) : {
|
|
13095
|
+
...v.metadata ?? {}
|
|
13096
|
+
};
|
|
13097
|
+
if (rotate || v.inviteStatus !== "pending") {
|
|
13098
|
+
await vendorRepo.update(vendorId, {
|
|
13099
|
+
metadata: nextMetadata,
|
|
13100
|
+
inviteStatus: "pending"
|
|
13101
|
+
});
|
|
13102
|
+
}
|
|
13103
|
+
const token = readVendorInviteToken(nextMetadata);
|
|
12596
13104
|
if (!token) {
|
|
12597
13105
|
return json({
|
|
12598
13106
|
error: "Failed to generate invite token"
|
|
@@ -12613,8 +13121,9 @@ function createVendorOnboardHandlers(config) {
|
|
|
12613
13121
|
sendToOwner: true
|
|
12614
13122
|
});
|
|
12615
13123
|
}
|
|
13124
|
+
const rotatedNote = rotate ? " Previous invite link is no longer valid." : "";
|
|
12616
13125
|
return json({
|
|
12617
|
-
message: emailSent ?
|
|
13126
|
+
message: emailSent ? `Invite email sent.${rotatedNote}` : sendEmail ? `Invite link ready (email may not have been sent \u2014 check email plugin).${rotatedNote}` : rotate ? "New invite link created. Previous invite link is no longer valid." : "Invite link ready.",
|
|
12618
13127
|
emailSent,
|
|
12619
13128
|
inviteLink,
|
|
12620
13129
|
inviteStatus: "pending"
|
|
@@ -12814,7 +13323,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12814
13323
|
if (!groupId) {
|
|
12815
13324
|
const g = await groupRepo.findOne({
|
|
12816
13325
|
where: {
|
|
12817
|
-
name:
|
|
13326
|
+
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
12818
13327
|
deleted: false
|
|
12819
13328
|
}
|
|
12820
13329
|
});
|
|
@@ -13124,10 +13633,10 @@ chunkUSNT2KNT_cjs.__name(createVendorOnboardHandlers, "createVendorOnboardHandle
|
|
|
13124
13633
|
function createVendorRolesHandlers(config) {
|
|
13125
13634
|
const { dataSource, entityMap, json, getSessionUser } = config;
|
|
13126
13635
|
const vendorRoleEntities = [
|
|
13127
|
-
...
|
|
13636
|
+
...chunkX6UQFV4X_cjs.VENDOR_RBAC_ENTITIES
|
|
13128
13637
|
].sort();
|
|
13129
13638
|
async function resolveActiveVendorId(u) {
|
|
13130
|
-
const scope =
|
|
13639
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u);
|
|
13131
13640
|
if (scope.type === "vendor") return scope.vendorId;
|
|
13132
13641
|
if (scope.type === "all") {
|
|
13133
13642
|
const id = u.activeVendorId ?? u.vendorIds?.[0];
|
|
@@ -13143,7 +13652,7 @@ function createVendorRolesHandlers(config) {
|
|
|
13143
13652
|
}, {
|
|
13144
13653
|
status: 401
|
|
13145
13654
|
});
|
|
13146
|
-
if (!
|
|
13655
|
+
if (!chunkX6UQFV4X_cjs.canManageVendorRoles(u)) return json({
|
|
13147
13656
|
error: "Forbidden"
|
|
13148
13657
|
}, {
|
|
13149
13658
|
status: 403
|
|
@@ -17082,6 +17591,7 @@ exports.Brand = class Brand {
|
|
|
17082
17591
|
chunkUSNT2KNT_cjs.__name(this, "Brand");
|
|
17083
17592
|
}
|
|
17084
17593
|
id;
|
|
17594
|
+
/** Null for platform catalog brands (`isCatalog`). */
|
|
17085
17595
|
vendorId;
|
|
17086
17596
|
name;
|
|
17087
17597
|
slug;
|
|
@@ -17089,6 +17599,8 @@ exports.Brand = class Brand {
|
|
|
17089
17599
|
metadata;
|
|
17090
17600
|
description;
|
|
17091
17601
|
active;
|
|
17602
|
+
/** Platform-wide catalog brand — vendors pick these on products unless allowed to create their own. */
|
|
17603
|
+
isCatalog;
|
|
17092
17604
|
sortOrder;
|
|
17093
17605
|
createdAt;
|
|
17094
17606
|
updatedAt;
|
|
@@ -17108,8 +17620,10 @@ _ts_decorate30([
|
|
|
17108
17620
|
_ts_metadata30("design:type", Number)
|
|
17109
17621
|
], exports.Brand.prototype, "id", void 0);
|
|
17110
17622
|
_ts_decorate30([
|
|
17111
|
-
typeorm.Column("int"
|
|
17112
|
-
|
|
17623
|
+
typeorm.Column("int", {
|
|
17624
|
+
nullable: true
|
|
17625
|
+
}),
|
|
17626
|
+
_ts_metadata30("design:type", Object)
|
|
17113
17627
|
], exports.Brand.prototype, "vendorId", void 0);
|
|
17114
17628
|
_ts_decorate30([
|
|
17115
17629
|
typeorm.Column("varchar"),
|
|
@@ -17143,6 +17657,12 @@ _ts_decorate30([
|
|
|
17143
17657
|
}),
|
|
17144
17658
|
_ts_metadata30("design:type", Boolean)
|
|
17145
17659
|
], exports.Brand.prototype, "active", void 0);
|
|
17660
|
+
_ts_decorate30([
|
|
17661
|
+
typeorm.Column("boolean", {
|
|
17662
|
+
default: false
|
|
17663
|
+
}),
|
|
17664
|
+
_ts_metadata30("design:type", Boolean)
|
|
17665
|
+
], exports.Brand.prototype, "isCatalog", void 0);
|
|
17146
17666
|
_ts_decorate30([
|
|
17147
17667
|
typeorm.Column("int", {
|
|
17148
17668
|
default: 0
|
|
@@ -17202,12 +17722,13 @@ _ts_decorate30([
|
|
|
17202
17722
|
], exports.Brand.prototype, "seoId", void 0);
|
|
17203
17723
|
_ts_decorate30([
|
|
17204
17724
|
typeorm.ManyToOne(() => exports.Vendor, {
|
|
17205
|
-
onDelete: "RESTRICT"
|
|
17725
|
+
onDelete: "RESTRICT",
|
|
17726
|
+
nullable: true
|
|
17206
17727
|
}),
|
|
17207
17728
|
typeorm.JoinColumn({
|
|
17208
17729
|
name: "vendorId"
|
|
17209
17730
|
}),
|
|
17210
|
-
_ts_metadata30("design:type",
|
|
17731
|
+
_ts_metadata30("design:type", Object)
|
|
17211
17732
|
], exports.Brand.prototype, "vendor", void 0);
|
|
17212
17733
|
_ts_decorate30([
|
|
17213
17734
|
typeorm.ManyToOne(() => exports.Seo, {
|
|
@@ -17491,6 +18012,14 @@ exports.Product = class Product {
|
|
|
17491
18012
|
currencyPrices;
|
|
17492
18013
|
quantity;
|
|
17493
18014
|
status;
|
|
18015
|
+
/**
|
|
18016
|
+
* Separate from catalog status. Used when multi_vendor.requireProductApproval is on.
|
|
18017
|
+
* `approved` also forces `status = available` (live).
|
|
18018
|
+
*/
|
|
18019
|
+
approvalStatus;
|
|
18020
|
+
rejectionReason;
|
|
18021
|
+
rejectedAt;
|
|
18022
|
+
rejectedBy;
|
|
17494
18023
|
featured;
|
|
17495
18024
|
metadata;
|
|
17496
18025
|
createdAt;
|
|
@@ -17614,6 +18143,31 @@ _ts_decorate32([
|
|
|
17614
18143
|
}),
|
|
17615
18144
|
_ts_metadata32("design:type", String)
|
|
17616
18145
|
], exports.Product.prototype, "status", void 0);
|
|
18146
|
+
_ts_decorate32([
|
|
18147
|
+
typeorm.Column("varchar", {
|
|
18148
|
+
nullable: true
|
|
18149
|
+
}),
|
|
18150
|
+
_ts_metadata32("design:type", Object)
|
|
18151
|
+
], exports.Product.prototype, "approvalStatus", void 0);
|
|
18152
|
+
_ts_decorate32([
|
|
18153
|
+
typeorm.Column("text", {
|
|
18154
|
+
nullable: true
|
|
18155
|
+
}),
|
|
18156
|
+
_ts_metadata32("design:type", Object)
|
|
18157
|
+
], exports.Product.prototype, "rejectionReason", void 0);
|
|
18158
|
+
_ts_decorate32([
|
|
18159
|
+
typeorm.Column({
|
|
18160
|
+
type: "timestamptz",
|
|
18161
|
+
nullable: true
|
|
18162
|
+
}),
|
|
18163
|
+
_ts_metadata32("design:type", Object)
|
|
18164
|
+
], exports.Product.prototype, "rejectedAt", void 0);
|
|
18165
|
+
_ts_decorate32([
|
|
18166
|
+
typeorm.Column("int", {
|
|
18167
|
+
nullable: true
|
|
18168
|
+
}),
|
|
18169
|
+
_ts_metadata32("design:type", Object)
|
|
18170
|
+
], exports.Product.prototype, "rejectedBy", void 0);
|
|
17617
18171
|
_ts_decorate32([
|
|
17618
18172
|
typeorm.Column("boolean", {
|
|
17619
18173
|
default: false
|
|
@@ -20702,6 +21256,14 @@ exports.Event = class Event {
|
|
|
20702
21256
|
expectedSpeakers;
|
|
20703
21257
|
expectedParticipants;
|
|
20704
21258
|
isActive;
|
|
21259
|
+
/**
|
|
21260
|
+
* Separate from isActive. Used when events.requireEventApproval is on.
|
|
21261
|
+
* `approved` also forces `isActive = true` (live).
|
|
21262
|
+
*/
|
|
21263
|
+
approvalStatus;
|
|
21264
|
+
rejectionReason;
|
|
21265
|
+
rejectedAt;
|
|
21266
|
+
rejectedBy;
|
|
20705
21267
|
comingSoon;
|
|
20706
21268
|
bannerImageUrl;
|
|
20707
21269
|
logoUrl;
|
|
@@ -20796,6 +21358,31 @@ _ts_decorate60([
|
|
|
20796
21358
|
}),
|
|
20797
21359
|
_ts_metadata60("design:type", Boolean)
|
|
20798
21360
|
], exports.Event.prototype, "isActive", void 0);
|
|
21361
|
+
_ts_decorate60([
|
|
21362
|
+
typeorm.Column("varchar", {
|
|
21363
|
+
nullable: true
|
|
21364
|
+
}),
|
|
21365
|
+
_ts_metadata60("design:type", Object)
|
|
21366
|
+
], exports.Event.prototype, "approvalStatus", void 0);
|
|
21367
|
+
_ts_decorate60([
|
|
21368
|
+
typeorm.Column("text", {
|
|
21369
|
+
nullable: true
|
|
21370
|
+
}),
|
|
21371
|
+
_ts_metadata60("design:type", Object)
|
|
21372
|
+
], exports.Event.prototype, "rejectionReason", void 0);
|
|
21373
|
+
_ts_decorate60([
|
|
21374
|
+
typeorm.Column({
|
|
21375
|
+
type: "timestamptz",
|
|
21376
|
+
nullable: true
|
|
21377
|
+
}),
|
|
21378
|
+
_ts_metadata60("design:type", Object)
|
|
21379
|
+
], exports.Event.prototype, "rejectedAt", void 0);
|
|
21380
|
+
_ts_decorate60([
|
|
21381
|
+
typeorm.Column("int", {
|
|
21382
|
+
nullable: true
|
|
21383
|
+
}),
|
|
21384
|
+
_ts_metadata60("design:type", Object)
|
|
21385
|
+
], exports.Event.prototype, "rejectedBy", void 0);
|
|
20799
21386
|
_ts_decorate60([
|
|
20800
21387
|
typeorm.Column("boolean", {
|
|
20801
21388
|
default: false
|
|
@@ -21356,18 +21943,20 @@ _ts_decorate63([
|
|
|
21356
21943
|
], exports.Combo.prototype, "desc", void 0);
|
|
21357
21944
|
_ts_decorate63([
|
|
21358
21945
|
typeorm.Column({
|
|
21359
|
-
type: "integer"
|
|
21946
|
+
type: "integer",
|
|
21947
|
+
nullable: true
|
|
21360
21948
|
}),
|
|
21361
|
-
_ts_metadata63("design:type",
|
|
21949
|
+
_ts_metadata63("design:type", Object)
|
|
21362
21950
|
], exports.Combo.prototype, "eventId", void 0);
|
|
21363
21951
|
_ts_decorate63([
|
|
21364
21952
|
typeorm.ManyToOne(() => exports.Event, {
|
|
21365
|
-
onDelete: "CASCADE"
|
|
21953
|
+
onDelete: "CASCADE",
|
|
21954
|
+
nullable: true
|
|
21366
21955
|
}),
|
|
21367
21956
|
typeorm.JoinColumn({
|
|
21368
21957
|
name: "eventId"
|
|
21369
21958
|
}),
|
|
21370
|
-
_ts_metadata63("design:type",
|
|
21959
|
+
_ts_metadata63("design:type", Object)
|
|
21371
21960
|
], exports.Combo.prototype, "event", void 0);
|
|
21372
21961
|
_ts_decorate63([
|
|
21373
21962
|
typeorm.Column({
|
|
@@ -25627,7 +26216,7 @@ function createCmsApiHandler(config) {
|
|
|
25627
26216
|
] : baseCrudResources;
|
|
25628
26217
|
const requireEntityPermissionEffective = /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async (_req, entity, action) => {
|
|
25629
26218
|
if (!resolveSessionUser) {
|
|
25630
|
-
|
|
26219
|
+
chunkX6UQFV4X_cjs.logRbac("requireEntityPermission: getSessionUser not passed \u2014 vendor store APIs may 403", {
|
|
25631
26220
|
entity,
|
|
25632
26221
|
action,
|
|
25633
26222
|
hint: "Pass getSessionUser: auth.getAuthenticatedUser from createCmsAuthBundle()"
|
|
@@ -25637,7 +26226,7 @@ function createCmsApiHandler(config) {
|
|
|
25637
26226
|
const raw = await resolveSessionUser();
|
|
25638
26227
|
const u = await hydrateVendorSessionUser(dataSource, raw);
|
|
25639
26228
|
if (!u?.email) {
|
|
25640
|
-
|
|
26229
|
+
chunkX6UQFV4X_cjs.logRbac("requireEntityPermission: no session user", {
|
|
25641
26230
|
entity,
|
|
25642
26231
|
action
|
|
25643
26232
|
});
|
|
@@ -25647,13 +26236,13 @@ function createCmsApiHandler(config) {
|
|
|
25647
26236
|
status: 401
|
|
25648
26237
|
});
|
|
25649
26238
|
}
|
|
25650
|
-
const allowed =
|
|
25651
|
-
await
|
|
26239
|
+
const allowed = chunkZMRQ72F6_cjs.sessionHasEntityAccess(u, entity, action);
|
|
26240
|
+
await chunkX6UQFV4X_cjs.logEntityAccessDecision(dataSource, "cmsApi.requireEntityPermission", u, entity, action, {
|
|
25652
26241
|
allowed,
|
|
25653
26242
|
resolvePath: "hydrated_session"
|
|
25654
26243
|
});
|
|
25655
26244
|
if (allowed) return null;
|
|
25656
|
-
const { reason } =
|
|
26245
|
+
const { reason } = chunkX6UQFV4X_cjs.explainSessionEntityAccess(u, entity, action);
|
|
25657
26246
|
return config.json({
|
|
25658
26247
|
error: "Forbidden",
|
|
25659
26248
|
entity,
|
|
@@ -25664,7 +26253,7 @@ function createCmsApiHandler(config) {
|
|
|
25664
26253
|
});
|
|
25665
26254
|
}
|
|
25666
26255
|
if (userRequireEntityPermission) {
|
|
25667
|
-
|
|
26256
|
+
chunkX6UQFV4X_cjs.logRbac("requireEntityPermission: using app callback only (no getSessionUser)", {
|
|
25668
26257
|
entity,
|
|
25669
26258
|
action
|
|
25670
26259
|
});
|
|
@@ -25751,10 +26340,10 @@ function createCmsApiHandler(config) {
|
|
|
25751
26340
|
getVendorScope: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => {
|
|
25752
26341
|
const multiVendorEnabled = await checkMultiVendorEnabled(dataSource);
|
|
25753
26342
|
if (!multiVendorEnabled) {
|
|
25754
|
-
return
|
|
26343
|
+
return chunkX6UQFV4X_cjs.resolveDisabledMultiVendorScope(dataSource);
|
|
25755
26344
|
}
|
|
25756
26345
|
const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
|
|
25757
|
-
return
|
|
26346
|
+
return chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u ?? null);
|
|
25758
26347
|
}, "getVendorScope"),
|
|
25759
26348
|
getHydratedSessionUser: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => {
|
|
25760
26349
|
const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
|
|
@@ -26680,16 +27269,24 @@ function createCmsApiHandler(config) {
|
|
|
26680
27269
|
if (pe) return pe;
|
|
26681
27270
|
if (group === "multi_vendor") {
|
|
26682
27271
|
invalidateMultiVendorCache();
|
|
27272
|
+
invalidateVendorCatalogCreateFlagsCache();
|
|
27273
|
+
invalidateRequireProductApprovalCache();
|
|
27274
|
+
invalidateRequireEventApprovalCache();
|
|
26683
27275
|
}
|
|
26684
27276
|
if (group === "events") {
|
|
26685
27277
|
invalidateEventsCache();
|
|
27278
|
+
invalidateRequireEventApprovalCache();
|
|
26686
27279
|
}
|
|
26687
27280
|
const res = await settingsHandlers.PUT(req, group);
|
|
26688
27281
|
if (group === "multi_vendor") {
|
|
26689
27282
|
invalidateMultiVendorCache();
|
|
27283
|
+
invalidateVendorCatalogCreateFlagsCache();
|
|
27284
|
+
invalidateRequireProductApprovalCache();
|
|
27285
|
+
invalidateRequireEventApprovalCache();
|
|
26690
27286
|
}
|
|
26691
27287
|
if (group === "events") {
|
|
26692
27288
|
invalidateEventsCache();
|
|
27289
|
+
invalidateRequireEventApprovalCache();
|
|
26693
27290
|
}
|
|
26694
27291
|
return res;
|
|
26695
27292
|
}
|
|
@@ -27013,7 +27610,7 @@ function createCmsApiHandler(config) {
|
|
|
27013
27610
|
let vendorId = null;
|
|
27014
27611
|
if (resolveSessionUser) {
|
|
27015
27612
|
const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
|
|
27016
|
-
const scope =
|
|
27613
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u ?? null);
|
|
27017
27614
|
if (scope.type === "vendor") vendorId = scope.vendorId;
|
|
27018
27615
|
}
|
|
27019
27616
|
const result = await validateCoupon(dataSource, entityMap, couponCode, orderLinesNorm, currency, contactId, isAutomatic, discountId ?? void 0, vendorId);
|
|
@@ -27093,7 +27690,7 @@ function createCmsApiHandler(config) {
|
|
|
27093
27690
|
let vendorId = null;
|
|
27094
27691
|
if (resolveSessionUser) {
|
|
27095
27692
|
const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
|
|
27096
|
-
const scope =
|
|
27693
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u ?? null);
|
|
27097
27694
|
if (scope.type === "vendor") vendorId = scope.vendorId;
|
|
27098
27695
|
}
|
|
27099
27696
|
const orderLinesNorm = normalizeOrderLinesInput(body?.orderLines);
|
|
@@ -27707,7 +28304,7 @@ function createCmsApiHandler(config) {
|
|
|
27707
28304
|
if (resolveSessionUser) {
|
|
27708
28305
|
const raw = await resolveSessionUser();
|
|
27709
28306
|
const u = await hydrateVendorSessionUser(dataSource, raw);
|
|
27710
|
-
const scope =
|
|
28307
|
+
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u ?? null);
|
|
27711
28308
|
if (scope.type === "vendor") {
|
|
27712
28309
|
scopedVendorIds = scope.vendorIds;
|
|
27713
28310
|
}
|
|
@@ -31006,10 +31603,16 @@ exports.BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG = BLOG_METADATA_ENRICHER_LLM_AGENT
|
|
|
31006
31603
|
exports.BlogGeneratorService = BlogGeneratorService;
|
|
31007
31604
|
exports.CMS_ENTITY_MAP = CMS_ENTITY_MAP;
|
|
31008
31605
|
exports.ZIP_MIME_TYPES = ZIP_MIME_TYPES;
|
|
31606
|
+
exports.applyApprovalStatusSideEffects = applyApprovalStatusSideEffects;
|
|
31607
|
+
exports.applyEventApprovalStatusSideEffects = applyEventApprovalStatusSideEffects;
|
|
31009
31608
|
exports.applyRotatingVendorInvite = applyRotatingVendorInvite;
|
|
31010
31609
|
exports.applyVendorCustomersContactFilter = applyVendorCustomersContactFilter;
|
|
31610
|
+
exports.applyVendorEventCreateApproval = applyVendorEventCreateApproval;
|
|
31611
|
+
exports.applyVendorProductCreateApproval = applyVendorProductCreateApproval;
|
|
31011
31612
|
exports.assertCaptchaOk = assertCaptchaOk;
|
|
31012
31613
|
exports.assertContactAllowedForVendorOrder = assertContactAllowedForVendorOrder;
|
|
31614
|
+
exports.assertEventApprovalUpdate = assertEventApprovalUpdate;
|
|
31615
|
+
exports.assertProductApprovalUpdate = assertProductApprovalUpdate;
|
|
31013
31616
|
exports.buildBlogMetadataUserPrompt = buildBlogMetadataUserPrompt;
|
|
31014
31617
|
exports.buildCronFromSchedule = buildCronFromSchedule;
|
|
31015
31618
|
exports.buildRssUserPromptFromFeeds = buildRssUserPromptFromFeeds;
|
|
@@ -31062,11 +31665,17 @@ exports.findVendorByInviteToken = findVendorByInviteToken;
|
|
|
31062
31665
|
exports.formatTierRange = formatTierRange;
|
|
31063
31666
|
exports.generateNumericOtp = generateNumericOtp;
|
|
31064
31667
|
exports.getPublicSettingsGroup = getPublicSettingsGroup;
|
|
31668
|
+
exports.getRequireEventApproval = getRequireEventApproval;
|
|
31669
|
+
exports.getRequireProductApproval = getRequireProductApproval;
|
|
31065
31670
|
exports.getRssArticleSummaryFromItem = getRssArticleSummaryFromItem;
|
|
31671
|
+
exports.getVendorCatalogCreateFlags = getVendorCatalogCreateFlags;
|
|
31066
31672
|
exports.hashOtpCode = hashOtpCode;
|
|
31067
31673
|
exports.hydrateVendorSessionUser = hydrateVendorSessionUser;
|
|
31068
31674
|
exports.invalidateEventsCache = invalidateEventsCache;
|
|
31069
31675
|
exports.invalidateMultiVendorCache = invalidateMultiVendorCache;
|
|
31676
|
+
exports.invalidateRequireEventApprovalCache = invalidateRequireEventApprovalCache;
|
|
31677
|
+
exports.invalidateRequireProductApprovalCache = invalidateRequireProductApprovalCache;
|
|
31678
|
+
exports.invalidateVendorCatalogCreateFlagsCache = invalidateVendorCatalogCreateFlagsCache;
|
|
31070
31679
|
exports.isCustomerTypeContact = isCustomerTypeContact;
|
|
31071
31680
|
exports.isZipMedia = isZipMedia;
|
|
31072
31681
|
exports.linkUnclaimedContactToUser = linkUnclaimedContactToUser;
|