@infuro/cms-core 1.0.16 → 1.0.19
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 +739 -724
- package/dist/admin.cjs +1 -1
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.js +1 -1
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +132 -57
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.js +132 -57
- package/dist/api.js.map +1 -1
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.js.map +1 -1
- package/dist/cli.cjs +21 -6
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +21 -6
- package/dist/cli.js.map +1 -1
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.js.map +1 -1
- package/dist/{index-h42MoUNq.d.cts → index-D2C1O9b4.d.cts} +8 -1
- package/dist/{index-C85X7cc7.d.ts → index-GMn7-9PX.d.ts} +8 -1
- package/dist/index.cjs +139 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +139 -57
- package/dist/index.js.map +1 -1
- package/dist/migrations/1772178563554-InitialSchema.ts +304 -304
- package/dist/migrations/1772178563555-ChatAndKnowledgeBase.ts +55 -55
- package/dist/migrations/1772178563556-KnowledgeBaseVector.ts +16 -16
- package/dist/migrations/1774300000000-RbacSeedGroupsAndPermissionUnique.ts +24 -24
- package/dist/migrations/1774300000001-SeedAdministratorUsersPermission.ts +35 -35
- package/dist/migrations/1774400000000-CustomerAdminAccessContactUser.ts +37 -37
- package/dist/migrations/1774400000001-StorefrontCartWishlist.ts +100 -100
- package/dist/migrations/1774400000002-WishlistGuestId.ts +29 -29
- package/dist/migrations/1774500000000-ProductCollectionHsn.ts +15 -15
- package/dist/migrations/1774600000000-OrderKindParentOrderNumber.ts +36 -36
- package/dist/migrations/1774700000000-CollectionVariants.ts +13 -0
- package/dist/migrations/1774800000000-OtpChallengesUserPhone.ts +41 -41
- package/dist/migrations/1774900000000-MessageTemplates.ts +39 -39
- package/dist/migrations/1775000000000-ProductUomTypeOrderItemSnapshots.ts +29 -29
- package/dist/migrations/1775200000000-MediaDriveFolders.ts +38 -38
- package/dist/migrations/README.md +3 -3
- package/dist/theme.cjs.map +1 -1
- package/dist/theme.js.map +1 -1
- package/package.json +13 -6
- package/src/admin/admin.css +72 -72
package/dist/api.cjs
CHANGED
|
@@ -569,6 +569,28 @@ function buildSearchWhereClause(repo, search) {
|
|
|
569
569
|
if (ors.length === 0) return {};
|
|
570
570
|
return ors.length === 1 ? ors[0] : ors;
|
|
571
571
|
}
|
|
572
|
+
function entityHasSoftDelete(repo) {
|
|
573
|
+
return repo.metadata.columns.some((c) => c.propertyName === "deleted");
|
|
574
|
+
}
|
|
575
|
+
function mergeDeletedFalseWhere(repo, where) {
|
|
576
|
+
if (!entityHasSoftDelete(repo)) return where;
|
|
577
|
+
const d = { deleted: false };
|
|
578
|
+
if (Array.isArray(where)) {
|
|
579
|
+
if (where.length === 0) return [d];
|
|
580
|
+
return where.map((w) => ({ ...w, ...d }));
|
|
581
|
+
}
|
|
582
|
+
return Object.keys(where).length > 0 ? { ...where, ...d } : d;
|
|
583
|
+
}
|
|
584
|
+
function buildSoftDeletePayload(meta, deletedBy) {
|
|
585
|
+
const payload = { deleted: true };
|
|
586
|
+
if (meta.columns.some((c) => c.propertyName === "deletedAt")) {
|
|
587
|
+
payload.deletedAt = /* @__PURE__ */ new Date();
|
|
588
|
+
}
|
|
589
|
+
if (deletedBy != null && meta.columns.some((c) => c.propertyName === "deletedBy")) {
|
|
590
|
+
payload.deletedBy = deletedBy;
|
|
591
|
+
}
|
|
592
|
+
return payload;
|
|
593
|
+
}
|
|
572
594
|
function makeContactErpSync(dataSource, entityMap, getCms) {
|
|
573
595
|
return async function syncContactRowToErp(row) {
|
|
574
596
|
if (!getCms) return;
|
|
@@ -593,10 +615,11 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
593
615
|
async function authz(req, resource, action) {
|
|
594
616
|
const authError = await requireAuth(req);
|
|
595
617
|
if (authError) return authError;
|
|
596
|
-
if (reqPerm) {
|
|
597
|
-
|
|
598
|
-
if (pe) return pe;
|
|
618
|
+
if (!reqPerm) {
|
|
619
|
+
return json({ error: "Forbidden", reason: "entity_rbac_required", entity: resource, action }, { status: 403 });
|
|
599
620
|
}
|
|
621
|
+
const pe = await reqPerm(req, resource, action);
|
|
622
|
+
if (pe) return pe;
|
|
600
623
|
return null;
|
|
601
624
|
}
|
|
602
625
|
return {
|
|
@@ -632,7 +655,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
632
655
|
return json({ total: 0, page, limit, totalPages: 0, data: [] });
|
|
633
656
|
}
|
|
634
657
|
}
|
|
635
|
-
const qb = repo2.createQueryBuilder("order").leftJoinAndSelect("order.contact", "contact").leftJoinAndSelect("order.items", "items").leftJoinAndSelect("items.product", "product").leftJoinAndSelect("product.collection", "collection").orderBy(`order.${sortField2}`, sortOrderOrders).skip(skip).take(limit);
|
|
658
|
+
const qb = repo2.createQueryBuilder("order").leftJoinAndSelect("order.contact", "contact").leftJoinAndSelect("order.items", "items").leftJoinAndSelect("items.product", "product").leftJoinAndSelect("product.collection", "collection").andWhere("order.deleted = :orderDel", { orderDel: false }).orderBy(`order.${sortField2}`, sortOrderOrders).skip(skip).take(limit);
|
|
636
659
|
if (search && typeof search === "string" && search.trim()) {
|
|
637
660
|
const term = `%${search.trim()}%`;
|
|
638
661
|
qb.andWhere(
|
|
@@ -670,7 +693,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
670
693
|
const dateTo = searchParams.get("dateTo")?.trim();
|
|
671
694
|
const methodFilter = searchParams.get("method")?.trim();
|
|
672
695
|
const orderNumberParam = searchParams.get("orderNumber")?.trim();
|
|
673
|
-
const qb = repo2.createQueryBuilder("payment").leftJoinAndSelect("payment.order", "ord").leftJoinAndSelect("ord.contact", "orderContact").leftJoinAndSelect("payment.contact", "contact").orderBy(`payment.${sortField2}`, sortOrderPayments).skip(skip).take(limit);
|
|
696
|
+
const qb = repo2.createQueryBuilder("payment").leftJoinAndSelect("payment.order", "ord").leftJoinAndSelect("ord.contact", "orderContact").leftJoinAndSelect("payment.contact", "contact").andWhere("payment.deleted = :payDel", { payDel: false }).orderBy(`payment.${sortField2}`, sortOrderPayments).skip(skip).take(limit);
|
|
674
697
|
if (search && typeof search === "string" && search.trim()) {
|
|
675
698
|
const term = `%${search.trim()}%`;
|
|
676
699
|
qb.andWhere(
|
|
@@ -701,7 +724,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
701
724
|
const repo2 = dataSource.getRepository(entity);
|
|
702
725
|
const statusFilter = searchParams.get("status")?.trim();
|
|
703
726
|
const inventory = searchParams.get("inventory")?.trim();
|
|
704
|
-
const productWhere = {};
|
|
727
|
+
const productWhere = { deleted: false };
|
|
705
728
|
if (statusFilter) productWhere.status = statusFilter;
|
|
706
729
|
if (inventory === "in_stock") productWhere.quantity = (0, import_typeorm.MoreThan)(0);
|
|
707
730
|
if (inventory === "out_of_stock") productWhere.quantity = 0;
|
|
@@ -724,7 +747,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
724
747
|
const typeFilter2 = searchParams.get("type")?.trim();
|
|
725
748
|
const orderIdParam = searchParams.get("orderId")?.trim();
|
|
726
749
|
const includeSummary = searchParams.get("includeSummary") === "1";
|
|
727
|
-
const qb = repo2.createQueryBuilder("contact").orderBy(`contact.${sortField2}`, sortOrderContacts).skip(skip).take(limit);
|
|
750
|
+
const qb = repo2.createQueryBuilder("contact").andWhere("contact.deleted = :contactDel", { contactDel: false }).orderBy(`contact.${sortField2}`, sortOrderContacts).skip(skip).take(limit);
|
|
728
751
|
if (search && typeof search === "string" && search.trim()) {
|
|
729
752
|
const term = `%${search.trim()}%`;
|
|
730
753
|
qb.andWhere("(contact.name ILIKE :term OR contact.email ILIKE :term OR contact.phone ILIKE :term)", { term });
|
|
@@ -765,9 +788,9 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
765
788
|
if (parentIdParam != null && parentIdParam !== "") {
|
|
766
789
|
const n = Number(parentIdParam);
|
|
767
790
|
if (!Number.isFinite(n)) return json({ error: "Invalid parentId" }, { status: 400 });
|
|
768
|
-
qb.where("m.parentId = :pid", { pid: n });
|
|
791
|
+
qb.where("m.deleted = :mediaDel AND m.parentId = :pid", { mediaDel: false, pid: n });
|
|
769
792
|
} else {
|
|
770
|
-
qb.where("m.parentId IS NULL");
|
|
793
|
+
qb.where("m.deleted = :mediaDel AND m.parentId IS NULL", { mediaDel: false });
|
|
771
794
|
}
|
|
772
795
|
if (search && typeof search === "string" && search.trim()) {
|
|
773
796
|
qb.andWhere("m.filename ILIKE :search", { search: `%${search.trim()}%` });
|
|
@@ -811,6 +834,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
811
834
|
where = extraWhere;
|
|
812
835
|
}
|
|
813
836
|
}
|
|
837
|
+
where = mergeDeletedFalseWhere(repo, where);
|
|
814
838
|
const [data, total] = await repo.findAndCount({
|
|
815
839
|
skip,
|
|
816
840
|
take: limit,
|
|
@@ -978,15 +1002,16 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
978
1002
|
};
|
|
979
1003
|
}
|
|
980
1004
|
function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
981
|
-
const { requireAuth, json, requireEntityPermission: reqPerm, getCms } = options;
|
|
1005
|
+
const { requireAuth, json, requireEntityPermission: reqPerm, getCms, getDeletedByUserId } = options;
|
|
982
1006
|
const syncContactRowToErp = makeContactErpSync(dataSource, entityMap, getCms);
|
|
983
1007
|
async function authz(req, resource, action) {
|
|
984
1008
|
const authError = await requireAuth(req);
|
|
985
1009
|
if (authError) return authError;
|
|
986
|
-
if (reqPerm) {
|
|
987
|
-
|
|
988
|
-
if (pe) return pe;
|
|
1010
|
+
if (!reqPerm) {
|
|
1011
|
+
return json({ error: "Forbidden", reason: "entity_rbac_required", entity: resource, action }, { status: 403 });
|
|
989
1012
|
}
|
|
1013
|
+
const pe = await reqPerm(req, resource, action);
|
|
1014
|
+
if (pe) return pe;
|
|
990
1015
|
return null;
|
|
991
1016
|
}
|
|
992
1017
|
return {
|
|
@@ -998,7 +1023,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
998
1023
|
const repo = dataSource.getRepository(entity);
|
|
999
1024
|
if (resource === "orders") {
|
|
1000
1025
|
const order = await repo.findOne({
|
|
1001
|
-
where: { id: Number(id) },
|
|
1026
|
+
where: { id: Number(id), deleted: false },
|
|
1002
1027
|
relations: ["contact", "billingAddress", "shippingAddress", "items", "items.product", "items.product.collection", "payments"]
|
|
1003
1028
|
});
|
|
1004
1029
|
if (!order) return json({ message: "Not found" }, { status: 404 });
|
|
@@ -1010,7 +1035,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1010
1035
|
}
|
|
1011
1036
|
if (resource === "contacts") {
|
|
1012
1037
|
const contact = await repo.findOne({
|
|
1013
|
-
where: { id: Number(id) },
|
|
1038
|
+
where: { id: Number(id), deleted: false },
|
|
1014
1039
|
relations: ["form_submissions", "form_submissions.form", "orders", "payments", "addresses"]
|
|
1015
1040
|
});
|
|
1016
1041
|
if (!contact) return json({ message: "Not found" }, { status: 404 });
|
|
@@ -1032,7 +1057,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1032
1057
|
}
|
|
1033
1058
|
if (resource === "payments") {
|
|
1034
1059
|
const payment = await repo.findOne({
|
|
1035
|
-
where: { id: Number(id) },
|
|
1060
|
+
where: { id: Number(id), deleted: false },
|
|
1036
1061
|
relations: ["order", "order.contact", "contact"]
|
|
1037
1062
|
});
|
|
1038
1063
|
if (!payment) return json({ message: "Not found" }, { status: 404 });
|
|
@@ -1040,12 +1065,13 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1040
1065
|
}
|
|
1041
1066
|
if (resource === "blogs") {
|
|
1042
1067
|
const blog = await repo.findOne({
|
|
1043
|
-
where: { id: Number(id) },
|
|
1068
|
+
where: { id: Number(id), deleted: false },
|
|
1044
1069
|
relations: ["category", "seo", "tags"]
|
|
1045
1070
|
});
|
|
1046
1071
|
return blog ? json(blog) : json({ message: "Not found" }, { status: 404 });
|
|
1047
1072
|
}
|
|
1048
|
-
const
|
|
1073
|
+
const idWhere = entityHasSoftDelete(repo) ? { id: Number(id), deleted: false } : { id: Number(id) };
|
|
1074
|
+
const item = await repo.findOne({ where: idWhere });
|
|
1049
1075
|
return item ? json(item) : json({ message: "Not found" }, { status: 404 });
|
|
1050
1076
|
},
|
|
1051
1077
|
async PUT(req, resource, id) {
|
|
@@ -1057,7 +1083,9 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1057
1083
|
const repo = dataSource.getRepository(entity);
|
|
1058
1084
|
const numericId = Number(id);
|
|
1059
1085
|
if (resource === "blogs" && rawBody && typeof rawBody === "object" && entityMap.categories && entityMap.seos && entityMap.tags) {
|
|
1060
|
-
const existing = await repo.findOne({
|
|
1086
|
+
const existing = await repo.findOne({
|
|
1087
|
+
where: { id: numericId, deleted: false }
|
|
1088
|
+
});
|
|
1061
1089
|
if (!existing) return json({ message: "Not found" }, { status: 404 });
|
|
1062
1090
|
const updatePayload2 = pickColumnUpdates(repo, rawBody);
|
|
1063
1091
|
if ("category" in rawBody) {
|
|
@@ -1133,6 +1161,12 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1133
1161
|
});
|
|
1134
1162
|
return updated2 ? json(updated2) : json({ message: "Not found" }, { status: 404 });
|
|
1135
1163
|
}
|
|
1164
|
+
if (entityHasSoftDelete(repo)) {
|
|
1165
|
+
const cur = await repo.findOne({
|
|
1166
|
+
where: { id: numericId, deleted: false }
|
|
1167
|
+
});
|
|
1168
|
+
if (!cur) return json({ message: "Not found" }, { status: 404 });
|
|
1169
|
+
}
|
|
1136
1170
|
const updatePayload = rawBody && typeof rawBody === "object" ? pickColumnUpdates(repo, rawBody) : {};
|
|
1137
1171
|
if (resource === "media") {
|
|
1138
1172
|
const u = updatePayload;
|
|
@@ -1159,7 +1193,24 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1159
1193
|
const entity = entityMap[resource];
|
|
1160
1194
|
if (!entity) return json({ error: "Invalid resource" }, { status: 400 });
|
|
1161
1195
|
const repo = dataSource.getRepository(entity);
|
|
1162
|
-
const
|
|
1196
|
+
const numericId = Number(id);
|
|
1197
|
+
if (entityHasSoftDelete(repo)) {
|
|
1198
|
+
const existing = await repo.findOne({
|
|
1199
|
+
where: { id: numericId, deleted: false }
|
|
1200
|
+
});
|
|
1201
|
+
if (!existing) return json({ message: "Not found" }, { status: 404 });
|
|
1202
|
+
let deletedBy = null;
|
|
1203
|
+
if (getDeletedByUserId) {
|
|
1204
|
+
try {
|
|
1205
|
+
deletedBy = await getDeletedByUserId(req);
|
|
1206
|
+
} catch {
|
|
1207
|
+
deletedBy = null;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
await repo.update(numericId, buildSoftDeletePayload(repo.metadata, deletedBy));
|
|
1211
|
+
return json({ message: "Deleted successfully" }, { status: 200 });
|
|
1212
|
+
}
|
|
1213
|
+
const result = await repo.delete(numericId);
|
|
1163
1214
|
if (result.affected === 0) return json({ message: "Not found" }, { status: 404 });
|
|
1164
1215
|
return json({ message: "Deleted successfully" }, { status: 200 });
|
|
1165
1216
|
}
|
|
@@ -2267,7 +2318,7 @@ function createFormSubmissionHandler(config) {
|
|
|
2267
2318
|
};
|
|
2268
2319
|
}
|
|
2269
2320
|
function createUsersApiHandlers(config) {
|
|
2270
|
-
const { dataSource, entityMap, json, requireAuth, requireEntityPermission, baseUrl, getCms, getCompanyDetails } = config;
|
|
2321
|
+
const { dataSource, entityMap, json, requireAuth, requireEntityPermission, baseUrl, getCms, getCompanyDetails, getSessionUser } = config;
|
|
2271
2322
|
async function trySendInviteEmail(toEmail, inviteLink, inviteeName) {
|
|
2272
2323
|
if (!getCms) return;
|
|
2273
2324
|
try {
|
|
@@ -2303,7 +2354,10 @@ function createUsersApiHandlers(config) {
|
|
|
2303
2354
|
const sortField = url.searchParams.get("sortField") || "createdAt";
|
|
2304
2355
|
const sortOrder = url.searchParams.get("sortOrder") === "desc" ? "DESC" : "ASC";
|
|
2305
2356
|
const search = url.searchParams.get("search");
|
|
2306
|
-
const where = search ? [
|
|
2357
|
+
const where = search ? [
|
|
2358
|
+
{ name: (0, import_typeorm4.ILike)(`%${search}%`), deleted: false },
|
|
2359
|
+
{ email: (0, import_typeorm4.ILike)(`%${search}%`), deleted: false }
|
|
2360
|
+
] : { deleted: false };
|
|
2307
2361
|
const [data, total] = await userRepo().findAndCount({
|
|
2308
2362
|
skip,
|
|
2309
2363
|
take: limit,
|
|
@@ -2368,7 +2422,7 @@ function createUsersApiHandlers(config) {
|
|
|
2368
2422
|
}
|
|
2369
2423
|
try {
|
|
2370
2424
|
const user = await userRepo().findOne({
|
|
2371
|
-
where: { id: parseInt(id, 10) },
|
|
2425
|
+
where: { id: parseInt(id, 10), deleted: false },
|
|
2372
2426
|
relations: ["group"],
|
|
2373
2427
|
select: ["id", "name", "email", "blocked", "createdAt", "updatedAt", "groupId"]
|
|
2374
2428
|
});
|
|
@@ -2386,11 +2440,14 @@ function createUsersApiHandlers(config) {
|
|
|
2386
2440
|
if (pe) return pe;
|
|
2387
2441
|
}
|
|
2388
2442
|
try {
|
|
2443
|
+
const uid = parseInt(id, 10);
|
|
2444
|
+
const existing = await userRepo().findOne({ where: { id: uid, deleted: false } });
|
|
2445
|
+
if (!existing) return json({ error: "Not found" }, { status: 404 });
|
|
2389
2446
|
const body = await req.json();
|
|
2390
2447
|
const { password: _p, ...safe } = body;
|
|
2391
|
-
await userRepo().update(
|
|
2448
|
+
await userRepo().update(uid, safe);
|
|
2392
2449
|
const updated = await userRepo().findOne({
|
|
2393
|
-
where: { id:
|
|
2450
|
+
where: { id: uid, deleted: false },
|
|
2394
2451
|
relations: ["group"],
|
|
2395
2452
|
select: ["id", "name", "email", "blocked", "createdAt", "updatedAt", "groupId"]
|
|
2396
2453
|
});
|
|
@@ -2407,8 +2464,23 @@ function createUsersApiHandlers(config) {
|
|
|
2407
2464
|
if (pe) return pe;
|
|
2408
2465
|
}
|
|
2409
2466
|
try {
|
|
2410
|
-
const
|
|
2411
|
-
|
|
2467
|
+
const uid = parseInt(id, 10);
|
|
2468
|
+
const existing = await userRepo().findOne({ where: { id: uid, deleted: false } });
|
|
2469
|
+
if (!existing) return json({ error: "User not found" }, { status: 404 });
|
|
2470
|
+
let deletedBy = null;
|
|
2471
|
+
if (getSessionUser) {
|
|
2472
|
+
try {
|
|
2473
|
+
const u = await getSessionUser();
|
|
2474
|
+
if (u?.id) {
|
|
2475
|
+
const n = Number(u.id);
|
|
2476
|
+
if (Number.isFinite(n)) deletedBy = n;
|
|
2477
|
+
}
|
|
2478
|
+
} catch {
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
const payload = { deleted: true, deletedAt: /* @__PURE__ */ new Date() };
|
|
2482
|
+
if (deletedBy != null) payload.deletedBy = deletedBy;
|
|
2483
|
+
await userRepo().update(uid, payload);
|
|
2412
2484
|
return json({ message: "User deleted successfully" });
|
|
2413
2485
|
} catch {
|
|
2414
2486
|
return json({ error: "Server Error" }, { status: 500 });
|
|
@@ -2422,7 +2494,10 @@ function createUsersApiHandlers(config) {
|
|
|
2422
2494
|
if (pe) return pe;
|
|
2423
2495
|
}
|
|
2424
2496
|
try {
|
|
2425
|
-
const user = await userRepo().findOne({
|
|
2497
|
+
const user = await userRepo().findOne({
|
|
2498
|
+
where: { id: parseInt(id, 10), deleted: false },
|
|
2499
|
+
select: ["email", "name"]
|
|
2500
|
+
});
|
|
2426
2501
|
if (!user) return json({ error: "User not found" }, { status: 404 });
|
|
2427
2502
|
const emailToken = Buffer.from(user.email).toString("base64");
|
|
2428
2503
|
const inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;
|
|
@@ -3045,9 +3120,10 @@ function createCmsApiHandler(config) {
|
|
|
3045
3120
|
userProfile,
|
|
3046
3121
|
settings: settingsConfig,
|
|
3047
3122
|
chat: chatConfig,
|
|
3048
|
-
requireEntityPermission:
|
|
3123
|
+
requireEntityPermission: userRequireEntityPermission,
|
|
3049
3124
|
getSessionUser
|
|
3050
3125
|
} = config;
|
|
3126
|
+
const requireEntityPermissionEffective = userRequireEntityPermission ?? (async (_req, entity, action) => config.json({ error: "Forbidden", reason: "entity_rbac_required", entity, action }, { status: 403 }));
|
|
3051
3127
|
const analytics = analyticsConfig ?? (getCms ? {
|
|
3052
3128
|
json: config.json,
|
|
3053
3129
|
requireAuth: async () => null,
|
|
@@ -3085,12 +3161,20 @@ function createCmsApiHandler(config) {
|
|
|
3085
3161
|
const crudOpts = {
|
|
3086
3162
|
requireAuth: config.requireAuth,
|
|
3087
3163
|
json: config.json,
|
|
3088
|
-
requireEntityPermission:
|
|
3089
|
-
getCms
|
|
3164
|
+
requireEntityPermission: requireEntityPermissionEffective,
|
|
3165
|
+
getCms,
|
|
3166
|
+
...getSessionUser ? {
|
|
3167
|
+
getDeletedByUserId: async () => {
|
|
3168
|
+
const u = await getSessionUser();
|
|
3169
|
+
if (!u?.id) return null;
|
|
3170
|
+
const n = Number(u.id);
|
|
3171
|
+
return Number.isFinite(n) ? n : null;
|
|
3172
|
+
}
|
|
3173
|
+
} : {}
|
|
3090
3174
|
};
|
|
3091
3175
|
const crud = createCrudHandler(dataSource, entityMap, crudOpts);
|
|
3092
3176
|
const crudById = createCrudByIdHandler(dataSource, entityMap, crudOpts);
|
|
3093
|
-
const mergePerm = (c) => !c ? void 0 :
|
|
3177
|
+
const mergePerm = (c) => !c ? void 0 : { ...c, requireEntityPermission: requireEntityPermissionEffective };
|
|
3094
3178
|
const adminRoles = getSessionUser && createAdminRolesHandlers({
|
|
3095
3179
|
dataSource,
|
|
3096
3180
|
entityMap,
|
|
@@ -3106,12 +3190,7 @@ function createCmsApiHandler(config) {
|
|
|
3106
3190
|
json: config.json,
|
|
3107
3191
|
requireAuth: config.requireAuth
|
|
3108
3192
|
}
|
|
3109
|
-
)
|
|
3110
|
-
dataSource,
|
|
3111
|
-
entityMap,
|
|
3112
|
-
json: config.json,
|
|
3113
|
-
requireAuth: config.requireAuth
|
|
3114
|
-
};
|
|
3193
|
+
);
|
|
3115
3194
|
const ecommerceAnalyticsGet = createEcommerceAnalyticsHandler(ecommerceAnalyticsResolved);
|
|
3116
3195
|
const analyticsHandlers = analytics ? createAnalyticsHandlers(analytics) : null;
|
|
3117
3196
|
const uploadMerged = upload ? {
|
|
@@ -3130,7 +3209,11 @@ function createCmsApiHandler(config) {
|
|
|
3130
3209
|
const usersApiMerged = usersApi && getCms ? {
|
|
3131
3210
|
...usersApi,
|
|
3132
3211
|
getCms: usersApi.getCms ?? getCms,
|
|
3133
|
-
getCompanyDetails: usersApi.getCompanyDetails ?? config.getCompanyDetails
|
|
3212
|
+
getCompanyDetails: usersApi.getCompanyDetails ?? config.getCompanyDetails,
|
|
3213
|
+
...getSessionUser ? { getSessionUser: usersApi.getSessionUser ?? getSessionUser } : {}
|
|
3214
|
+
} : usersApi ? {
|
|
3215
|
+
...usersApi,
|
|
3216
|
+
...getSessionUser ? { getSessionUser: usersApi.getSessionUser ?? getSessionUser } : {}
|
|
3134
3217
|
} : usersApi;
|
|
3135
3218
|
const usersHandlers = usersApiMerged ? createUsersApiHandlers(mergePerm(usersApiMerged) ?? usersApiMerged) : null;
|
|
3136
3219
|
const avatarPost = userAvatar ? createUserAvatarHandler(userAvatar) : null;
|
|
@@ -3141,7 +3224,7 @@ function createCmsApiHandler(config) {
|
|
|
3141
3224
|
entityMap,
|
|
3142
3225
|
json: config.json,
|
|
3143
3226
|
requireAuth: config.requireAuth,
|
|
3144
|
-
requireEntityPermission:
|
|
3227
|
+
requireEntityPermission: requireEntityPermissionEffective
|
|
3145
3228
|
});
|
|
3146
3229
|
const chatHandlers = chatConfig ? createChatHandlers(chatConfig) : null;
|
|
3147
3230
|
function resolveResource(segment) {
|
|
@@ -3150,12 +3233,10 @@ function createCmsApiHandler(config) {
|
|
|
3150
3233
|
}
|
|
3151
3234
|
return {
|
|
3152
3235
|
async handle(method, path, req) {
|
|
3153
|
-
const perm = reqEntityPerm;
|
|
3154
3236
|
async function analyticsGate() {
|
|
3155
3237
|
const a = await config.requireAuth(req);
|
|
3156
3238
|
if (a) return a;
|
|
3157
|
-
|
|
3158
|
-
return null;
|
|
3239
|
+
return requireEntityPermissionEffective(req, "analytics", "read");
|
|
3159
3240
|
}
|
|
3160
3241
|
if (path[0] === "admin" && path[1] === "roles") {
|
|
3161
3242
|
if (!adminRoles) return config.json({ error: "Not found" }, { status: 404 });
|
|
@@ -3239,19 +3320,17 @@ function createCmsApiHandler(config) {
|
|
|
3239
3320
|
const group = path[1];
|
|
3240
3321
|
const isPublic = settingsConfig?.publicGetGroups?.includes(group);
|
|
3241
3322
|
if (method === "GET") {
|
|
3242
|
-
if (!isPublic
|
|
3323
|
+
if (!isPublic) {
|
|
3243
3324
|
const a = await config.requireAuth(req);
|
|
3244
3325
|
if (a) return a;
|
|
3245
|
-
const pe = await
|
|
3326
|
+
const pe = await requireEntityPermissionEffective(req, "settings", "read");
|
|
3246
3327
|
if (pe) return pe;
|
|
3247
3328
|
}
|
|
3248
3329
|
return settingsHandlers.GET(req, group);
|
|
3249
3330
|
}
|
|
3250
3331
|
if (method === "PUT") {
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
if (pe) return pe;
|
|
3254
|
-
}
|
|
3332
|
+
const pe = await requireEntityPermissionEffective(req, "settings", "update");
|
|
3333
|
+
if (pe) return pe;
|
|
3255
3334
|
return settingsHandlers.PUT(req, group);
|
|
3256
3335
|
}
|
|
3257
3336
|
}
|
|
@@ -3267,10 +3346,8 @@ function createCmsApiHandler(config) {
|
|
|
3267
3346
|
if (path[0] === "orders" && path.length === 3 && path[2] === "invoice" && method === "GET" && getCms) {
|
|
3268
3347
|
const a = await config.requireAuth(req);
|
|
3269
3348
|
if (a) return a;
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
if (pe) return pe;
|
|
3273
|
-
}
|
|
3349
|
+
const pe = await requireEntityPermissionEffective(req, "orders", "read");
|
|
3350
|
+
if (pe) return pe;
|
|
3274
3351
|
const cms = await getCms();
|
|
3275
3352
|
const { streamOrderInvoicePdf: streamOrderInvoicePdf2 } = await Promise.resolve().then(() => (init_erp_order_invoice(), erp_order_invoice_exports));
|
|
3276
3353
|
const oid = Number(path[1]);
|
|
@@ -3280,10 +3357,8 @@ function createCmsApiHandler(config) {
|
|
|
3280
3357
|
if (path[0] === "orders" && path.length === 3 && path[2] === "repost-erp" && getCms) {
|
|
3281
3358
|
const a = await config.requireAuth(req);
|
|
3282
3359
|
if (a) return a;
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
if (pe) return pe;
|
|
3286
|
-
}
|
|
3360
|
+
const pe = await requireEntityPermissionEffective(req, "orders", method === "GET" ? "read" : "update");
|
|
3361
|
+
if (pe) return pe;
|
|
3287
3362
|
const oid = Number(path[1]);
|
|
3288
3363
|
if (!Number.isFinite(oid)) return config.json({ error: "Invalid id" }, { status: 400 });
|
|
3289
3364
|
const cms = await getCms();
|