@infuro/cms-core 1.0.16 → 1.0.18
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 +135 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +135 -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/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.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { A as AnalyticsHandlerConfig, c as AuthHandlersConfig, B as BlogBySlugConfig, d as ChangePasswordConfig, e as CmsApiHandlerConfig, f as CmsGetter, g as CrudHandlerOptions, D as DashboardStatsConfig, h as EcommerceAnalyticsConfig, b as EntityMap, F as ForgotPasswordConfig, i as FormBySlugConfig, G as GetPublicSettingsGroupConfig, j as GetPublicSettingsGroupDataSource, I as InviteAcceptConfig, k as SetPasswordConfig, l as SettingsApiConfig, n as StorefrontApiConfig, o as StorefrontOtpFlags, U as UploadHandlerConfig, p as UserAuthApiConfig, q as UserAvatarConfig, r as UserProfileConfig, s as UsersApiConfig, t as createAnalyticsHandlers, u as createBlogBySlugHandler, v as createChangePasswordHandler, w as createCmsApiHandler, x as createCrudByIdHandler, y as createCrudHandler, z as createDashboardStatsHandler, H as createEcommerceAnalyticsHandler, J as createForgotPasswordHandler, K as createFormBySlugHandler, L as createInviteAcceptHandler, M as createMediaZipExtractHandler, N as createSetPasswordHandler, P as createSettingsApiHandlers, Q as createStorefrontApiHandler, R as createUploadHandler, V as createUserAuthApiRouter, W as createUserAvatarHandler, X as createUserProfileHandler, Y as createUsersApiHandlers, _ as getPublicSettingsGroup } from './index-
|
|
1
|
+
export { A as AnalyticsHandlerConfig, c as AuthHandlersConfig, B as BlogBySlugConfig, d as ChangePasswordConfig, e as CmsApiHandlerConfig, f as CmsGetter, g as CrudHandlerOptions, D as DashboardStatsConfig, h as EcommerceAnalyticsConfig, b as EntityMap, F as ForgotPasswordConfig, i as FormBySlugConfig, G as GetPublicSettingsGroupConfig, j as GetPublicSettingsGroupDataSource, I as InviteAcceptConfig, k as SetPasswordConfig, l as SettingsApiConfig, n as StorefrontApiConfig, o as StorefrontOtpFlags, U as UploadHandlerConfig, p as UserAuthApiConfig, q as UserAvatarConfig, r as UserProfileConfig, s as UsersApiConfig, t as createAnalyticsHandlers, u as createBlogBySlugHandler, v as createChangePasswordHandler, w as createCmsApiHandler, x as createCrudByIdHandler, y as createCrudHandler, z as createDashboardStatsHandler, H as createEcommerceAnalyticsHandler, J as createForgotPasswordHandler, K as createFormBySlugHandler, L as createInviteAcceptHandler, M as createMediaZipExtractHandler, N as createSetPasswordHandler, P as createSettingsApiHandlers, Q as createStorefrontApiHandler, R as createUploadHandler, V as createUserAuthApiRouter, W as createUserAvatarHandler, X as createUserProfileHandler, Y as createUsersApiHandlers, _ as getPublicSettingsGroup } from './index-D2C1O9b4.cjs';
|
|
2
2
|
import 'typeorm';
|
|
3
3
|
import './helpers-dlrF_49e.cjs';
|
package/dist/api.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { A as AnalyticsHandlerConfig, c as AuthHandlersConfig, B as BlogBySlugConfig, d as ChangePasswordConfig, e as CmsApiHandlerConfig, f as CmsGetter, g as CrudHandlerOptions, D as DashboardStatsConfig, h as EcommerceAnalyticsConfig, b as EntityMap, F as ForgotPasswordConfig, i as FormBySlugConfig, G as GetPublicSettingsGroupConfig, j as GetPublicSettingsGroupDataSource, I as InviteAcceptConfig, k as SetPasswordConfig, l as SettingsApiConfig, n as StorefrontApiConfig, o as StorefrontOtpFlags, U as UploadHandlerConfig, p as UserAuthApiConfig, q as UserAvatarConfig, r as UserProfileConfig, s as UsersApiConfig, t as createAnalyticsHandlers, u as createBlogBySlugHandler, v as createChangePasswordHandler, w as createCmsApiHandler, x as createCrudByIdHandler, y as createCrudHandler, z as createDashboardStatsHandler, H as createEcommerceAnalyticsHandler, J as createForgotPasswordHandler, K as createFormBySlugHandler, L as createInviteAcceptHandler, M as createMediaZipExtractHandler, N as createSetPasswordHandler, P as createSettingsApiHandlers, Q as createStorefrontApiHandler, R as createUploadHandler, V as createUserAuthApiRouter, W as createUserAvatarHandler, X as createUserProfileHandler, Y as createUsersApiHandlers, _ as getPublicSettingsGroup } from './index-
|
|
1
|
+
export { A as AnalyticsHandlerConfig, c as AuthHandlersConfig, B as BlogBySlugConfig, d as ChangePasswordConfig, e as CmsApiHandlerConfig, f as CmsGetter, g as CrudHandlerOptions, D as DashboardStatsConfig, h as EcommerceAnalyticsConfig, b as EntityMap, F as ForgotPasswordConfig, i as FormBySlugConfig, G as GetPublicSettingsGroupConfig, j as GetPublicSettingsGroupDataSource, I as InviteAcceptConfig, k as SetPasswordConfig, l as SettingsApiConfig, n as StorefrontApiConfig, o as StorefrontOtpFlags, U as UploadHandlerConfig, p as UserAuthApiConfig, q as UserAvatarConfig, r as UserProfileConfig, s as UsersApiConfig, t as createAnalyticsHandlers, u as createBlogBySlugHandler, v as createChangePasswordHandler, w as createCmsApiHandler, x as createCrudByIdHandler, y as createCrudHandler, z as createDashboardStatsHandler, H as createEcommerceAnalyticsHandler, J as createForgotPasswordHandler, K as createFormBySlugHandler, L as createInviteAcceptHandler, M as createMediaZipExtractHandler, N as createSetPasswordHandler, P as createSettingsApiHandlers, Q as createStorefrontApiHandler, R as createUploadHandler, V as createUserAuthApiRouter, W as createUserAvatarHandler, X as createUserProfileHandler, Y as createUsersApiHandlers, _ as getPublicSettingsGroup } from './index-GMn7-9PX.js';
|
|
2
2
|
import 'typeorm';
|
|
3
3
|
import './helpers-dlrF_49e.js';
|
package/dist/api.js
CHANGED
|
@@ -520,6 +520,28 @@ function buildSearchWhereClause(repo, search) {
|
|
|
520
520
|
if (ors.length === 0) return {};
|
|
521
521
|
return ors.length === 1 ? ors[0] : ors;
|
|
522
522
|
}
|
|
523
|
+
function entityHasSoftDelete(repo) {
|
|
524
|
+
return repo.metadata.columns.some((c) => c.propertyName === "deleted");
|
|
525
|
+
}
|
|
526
|
+
function mergeDeletedFalseWhere(repo, where) {
|
|
527
|
+
if (!entityHasSoftDelete(repo)) return where;
|
|
528
|
+
const d = { deleted: false };
|
|
529
|
+
if (Array.isArray(where)) {
|
|
530
|
+
if (where.length === 0) return [d];
|
|
531
|
+
return where.map((w) => ({ ...w, ...d }));
|
|
532
|
+
}
|
|
533
|
+
return Object.keys(where).length > 0 ? { ...where, ...d } : d;
|
|
534
|
+
}
|
|
535
|
+
function buildSoftDeletePayload(meta, deletedBy) {
|
|
536
|
+
const payload = { deleted: true };
|
|
537
|
+
if (meta.columns.some((c) => c.propertyName === "deletedAt")) {
|
|
538
|
+
payload.deletedAt = /* @__PURE__ */ new Date();
|
|
539
|
+
}
|
|
540
|
+
if (deletedBy != null && meta.columns.some((c) => c.propertyName === "deletedBy")) {
|
|
541
|
+
payload.deletedBy = deletedBy;
|
|
542
|
+
}
|
|
543
|
+
return payload;
|
|
544
|
+
}
|
|
523
545
|
function makeContactErpSync(dataSource, entityMap, getCms) {
|
|
524
546
|
return async function syncContactRowToErp(row) {
|
|
525
547
|
if (!getCms) return;
|
|
@@ -544,10 +566,11 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
544
566
|
async function authz(req, resource, action) {
|
|
545
567
|
const authError = await requireAuth(req);
|
|
546
568
|
if (authError) return authError;
|
|
547
|
-
if (reqPerm) {
|
|
548
|
-
|
|
549
|
-
if (pe) return pe;
|
|
569
|
+
if (!reqPerm) {
|
|
570
|
+
return json({ error: "Forbidden", reason: "entity_rbac_required", entity: resource, action }, { status: 403 });
|
|
550
571
|
}
|
|
572
|
+
const pe = await reqPerm(req, resource, action);
|
|
573
|
+
if (pe) return pe;
|
|
551
574
|
return null;
|
|
552
575
|
}
|
|
553
576
|
return {
|
|
@@ -583,7 +606,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
583
606
|
return json({ total: 0, page, limit, totalPages: 0, data: [] });
|
|
584
607
|
}
|
|
585
608
|
}
|
|
586
|
-
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);
|
|
609
|
+
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);
|
|
587
610
|
if (search && typeof search === "string" && search.trim()) {
|
|
588
611
|
const term = `%${search.trim()}%`;
|
|
589
612
|
qb.andWhere(
|
|
@@ -621,7 +644,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
621
644
|
const dateTo = searchParams.get("dateTo")?.trim();
|
|
622
645
|
const methodFilter = searchParams.get("method")?.trim();
|
|
623
646
|
const orderNumberParam = searchParams.get("orderNumber")?.trim();
|
|
624
|
-
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);
|
|
647
|
+
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);
|
|
625
648
|
if (search && typeof search === "string" && search.trim()) {
|
|
626
649
|
const term = `%${search.trim()}%`;
|
|
627
650
|
qb.andWhere(
|
|
@@ -652,7 +675,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
652
675
|
const repo2 = dataSource.getRepository(entity);
|
|
653
676
|
const statusFilter = searchParams.get("status")?.trim();
|
|
654
677
|
const inventory = searchParams.get("inventory")?.trim();
|
|
655
|
-
const productWhere = {};
|
|
678
|
+
const productWhere = { deleted: false };
|
|
656
679
|
if (statusFilter) productWhere.status = statusFilter;
|
|
657
680
|
if (inventory === "in_stock") productWhere.quantity = MoreThan(0);
|
|
658
681
|
if (inventory === "out_of_stock") productWhere.quantity = 0;
|
|
@@ -675,7 +698,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
675
698
|
const typeFilter2 = searchParams.get("type")?.trim();
|
|
676
699
|
const orderIdParam = searchParams.get("orderId")?.trim();
|
|
677
700
|
const includeSummary = searchParams.get("includeSummary") === "1";
|
|
678
|
-
const qb = repo2.createQueryBuilder("contact").orderBy(`contact.${sortField2}`, sortOrderContacts).skip(skip).take(limit);
|
|
701
|
+
const qb = repo2.createQueryBuilder("contact").andWhere("contact.deleted = :contactDel", { contactDel: false }).orderBy(`contact.${sortField2}`, sortOrderContacts).skip(skip).take(limit);
|
|
679
702
|
if (search && typeof search === "string" && search.trim()) {
|
|
680
703
|
const term = `%${search.trim()}%`;
|
|
681
704
|
qb.andWhere("(contact.name ILIKE :term OR contact.email ILIKE :term OR contact.phone ILIKE :term)", { term });
|
|
@@ -716,9 +739,9 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
716
739
|
if (parentIdParam != null && parentIdParam !== "") {
|
|
717
740
|
const n = Number(parentIdParam);
|
|
718
741
|
if (!Number.isFinite(n)) return json({ error: "Invalid parentId" }, { status: 400 });
|
|
719
|
-
qb.where("m.parentId = :pid", { pid: n });
|
|
742
|
+
qb.where("m.deleted = :mediaDel AND m.parentId = :pid", { mediaDel: false, pid: n });
|
|
720
743
|
} else {
|
|
721
|
-
qb.where("m.parentId IS NULL");
|
|
744
|
+
qb.where("m.deleted = :mediaDel AND m.parentId IS NULL", { mediaDel: false });
|
|
722
745
|
}
|
|
723
746
|
if (search && typeof search === "string" && search.trim()) {
|
|
724
747
|
qb.andWhere("m.filename ILIKE :search", { search: `%${search.trim()}%` });
|
|
@@ -762,6 +785,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
762
785
|
where = extraWhere;
|
|
763
786
|
}
|
|
764
787
|
}
|
|
788
|
+
where = mergeDeletedFalseWhere(repo, where);
|
|
765
789
|
const [data, total] = await repo.findAndCount({
|
|
766
790
|
skip,
|
|
767
791
|
take: limit,
|
|
@@ -929,15 +953,16 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
929
953
|
};
|
|
930
954
|
}
|
|
931
955
|
function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
932
|
-
const { requireAuth, json, requireEntityPermission: reqPerm, getCms } = options;
|
|
956
|
+
const { requireAuth, json, requireEntityPermission: reqPerm, getCms, getDeletedByUserId } = options;
|
|
933
957
|
const syncContactRowToErp = makeContactErpSync(dataSource, entityMap, getCms);
|
|
934
958
|
async function authz(req, resource, action) {
|
|
935
959
|
const authError = await requireAuth(req);
|
|
936
960
|
if (authError) return authError;
|
|
937
|
-
if (reqPerm) {
|
|
938
|
-
|
|
939
|
-
if (pe) return pe;
|
|
961
|
+
if (!reqPerm) {
|
|
962
|
+
return json({ error: "Forbidden", reason: "entity_rbac_required", entity: resource, action }, { status: 403 });
|
|
940
963
|
}
|
|
964
|
+
const pe = await reqPerm(req, resource, action);
|
|
965
|
+
if (pe) return pe;
|
|
941
966
|
return null;
|
|
942
967
|
}
|
|
943
968
|
return {
|
|
@@ -949,7 +974,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
949
974
|
const repo = dataSource.getRepository(entity);
|
|
950
975
|
if (resource === "orders") {
|
|
951
976
|
const order = await repo.findOne({
|
|
952
|
-
where: { id: Number(id) },
|
|
977
|
+
where: { id: Number(id), deleted: false },
|
|
953
978
|
relations: ["contact", "billingAddress", "shippingAddress", "items", "items.product", "items.product.collection", "payments"]
|
|
954
979
|
});
|
|
955
980
|
if (!order) return json({ message: "Not found" }, { status: 404 });
|
|
@@ -961,7 +986,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
961
986
|
}
|
|
962
987
|
if (resource === "contacts") {
|
|
963
988
|
const contact = await repo.findOne({
|
|
964
|
-
where: { id: Number(id) },
|
|
989
|
+
where: { id: Number(id), deleted: false },
|
|
965
990
|
relations: ["form_submissions", "form_submissions.form", "orders", "payments", "addresses"]
|
|
966
991
|
});
|
|
967
992
|
if (!contact) return json({ message: "Not found" }, { status: 404 });
|
|
@@ -983,7 +1008,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
983
1008
|
}
|
|
984
1009
|
if (resource === "payments") {
|
|
985
1010
|
const payment = await repo.findOne({
|
|
986
|
-
where: { id: Number(id) },
|
|
1011
|
+
where: { id: Number(id), deleted: false },
|
|
987
1012
|
relations: ["order", "order.contact", "contact"]
|
|
988
1013
|
});
|
|
989
1014
|
if (!payment) return json({ message: "Not found" }, { status: 404 });
|
|
@@ -991,12 +1016,13 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
991
1016
|
}
|
|
992
1017
|
if (resource === "blogs") {
|
|
993
1018
|
const blog = await repo.findOne({
|
|
994
|
-
where: { id: Number(id) },
|
|
1019
|
+
where: { id: Number(id), deleted: false },
|
|
995
1020
|
relations: ["category", "seo", "tags"]
|
|
996
1021
|
});
|
|
997
1022
|
return blog ? json(blog) : json({ message: "Not found" }, { status: 404 });
|
|
998
1023
|
}
|
|
999
|
-
const
|
|
1024
|
+
const idWhere = entityHasSoftDelete(repo) ? { id: Number(id), deleted: false } : { id: Number(id) };
|
|
1025
|
+
const item = await repo.findOne({ where: idWhere });
|
|
1000
1026
|
return item ? json(item) : json({ message: "Not found" }, { status: 404 });
|
|
1001
1027
|
},
|
|
1002
1028
|
async PUT(req, resource, id) {
|
|
@@ -1008,7 +1034,9 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1008
1034
|
const repo = dataSource.getRepository(entity);
|
|
1009
1035
|
const numericId = Number(id);
|
|
1010
1036
|
if (resource === "blogs" && rawBody && typeof rawBody === "object" && entityMap.categories && entityMap.seos && entityMap.tags) {
|
|
1011
|
-
const existing = await repo.findOne({
|
|
1037
|
+
const existing = await repo.findOne({
|
|
1038
|
+
where: { id: numericId, deleted: false }
|
|
1039
|
+
});
|
|
1012
1040
|
if (!existing) return json({ message: "Not found" }, { status: 404 });
|
|
1013
1041
|
const updatePayload2 = pickColumnUpdates(repo, rawBody);
|
|
1014
1042
|
if ("category" in rawBody) {
|
|
@@ -1084,6 +1112,12 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1084
1112
|
});
|
|
1085
1113
|
return updated2 ? json(updated2) : json({ message: "Not found" }, { status: 404 });
|
|
1086
1114
|
}
|
|
1115
|
+
if (entityHasSoftDelete(repo)) {
|
|
1116
|
+
const cur = await repo.findOne({
|
|
1117
|
+
where: { id: numericId, deleted: false }
|
|
1118
|
+
});
|
|
1119
|
+
if (!cur) return json({ message: "Not found" }, { status: 404 });
|
|
1120
|
+
}
|
|
1087
1121
|
const updatePayload = rawBody && typeof rawBody === "object" ? pickColumnUpdates(repo, rawBody) : {};
|
|
1088
1122
|
if (resource === "media") {
|
|
1089
1123
|
const u = updatePayload;
|
|
@@ -1110,7 +1144,24 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
1110
1144
|
const entity = entityMap[resource];
|
|
1111
1145
|
if (!entity) return json({ error: "Invalid resource" }, { status: 400 });
|
|
1112
1146
|
const repo = dataSource.getRepository(entity);
|
|
1113
|
-
const
|
|
1147
|
+
const numericId = Number(id);
|
|
1148
|
+
if (entityHasSoftDelete(repo)) {
|
|
1149
|
+
const existing = await repo.findOne({
|
|
1150
|
+
where: { id: numericId, deleted: false }
|
|
1151
|
+
});
|
|
1152
|
+
if (!existing) return json({ message: "Not found" }, { status: 404 });
|
|
1153
|
+
let deletedBy = null;
|
|
1154
|
+
if (getDeletedByUserId) {
|
|
1155
|
+
try {
|
|
1156
|
+
deletedBy = await getDeletedByUserId(req);
|
|
1157
|
+
} catch {
|
|
1158
|
+
deletedBy = null;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
await repo.update(numericId, buildSoftDeletePayload(repo.metadata, deletedBy));
|
|
1162
|
+
return json({ message: "Deleted successfully" }, { status: 200 });
|
|
1163
|
+
}
|
|
1164
|
+
const result = await repo.delete(numericId);
|
|
1114
1165
|
if (result.affected === 0) return json({ message: "Not found" }, { status: 404 });
|
|
1115
1166
|
return json({ message: "Deleted successfully" }, { status: 200 });
|
|
1116
1167
|
}
|
|
@@ -2218,7 +2269,7 @@ function createFormSubmissionHandler(config) {
|
|
|
2218
2269
|
};
|
|
2219
2270
|
}
|
|
2220
2271
|
function createUsersApiHandlers(config) {
|
|
2221
|
-
const { dataSource, entityMap, json, requireAuth, requireEntityPermission, baseUrl, getCms, getCompanyDetails } = config;
|
|
2272
|
+
const { dataSource, entityMap, json, requireAuth, requireEntityPermission, baseUrl, getCms, getCompanyDetails, getSessionUser } = config;
|
|
2222
2273
|
async function trySendInviteEmail(toEmail, inviteLink, inviteeName) {
|
|
2223
2274
|
if (!getCms) return;
|
|
2224
2275
|
try {
|
|
@@ -2254,7 +2305,10 @@ function createUsersApiHandlers(config) {
|
|
|
2254
2305
|
const sortField = url.searchParams.get("sortField") || "createdAt";
|
|
2255
2306
|
const sortOrder = url.searchParams.get("sortOrder") === "desc" ? "DESC" : "ASC";
|
|
2256
2307
|
const search = url.searchParams.get("search");
|
|
2257
|
-
const where = search ? [
|
|
2308
|
+
const where = search ? [
|
|
2309
|
+
{ name: ILike2(`%${search}%`), deleted: false },
|
|
2310
|
+
{ email: ILike2(`%${search}%`), deleted: false }
|
|
2311
|
+
] : { deleted: false };
|
|
2258
2312
|
const [data, total] = await userRepo().findAndCount({
|
|
2259
2313
|
skip,
|
|
2260
2314
|
take: limit,
|
|
@@ -2319,7 +2373,7 @@ function createUsersApiHandlers(config) {
|
|
|
2319
2373
|
}
|
|
2320
2374
|
try {
|
|
2321
2375
|
const user = await userRepo().findOne({
|
|
2322
|
-
where: { id: parseInt(id, 10) },
|
|
2376
|
+
where: { id: parseInt(id, 10), deleted: false },
|
|
2323
2377
|
relations: ["group"],
|
|
2324
2378
|
select: ["id", "name", "email", "blocked", "createdAt", "updatedAt", "groupId"]
|
|
2325
2379
|
});
|
|
@@ -2337,11 +2391,14 @@ function createUsersApiHandlers(config) {
|
|
|
2337
2391
|
if (pe) return pe;
|
|
2338
2392
|
}
|
|
2339
2393
|
try {
|
|
2394
|
+
const uid = parseInt(id, 10);
|
|
2395
|
+
const existing = await userRepo().findOne({ where: { id: uid, deleted: false } });
|
|
2396
|
+
if (!existing) return json({ error: "Not found" }, { status: 404 });
|
|
2340
2397
|
const body = await req.json();
|
|
2341
2398
|
const { password: _p, ...safe } = body;
|
|
2342
|
-
await userRepo().update(
|
|
2399
|
+
await userRepo().update(uid, safe);
|
|
2343
2400
|
const updated = await userRepo().findOne({
|
|
2344
|
-
where: { id:
|
|
2401
|
+
where: { id: uid, deleted: false },
|
|
2345
2402
|
relations: ["group"],
|
|
2346
2403
|
select: ["id", "name", "email", "blocked", "createdAt", "updatedAt", "groupId"]
|
|
2347
2404
|
});
|
|
@@ -2358,8 +2415,23 @@ function createUsersApiHandlers(config) {
|
|
|
2358
2415
|
if (pe) return pe;
|
|
2359
2416
|
}
|
|
2360
2417
|
try {
|
|
2361
|
-
const
|
|
2362
|
-
|
|
2418
|
+
const uid = parseInt(id, 10);
|
|
2419
|
+
const existing = await userRepo().findOne({ where: { id: uid, deleted: false } });
|
|
2420
|
+
if (!existing) return json({ error: "User not found" }, { status: 404 });
|
|
2421
|
+
let deletedBy = null;
|
|
2422
|
+
if (getSessionUser) {
|
|
2423
|
+
try {
|
|
2424
|
+
const u = await getSessionUser();
|
|
2425
|
+
if (u?.id) {
|
|
2426
|
+
const n = Number(u.id);
|
|
2427
|
+
if (Number.isFinite(n)) deletedBy = n;
|
|
2428
|
+
}
|
|
2429
|
+
} catch {
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
const payload = { deleted: true, deletedAt: /* @__PURE__ */ new Date() };
|
|
2433
|
+
if (deletedBy != null) payload.deletedBy = deletedBy;
|
|
2434
|
+
await userRepo().update(uid, payload);
|
|
2363
2435
|
return json({ message: "User deleted successfully" });
|
|
2364
2436
|
} catch {
|
|
2365
2437
|
return json({ error: "Server Error" }, { status: 500 });
|
|
@@ -2373,7 +2445,10 @@ function createUsersApiHandlers(config) {
|
|
|
2373
2445
|
if (pe) return pe;
|
|
2374
2446
|
}
|
|
2375
2447
|
try {
|
|
2376
|
-
const user = await userRepo().findOne({
|
|
2448
|
+
const user = await userRepo().findOne({
|
|
2449
|
+
where: { id: parseInt(id, 10), deleted: false },
|
|
2450
|
+
select: ["email", "name"]
|
|
2451
|
+
});
|
|
2377
2452
|
if (!user) return json({ error: "User not found" }, { status: 404 });
|
|
2378
2453
|
const emailToken = Buffer.from(user.email).toString("base64");
|
|
2379
2454
|
const inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;
|
|
@@ -2996,9 +3071,10 @@ function createCmsApiHandler(config) {
|
|
|
2996
3071
|
userProfile,
|
|
2997
3072
|
settings: settingsConfig,
|
|
2998
3073
|
chat: chatConfig,
|
|
2999
|
-
requireEntityPermission:
|
|
3074
|
+
requireEntityPermission: userRequireEntityPermission,
|
|
3000
3075
|
getSessionUser
|
|
3001
3076
|
} = config;
|
|
3077
|
+
const requireEntityPermissionEffective = userRequireEntityPermission ?? (async (_req, entity, action) => config.json({ error: "Forbidden", reason: "entity_rbac_required", entity, action }, { status: 403 }));
|
|
3002
3078
|
const analytics = analyticsConfig ?? (getCms ? {
|
|
3003
3079
|
json: config.json,
|
|
3004
3080
|
requireAuth: async () => null,
|
|
@@ -3036,12 +3112,20 @@ function createCmsApiHandler(config) {
|
|
|
3036
3112
|
const crudOpts = {
|
|
3037
3113
|
requireAuth: config.requireAuth,
|
|
3038
3114
|
json: config.json,
|
|
3039
|
-
requireEntityPermission:
|
|
3040
|
-
getCms
|
|
3115
|
+
requireEntityPermission: requireEntityPermissionEffective,
|
|
3116
|
+
getCms,
|
|
3117
|
+
...getSessionUser ? {
|
|
3118
|
+
getDeletedByUserId: async () => {
|
|
3119
|
+
const u = await getSessionUser();
|
|
3120
|
+
if (!u?.id) return null;
|
|
3121
|
+
const n = Number(u.id);
|
|
3122
|
+
return Number.isFinite(n) ? n : null;
|
|
3123
|
+
}
|
|
3124
|
+
} : {}
|
|
3041
3125
|
};
|
|
3042
3126
|
const crud = createCrudHandler(dataSource, entityMap, crudOpts);
|
|
3043
3127
|
const crudById = createCrudByIdHandler(dataSource, entityMap, crudOpts);
|
|
3044
|
-
const mergePerm = (c) => !c ? void 0 :
|
|
3128
|
+
const mergePerm = (c) => !c ? void 0 : { ...c, requireEntityPermission: requireEntityPermissionEffective };
|
|
3045
3129
|
const adminRoles = getSessionUser && createAdminRolesHandlers({
|
|
3046
3130
|
dataSource,
|
|
3047
3131
|
entityMap,
|
|
@@ -3057,12 +3141,7 @@ function createCmsApiHandler(config) {
|
|
|
3057
3141
|
json: config.json,
|
|
3058
3142
|
requireAuth: config.requireAuth
|
|
3059
3143
|
}
|
|
3060
|
-
)
|
|
3061
|
-
dataSource,
|
|
3062
|
-
entityMap,
|
|
3063
|
-
json: config.json,
|
|
3064
|
-
requireAuth: config.requireAuth
|
|
3065
|
-
};
|
|
3144
|
+
);
|
|
3066
3145
|
const ecommerceAnalyticsGet = createEcommerceAnalyticsHandler(ecommerceAnalyticsResolved);
|
|
3067
3146
|
const analyticsHandlers = analytics ? createAnalyticsHandlers(analytics) : null;
|
|
3068
3147
|
const uploadMerged = upload ? {
|
|
@@ -3081,7 +3160,11 @@ function createCmsApiHandler(config) {
|
|
|
3081
3160
|
const usersApiMerged = usersApi && getCms ? {
|
|
3082
3161
|
...usersApi,
|
|
3083
3162
|
getCms: usersApi.getCms ?? getCms,
|
|
3084
|
-
getCompanyDetails: usersApi.getCompanyDetails ?? config.getCompanyDetails
|
|
3163
|
+
getCompanyDetails: usersApi.getCompanyDetails ?? config.getCompanyDetails,
|
|
3164
|
+
...getSessionUser ? { getSessionUser: usersApi.getSessionUser ?? getSessionUser } : {}
|
|
3165
|
+
} : usersApi ? {
|
|
3166
|
+
...usersApi,
|
|
3167
|
+
...getSessionUser ? { getSessionUser: usersApi.getSessionUser ?? getSessionUser } : {}
|
|
3085
3168
|
} : usersApi;
|
|
3086
3169
|
const usersHandlers = usersApiMerged ? createUsersApiHandlers(mergePerm(usersApiMerged) ?? usersApiMerged) : null;
|
|
3087
3170
|
const avatarPost = userAvatar ? createUserAvatarHandler(userAvatar) : null;
|
|
@@ -3092,7 +3175,7 @@ function createCmsApiHandler(config) {
|
|
|
3092
3175
|
entityMap,
|
|
3093
3176
|
json: config.json,
|
|
3094
3177
|
requireAuth: config.requireAuth,
|
|
3095
|
-
requireEntityPermission:
|
|
3178
|
+
requireEntityPermission: requireEntityPermissionEffective
|
|
3096
3179
|
});
|
|
3097
3180
|
const chatHandlers = chatConfig ? createChatHandlers(chatConfig) : null;
|
|
3098
3181
|
function resolveResource(segment) {
|
|
@@ -3101,12 +3184,10 @@ function createCmsApiHandler(config) {
|
|
|
3101
3184
|
}
|
|
3102
3185
|
return {
|
|
3103
3186
|
async handle(method, path, req) {
|
|
3104
|
-
const perm = reqEntityPerm;
|
|
3105
3187
|
async function analyticsGate() {
|
|
3106
3188
|
const a = await config.requireAuth(req);
|
|
3107
3189
|
if (a) return a;
|
|
3108
|
-
|
|
3109
|
-
return null;
|
|
3190
|
+
return requireEntityPermissionEffective(req, "analytics", "read");
|
|
3110
3191
|
}
|
|
3111
3192
|
if (path[0] === "admin" && path[1] === "roles") {
|
|
3112
3193
|
if (!adminRoles) return config.json({ error: "Not found" }, { status: 404 });
|
|
@@ -3190,19 +3271,17 @@ function createCmsApiHandler(config) {
|
|
|
3190
3271
|
const group = path[1];
|
|
3191
3272
|
const isPublic = settingsConfig?.publicGetGroups?.includes(group);
|
|
3192
3273
|
if (method === "GET") {
|
|
3193
|
-
if (!isPublic
|
|
3274
|
+
if (!isPublic) {
|
|
3194
3275
|
const a = await config.requireAuth(req);
|
|
3195
3276
|
if (a) return a;
|
|
3196
|
-
const pe = await
|
|
3277
|
+
const pe = await requireEntityPermissionEffective(req, "settings", "read");
|
|
3197
3278
|
if (pe) return pe;
|
|
3198
3279
|
}
|
|
3199
3280
|
return settingsHandlers.GET(req, group);
|
|
3200
3281
|
}
|
|
3201
3282
|
if (method === "PUT") {
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
if (pe) return pe;
|
|
3205
|
-
}
|
|
3283
|
+
const pe = await requireEntityPermissionEffective(req, "settings", "update");
|
|
3284
|
+
if (pe) return pe;
|
|
3206
3285
|
return settingsHandlers.PUT(req, group);
|
|
3207
3286
|
}
|
|
3208
3287
|
}
|
|
@@ -3218,10 +3297,8 @@ function createCmsApiHandler(config) {
|
|
|
3218
3297
|
if (path[0] === "orders" && path.length === 3 && path[2] === "invoice" && method === "GET" && getCms) {
|
|
3219
3298
|
const a = await config.requireAuth(req);
|
|
3220
3299
|
if (a) return a;
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
if (pe) return pe;
|
|
3224
|
-
}
|
|
3300
|
+
const pe = await requireEntityPermissionEffective(req, "orders", "read");
|
|
3301
|
+
if (pe) return pe;
|
|
3225
3302
|
const cms = await getCms();
|
|
3226
3303
|
const { streamOrderInvoicePdf: streamOrderInvoicePdf2 } = await Promise.resolve().then(() => (init_erp_order_invoice(), erp_order_invoice_exports));
|
|
3227
3304
|
const oid = Number(path[1]);
|
|
@@ -3231,10 +3308,8 @@ function createCmsApiHandler(config) {
|
|
|
3231
3308
|
if (path[0] === "orders" && path.length === 3 && path[2] === "repost-erp" && getCms) {
|
|
3232
3309
|
const a = await config.requireAuth(req);
|
|
3233
3310
|
if (a) return a;
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
if (pe) return pe;
|
|
3237
|
-
}
|
|
3311
|
+
const pe = await requireEntityPermissionEffective(req, "orders", method === "GET" ? "read" : "update");
|
|
3312
|
+
if (pe) return pe;
|
|
3238
3313
|
const oid = Number(path[1]);
|
|
3239
3314
|
if (!Number.isFinite(oid)) return config.json({ error: "Invalid id" }, { status: 400 });
|
|
3240
3315
|
const cms = await getCms();
|