@infuro/cms-core 1.0.24 → 1.0.26
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/dist/admin.cjs +5725 -4475
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +23 -4
- package/dist/admin.d.ts +23 -4
- package/dist/admin.js +5672 -4420
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +422 -52
- 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 +430 -60
- package/dist/api.js.map +1 -1
- package/dist/auth.cjs +9 -1
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.js +9 -1
- package/dist/auth.js.map +1 -1
- package/dist/cli.cjs +7 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -1
- package/dist/{index-BGAh4fPQ.d.cts → index--vbixpxE.d.cts} +17 -2
- package/dist/{index-Cnwh7B3r.d.ts → index-DMJgi-fy.d.ts} +17 -2
- package/dist/index.cjs +508 -67
- 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 +509 -68
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,10 +38,52 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
38
38
|
return result;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
// src/plugins/erp/erp-log.ts
|
|
42
|
+
function logErp(event, detail) {
|
|
43
|
+
if (detail && Object.keys(detail).length) console.info(ERP_LOG, event, detail);
|
|
44
|
+
else console.info(ERP_LOG, event);
|
|
45
|
+
}
|
|
46
|
+
function warnErp(event, detail) {
|
|
47
|
+
console.warn(ERP_LOG, event, detail);
|
|
48
|
+
}
|
|
49
|
+
function errorErp(event, detail) {
|
|
50
|
+
console.error(ERP_LOG, event, detail);
|
|
51
|
+
}
|
|
52
|
+
function erpSafeWebhookUrl(url) {
|
|
53
|
+
try {
|
|
54
|
+
const u = new URL(url);
|
|
55
|
+
return `${u.origin}${u.pathname}`;
|
|
56
|
+
} catch {
|
|
57
|
+
return "(invalid webhook URL)";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
var ERP_LOG;
|
|
61
|
+
var init_erp_log = __esm({
|
|
62
|
+
"src/plugins/erp/erp-log.ts"() {
|
|
63
|
+
"use strict";
|
|
64
|
+
ERP_LOG = "[webcore:erp]";
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
41
68
|
// src/plugins/erp/erp-queue.ts
|
|
69
|
+
function queuePayloadSummary(payload) {
|
|
70
|
+
if (payload.kind === "order") {
|
|
71
|
+
const o = payload.order;
|
|
72
|
+
return {
|
|
73
|
+
kind: payload.kind,
|
|
74
|
+
platformOrderId: o.platformOrderId ?? o.platformOrderNumber,
|
|
75
|
+
itemCount: Array.isArray(o.items) ? o.items.length : 0
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return { kind: payload.kind };
|
|
79
|
+
}
|
|
42
80
|
async function queueErp(cms, payload) {
|
|
43
81
|
const queue = cms.getPlugin("queue");
|
|
44
|
-
if (!queue)
|
|
82
|
+
if (!queue) {
|
|
83
|
+
warnErp("queue:add_skipped", { reason: "queue_plugin_missing", ...queuePayloadSummary(payload) });
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
logErp("queue:add", { job: ERP_QUEUE_NAME, ...queuePayloadSummary(payload) });
|
|
45
87
|
await queue.add(ERP_QUEUE_NAME, payload);
|
|
46
88
|
}
|
|
47
89
|
function registerErpQueueProcessor(cms) {
|
|
@@ -49,18 +91,31 @@ function registerErpQueueProcessor(cms) {
|
|
|
49
91
|
if (!queue) return;
|
|
50
92
|
queue.registerProcessor(ERP_QUEUE_NAME, async (data) => {
|
|
51
93
|
const erp = cms.getPlugin("erp");
|
|
52
|
-
if (!erp)
|
|
94
|
+
if (!erp) {
|
|
95
|
+
warnErp("queue:processor_skip", { reason: "erp_plugin_missing" });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
53
98
|
const payload = data;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
99
|
+
logErp("queue:job_start", queuePayloadSummary(payload));
|
|
100
|
+
try {
|
|
101
|
+
if (payload.kind === "lead") {
|
|
102
|
+
await erp.submission.submitContact(payload.contact);
|
|
103
|
+
} else if (payload.kind === "formOpportunity") {
|
|
104
|
+
await erp.submission.submitFormOpportunity(payload.contact);
|
|
105
|
+
} else if (payload.kind === "createContact") {
|
|
106
|
+
await erp.submission.submitCreateContact(payload.contact);
|
|
107
|
+
} else if (payload.kind === "order") {
|
|
108
|
+
await erp.submission.submitOrder(payload.order);
|
|
109
|
+
} else if (payload.kind === "productUpsert") {
|
|
110
|
+
await erp.submission.submitProductUpsert(payload.product);
|
|
111
|
+
}
|
|
112
|
+
logErp("queue:job_done", queuePayloadSummary(payload));
|
|
113
|
+
} catch (e) {
|
|
114
|
+
errorErp("queue:job_failed", {
|
|
115
|
+
...queuePayloadSummary(payload),
|
|
116
|
+
message: e instanceof Error ? e.message : String(e)
|
|
117
|
+
});
|
|
118
|
+
throw e;
|
|
64
119
|
}
|
|
65
120
|
});
|
|
66
121
|
}
|
|
@@ -68,6 +123,7 @@ var ERP_QUEUE_NAME;
|
|
|
68
123
|
var init_erp_queue = __esm({
|
|
69
124
|
"src/plugins/erp/erp-queue.ts"() {
|
|
70
125
|
"use strict";
|
|
126
|
+
init_erp_log();
|
|
71
127
|
ERP_QUEUE_NAME = "erp";
|
|
72
128
|
}
|
|
73
129
|
});
|
|
@@ -119,21 +175,36 @@ async function queueErpPaidOrderForOrderId(cms, dataSource, entityMap, orderId)
|
|
|
119
175
|
const cfgRows = await configRepo.find({ where: { settings: "erp", deleted: false } });
|
|
120
176
|
for (const row of cfgRows) {
|
|
121
177
|
const r = row;
|
|
122
|
-
if (r.key === "enabled" && r.value === "false")
|
|
178
|
+
if (r.key === "enabled" && r.value === "false") {
|
|
179
|
+
logErp("paid-order:skip", { orderId, reason: "erp_config_disabled" });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (!cms.getPlugin("erp")) {
|
|
184
|
+
logErp("paid-order:skip", { orderId, reason: "erp_plugin_missing" });
|
|
185
|
+
return;
|
|
123
186
|
}
|
|
124
|
-
if (!cms.getPlugin("erp")) return;
|
|
125
187
|
const orderRepo = dataSource.getRepository(entityMap.orders);
|
|
126
188
|
const ord = await orderRepo.findOne({
|
|
127
189
|
where: { id: orderId },
|
|
128
190
|
relations: ["items", "items.product", "contact", "billingAddress", "shippingAddress", "payments"]
|
|
129
191
|
});
|
|
130
|
-
if (!ord)
|
|
192
|
+
if (!ord) {
|
|
193
|
+
logErp("paid-order:skip", { orderId, reason: "order_not_found" });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
131
196
|
const o = ord;
|
|
132
197
|
const okKind = o.orderKind === void 0 || o.orderKind === null || o.orderKind === "sale";
|
|
133
|
-
if (!okKind)
|
|
198
|
+
if (!okKind) {
|
|
199
|
+
logErp("paid-order:skip", { orderId, reason: "order_kind_not_sale", orderKind: o.orderKind });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
134
202
|
const rawPayments = o.payments ?? [];
|
|
135
203
|
const completedPayments = rawPayments.filter((pay) => pay.status === "completed" && pay.deleted !== true);
|
|
136
|
-
if (!completedPayments.length)
|
|
204
|
+
if (!completedPayments.length) {
|
|
205
|
+
logErp("paid-order:skip", { orderId, reason: "no_completed_payments" });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
137
208
|
const rawItems = o.items ?? [];
|
|
138
209
|
const lines = rawItems.filter((it) => it.product).map((it) => {
|
|
139
210
|
const p = it.product;
|
|
@@ -152,7 +223,10 @@ async function queueErpPaidOrderForOrderId(cms, dataSource, entityMap, orderId)
|
|
|
152
223
|
type: itemType
|
|
153
224
|
};
|
|
154
225
|
});
|
|
155
|
-
if (!lines.length)
|
|
226
|
+
if (!lines.length) {
|
|
227
|
+
logErp("paid-order:skip", { orderId, reason: "no_line_items_with_product" });
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
156
230
|
const contact = o.contact;
|
|
157
231
|
const orderTotalMajor = Number(o.total);
|
|
158
232
|
const paymentDtos = completedPayments.length === 1 && Number.isFinite(orderTotalMajor) ? [paymentRowToWebhookDto(completedPayments[0], orderTotalMajor)] : completedPayments.map((pay) => paymentRowToWebhookDto(pay));
|
|
@@ -174,13 +248,28 @@ async function queueErpPaidOrderForOrderId(cms, dataSource, entityMap, orderId)
|
|
|
174
248
|
payments: paymentDtos,
|
|
175
249
|
metadata: { ...baseMeta, source: "storefront" }
|
|
176
250
|
};
|
|
251
|
+
logErp("paid-order:payload_built", {
|
|
252
|
+
orderId,
|
|
253
|
+
platformOrderId: orderDto.platformOrderId,
|
|
254
|
+
status: orderDto.status,
|
|
255
|
+
itemCount: lines.length,
|
|
256
|
+
skus: lines.map((l) => l.sku),
|
|
257
|
+
paymentCount: paymentDtos.length,
|
|
258
|
+
paymentIds: paymentDtos.map((p) => p.id),
|
|
259
|
+
total: orderTotalMajor
|
|
260
|
+
});
|
|
177
261
|
await queueErp(cms, { kind: "order", order: orderDto });
|
|
178
|
-
} catch {
|
|
262
|
+
} catch (e) {
|
|
263
|
+
errorErp("paid-order:enqueue_failed", {
|
|
264
|
+
orderId,
|
|
265
|
+
message: e instanceof Error ? e.message : String(e)
|
|
266
|
+
});
|
|
179
267
|
}
|
|
180
268
|
}
|
|
181
269
|
var init_paid_order_erp = __esm({
|
|
182
270
|
"src/plugins/erp/paid-order-erp.ts"() {
|
|
183
271
|
"use strict";
|
|
272
|
+
init_erp_log();
|
|
184
273
|
init_erp_queue();
|
|
185
274
|
}
|
|
186
275
|
});
|
|
@@ -816,6 +905,7 @@ async function createCmsApp(options) {
|
|
|
816
905
|
}
|
|
817
906
|
|
|
818
907
|
// src/plugins/erp/erp-submission.ts
|
|
908
|
+
init_erp_log();
|
|
819
909
|
var ERPSubmissionService = class {
|
|
820
910
|
webhookUrl;
|
|
821
911
|
webhookJwt;
|
|
@@ -895,7 +985,29 @@ var ERPSubmissionService = class {
|
|
|
895
985
|
};
|
|
896
986
|
return this.postWebhookJson(envelope);
|
|
897
987
|
}
|
|
988
|
+
summarizeWebhookBody(body) {
|
|
989
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
990
|
+
return { bodyKind: typeof body };
|
|
991
|
+
}
|
|
992
|
+
const o = body;
|
|
993
|
+
const out = { event_type: o.event_type, timestamp: o.timestamp };
|
|
994
|
+
const data = o.data;
|
|
995
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
996
|
+
const d = data;
|
|
997
|
+
out.dataKeys = Object.keys(d);
|
|
998
|
+
out.platformOrderId = d.platformOrderId ?? d.platformOrderNumber;
|
|
999
|
+
out.itemCount = Array.isArray(d.items) ? d.items.length : void 0;
|
|
1000
|
+
}
|
|
1001
|
+
return out;
|
|
1002
|
+
}
|
|
898
1003
|
async postWebhookJson(body) {
|
|
1004
|
+
const safeUrl = erpSafeWebhookUrl(this.webhookUrl);
|
|
1005
|
+
const bodyJson = JSON.stringify(body);
|
|
1006
|
+
logErp("webhook:post_start", {
|
|
1007
|
+
url: safeUrl,
|
|
1008
|
+
bodyBytes: bodyJson.length,
|
|
1009
|
+
...this.summarizeWebhookBody(body)
|
|
1010
|
+
});
|
|
899
1011
|
try {
|
|
900
1012
|
const res = await fetch(this.webhookUrl, {
|
|
901
1013
|
method: "POST",
|
|
@@ -903,13 +1015,19 @@ var ERPSubmissionService = class {
|
|
|
903
1015
|
"Content-Type": "application/json",
|
|
904
1016
|
"X-External-Token": this.webhookJwt
|
|
905
1017
|
},
|
|
906
|
-
body:
|
|
1018
|
+
body: bodyJson
|
|
907
1019
|
});
|
|
908
|
-
if (res.ok) return { success: true, status: res.status };
|
|
909
1020
|
const text = await res.text();
|
|
1021
|
+
const preview = text.length > 500 ? `${text.slice(0, 500)}\u2026` : text;
|
|
1022
|
+
if (res.ok) {
|
|
1023
|
+
logErp("webhook:post_ok", { status: res.status, responsePreview: preview || "(empty body)" });
|
|
1024
|
+
return { success: true, status: res.status };
|
|
1025
|
+
}
|
|
1026
|
+
warnErp("webhook:post_http_error", { status: res.status, responsePreview: preview });
|
|
910
1027
|
return { success: false, error: `${res.status} ${text.slice(0, 500)}`, status: res.status };
|
|
911
1028
|
} catch (e) {
|
|
912
1029
|
const message = e instanceof Error ? e.message : "ERP webhook request failed";
|
|
1030
|
+
errorErp("webhook:post_fetch_failed", { url: safeUrl, message });
|
|
913
1031
|
return { success: false, error: message };
|
|
914
1032
|
}
|
|
915
1033
|
}
|
|
@@ -1023,7 +1141,20 @@ var ERPSubmissionService = class {
|
|
|
1023
1141
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1024
1142
|
data: orderDto
|
|
1025
1143
|
};
|
|
1026
|
-
|
|
1144
|
+
logErp("submitOrder:envelope_ready", {
|
|
1145
|
+
event_type: envelope.event_type,
|
|
1146
|
+
timestamp: envelope.timestamp,
|
|
1147
|
+
platformOrderId: orderDto.platformOrderId ?? orderDto.platformOrderNumber,
|
|
1148
|
+
itemCount: Array.isArray(orderDto.items) ? orderDto.items.length : 0,
|
|
1149
|
+
paymentCount: Array.isArray(orderDto.payments) ? orderDto.payments.length : 0
|
|
1150
|
+
});
|
|
1151
|
+
const result = await this.postWebhookJson(envelope);
|
|
1152
|
+
if (result.success) {
|
|
1153
|
+
logErp("submitOrder:complete", { ok: true, status: result.status });
|
|
1154
|
+
} else {
|
|
1155
|
+
warnErp("submitOrder:complete", { ok: false, status: result.status, error: result.error });
|
|
1156
|
+
}
|
|
1157
|
+
return result;
|
|
1027
1158
|
}
|
|
1028
1159
|
extractContactData(formData, formFields) {
|
|
1029
1160
|
const contactData = {
|
|
@@ -5184,18 +5315,37 @@ function createUsersApiHandlers(config) {
|
|
|
5184
5315
|
try {
|
|
5185
5316
|
const body = await req.json();
|
|
5186
5317
|
if (!body?.name || !body?.email) return json({ error: "Name and email are required" }, { status: 400 });
|
|
5187
|
-
const
|
|
5188
|
-
|
|
5318
|
+
const email = body.email;
|
|
5319
|
+
const existing = await userRepo().findOne({ where: { email } });
|
|
5320
|
+
if (existing && !existing.deleted) {
|
|
5321
|
+
return json({ error: "User with this email already exists" }, { status: 400 });
|
|
5322
|
+
}
|
|
5189
5323
|
const groupRepo = dataSource.getRepository(entityMap.user_groups);
|
|
5190
5324
|
const customerG = await groupRepo.findOne({ where: { name: "Customer", deleted: false } });
|
|
5191
5325
|
const gid = body.groupId ?? null;
|
|
5192
5326
|
const isCustomer = !!(customerG && gid === customerG.id);
|
|
5193
5327
|
const adminAccess = isCustomer ? false : body.adminAccess === false ? false : true;
|
|
5194
5328
|
const blocked = body.blocked === true || body.blocked === "true" || body.blocked === 1 || body.blocked === "1";
|
|
5195
|
-
const newUser = await
|
|
5329
|
+
const newUser = existing?.deleted ? await (async () => {
|
|
5330
|
+
await userRepo().update(existing.id, {
|
|
5331
|
+
deleted: false,
|
|
5332
|
+
deletedAt: null,
|
|
5333
|
+
deletedBy: null,
|
|
5334
|
+
name: body.name,
|
|
5335
|
+
email,
|
|
5336
|
+
password: null,
|
|
5337
|
+
blocked,
|
|
5338
|
+
groupId: gid,
|
|
5339
|
+
adminAccess,
|
|
5340
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
5341
|
+
});
|
|
5342
|
+
const row = await userRepo().findOne({ where: { id: existing.id } });
|
|
5343
|
+
if (!row) throw new Error("user missing after restore");
|
|
5344
|
+
return row;
|
|
5345
|
+
})() : await userRepo().save(
|
|
5196
5346
|
userRepo().create({
|
|
5197
5347
|
name: body.name,
|
|
5198
|
-
email
|
|
5348
|
+
email,
|
|
5199
5349
|
password: null,
|
|
5200
5350
|
blocked,
|
|
5201
5351
|
groupId: gid,
|
|
@@ -5348,21 +5498,110 @@ function createUserAvatarHandler(config) {
|
|
|
5348
5498
|
}
|
|
5349
5499
|
};
|
|
5350
5500
|
}
|
|
5501
|
+
var PROFILE_EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
5351
5502
|
function createUserProfileHandler(config) {
|
|
5352
|
-
const { dataSource, entityMap, json, getSession } = config;
|
|
5353
|
-
|
|
5503
|
+
const { dataSource, entityMap, json, getSession, onProfileUpdated } = config;
|
|
5504
|
+
async function loadCurrentUser() {
|
|
5354
5505
|
const session = await getSession();
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5506
|
+
const su = session?.user;
|
|
5507
|
+
if (!su?.email && su?.id == null) {
|
|
5508
|
+
return { ok: false, response: json({ error: "Unauthorized" }, { status: 401 }) };
|
|
5509
|
+
}
|
|
5510
|
+
const userRepo = dataSource.getRepository(entityMap.users);
|
|
5511
|
+
let user = null;
|
|
5512
|
+
const uidRaw = su.id != null ? String(su.id).trim() : "";
|
|
5513
|
+
const uid = uidRaw && /^\d+$/.test(uidRaw) ? parseInt(uidRaw, 10) : NaN;
|
|
5514
|
+
if (Number.isFinite(uid) && uid > 0) {
|
|
5515
|
+
user = await userRepo.findOne({
|
|
5516
|
+
where: { id: uid, deleted: false },
|
|
5517
|
+
select: ["id", "name", "email", "phone", "createdAt"]
|
|
5518
|
+
});
|
|
5519
|
+
}
|
|
5520
|
+
if (!user && su.email) {
|
|
5521
|
+
const em = String(su.email).trim().toLowerCase();
|
|
5522
|
+
if (em) {
|
|
5523
|
+
user = await userRepo.findOne({
|
|
5524
|
+
where: { email: em, deleted: false },
|
|
5525
|
+
select: ["id", "name", "email", "phone", "createdAt"]
|
|
5526
|
+
});
|
|
5527
|
+
}
|
|
5528
|
+
}
|
|
5529
|
+
if (!user) return { ok: false, response: json({ error: "Not found" }, { status: 404 }) };
|
|
5530
|
+
return { ok: true, user };
|
|
5531
|
+
}
|
|
5532
|
+
return {
|
|
5533
|
+
async GET(_req) {
|
|
5534
|
+
try {
|
|
5535
|
+
const r = await loadCurrentUser();
|
|
5536
|
+
if (!r.ok) return r.response;
|
|
5537
|
+
const u = r.user;
|
|
5538
|
+
return json({
|
|
5539
|
+
id: u.id,
|
|
5540
|
+
name: u.name ?? "",
|
|
5541
|
+
email: u.email ?? "",
|
|
5542
|
+
phone: u.phone ?? null,
|
|
5543
|
+
createdAt: u.createdAt instanceof Date ? u.createdAt.toISOString() : u.createdAt ?? void 0
|
|
5544
|
+
});
|
|
5545
|
+
} catch {
|
|
5546
|
+
return json({ error: "Internal server error" }, { status: 500 });
|
|
5547
|
+
}
|
|
5548
|
+
},
|
|
5549
|
+
async PUT(req) {
|
|
5550
|
+
try {
|
|
5551
|
+
const r = await loadCurrentUser();
|
|
5552
|
+
if (!r.ok) return r.response;
|
|
5553
|
+
const current = r.user;
|
|
5554
|
+
let body;
|
|
5555
|
+
try {
|
|
5556
|
+
body = await req.json();
|
|
5557
|
+
} catch {
|
|
5558
|
+
return json({ error: "Invalid JSON" }, { status: 400 });
|
|
5559
|
+
}
|
|
5560
|
+
const name = typeof body.name === "string" ? body.name.trim() : "";
|
|
5561
|
+
if (!name) return json({ error: "Name is required" }, { status: 400 });
|
|
5562
|
+
const emailRaw = typeof body.email === "string" ? body.email.trim().toLowerCase() : "";
|
|
5563
|
+
if (!emailRaw || !PROFILE_EMAIL_RE.test(emailRaw)) {
|
|
5564
|
+
return json({ error: "Valid email is required" }, { status: 400 });
|
|
5565
|
+
}
|
|
5566
|
+
const phone = body.phone === null || body.phone === void 0 ? null : typeof body.phone === "string" ? body.phone.trim() || null : null;
|
|
5567
|
+
const userRepo = dataSource.getRepository(entityMap.users);
|
|
5568
|
+
if (emailRaw !== String(current.email ?? "").toLowerCase()) {
|
|
5569
|
+
const taken = await userRepo.findOne({
|
|
5570
|
+
where: { email: emailRaw, deleted: false },
|
|
5571
|
+
select: ["id"]
|
|
5572
|
+
});
|
|
5573
|
+
if (taken && taken.id !== current.id) {
|
|
5574
|
+
return json({ error: "Email is already in use" }, { status: 409 });
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
await userRepo.update(
|
|
5578
|
+
{ id: current.id },
|
|
5579
|
+
{
|
|
5580
|
+
name,
|
|
5581
|
+
email: emailRaw,
|
|
5582
|
+
phone,
|
|
5583
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
5584
|
+
}
|
|
5585
|
+
);
|
|
5586
|
+
const updated = await userRepo.findOne({
|
|
5587
|
+
where: { id: current.id },
|
|
5588
|
+
select: ["id", "name", "email", "phone"]
|
|
5589
|
+
});
|
|
5590
|
+
if (!updated) return json({ error: "Not found" }, { status: 404 });
|
|
5591
|
+
const row = updated;
|
|
5592
|
+
if (onProfileUpdated) {
|
|
5593
|
+
try {
|
|
5594
|
+
await onProfileUpdated(req, row);
|
|
5595
|
+
} catch {
|
|
5596
|
+
}
|
|
5597
|
+
}
|
|
5598
|
+
return json({
|
|
5599
|
+
message: "Profile updated successfully",
|
|
5600
|
+
user: { id: row.id, name: row.name, email: row.email, phone: row.phone }
|
|
5601
|
+
});
|
|
5602
|
+
} catch {
|
|
5603
|
+
return json({ error: "Internal server error" }, { status: 500 });
|
|
5604
|
+
}
|
|
5366
5605
|
}
|
|
5367
5606
|
};
|
|
5368
5607
|
}
|
|
@@ -8687,7 +8926,7 @@ function getNextAuthOptions(config) {
|
|
|
8687
8926
|
}
|
|
8688
8927
|
},
|
|
8689
8928
|
callbacks: {
|
|
8690
|
-
async jwt({ token, user }) {
|
|
8929
|
+
async jwt({ token, user, trigger, session }) {
|
|
8691
8930
|
if (user) {
|
|
8692
8931
|
const u = user;
|
|
8693
8932
|
token.id = u.id;
|
|
@@ -8696,11 +8935,19 @@ function getNextAuthOptions(config) {
|
|
|
8696
8935
|
token.entityPerms = u.entityPerms;
|
|
8697
8936
|
token.adminAccess = u.adminAccess;
|
|
8698
8937
|
}
|
|
8938
|
+
if (trigger === "update" && session && typeof session === "object") {
|
|
8939
|
+
const s = session;
|
|
8940
|
+
const t = token;
|
|
8941
|
+
if (typeof s.name === "string") t.name = s.name;
|
|
8942
|
+
if (typeof s.email === "string") t.email = s.email;
|
|
8943
|
+
}
|
|
8699
8944
|
return token;
|
|
8700
8945
|
},
|
|
8701
8946
|
async session({ session, token }) {
|
|
8702
8947
|
if (session.user) {
|
|
8703
8948
|
const t = token;
|
|
8949
|
+
if (typeof t.name === "string") session.user.name = t.name;
|
|
8950
|
+
if (typeof t.email === "string") session.user.email = t.email;
|
|
8704
8951
|
session.user.id = t.id;
|
|
8705
8952
|
session.user.groupId = t.groupId;
|
|
8706
8953
|
session.user.isRBACAdmin = t.isRBACAdmin;
|
|
@@ -8872,6 +9119,156 @@ function buildSearchWhereClause(repo, search) {
|
|
|
8872
9119
|
function entityHasSoftDelete(repo) {
|
|
8873
9120
|
return repo.metadata.columns.some((c) => c.propertyName === "deleted");
|
|
8874
9121
|
}
|
|
9122
|
+
var LIST_QUERY_RESERVED = /* @__PURE__ */ new Set(["page", "limit", "sortField", "sortOrder", "search"]);
|
|
9123
|
+
function dayStartUtc(isoDay) {
|
|
9124
|
+
return /* @__PURE__ */ new Date(isoDay + "T00:00:00.000Z");
|
|
9125
|
+
}
|
|
9126
|
+
function dayEndUtc(isoDay) {
|
|
9127
|
+
return /* @__PURE__ */ new Date(isoDay + "T23:59:59.999Z");
|
|
9128
|
+
}
|
|
9129
|
+
function columnTypeLabel(col) {
|
|
9130
|
+
const t = col.type;
|
|
9131
|
+
if (typeof t === "string") return t.toLowerCase();
|
|
9132
|
+
if (typeof t === "function") return t.name?.toLowerCase?.() ?? "";
|
|
9133
|
+
if (t && typeof t === "object" && "name" in t && typeof t.name === "string") {
|
|
9134
|
+
return String(t.name).toLowerCase();
|
|
9135
|
+
}
|
|
9136
|
+
return "";
|
|
9137
|
+
}
|
|
9138
|
+
function isListDateColumn(col) {
|
|
9139
|
+
const tl = columnTypeLabel(col);
|
|
9140
|
+
return DATE_COLUMN_TYPES.has(tl) || col.type === Date || TIMESTAMP_PROP_NAMES.has(col.propertyName);
|
|
9141
|
+
}
|
|
9142
|
+
function isListNumericColumn(col) {
|
|
9143
|
+
const tl = columnTypeLabel(col);
|
|
9144
|
+
if (col.type === Number) return true;
|
|
9145
|
+
const patterns = [
|
|
9146
|
+
"int",
|
|
9147
|
+
"integer",
|
|
9148
|
+
"int2",
|
|
9149
|
+
"int4",
|
|
9150
|
+
"int8",
|
|
9151
|
+
"smallint",
|
|
9152
|
+
"bigint",
|
|
9153
|
+
"float",
|
|
9154
|
+
"double",
|
|
9155
|
+
"decimal",
|
|
9156
|
+
"numeric",
|
|
9157
|
+
"real",
|
|
9158
|
+
"tinyint",
|
|
9159
|
+
"mediumint"
|
|
9160
|
+
];
|
|
9161
|
+
if (patterns.some((x) => tl.includes(x))) return true;
|
|
9162
|
+
if (tl.includes("unsigned") && (tl.includes("int") || tl.includes("bigint") || tl.includes("small"))) return true;
|
|
9163
|
+
if (!tl && /Id$/i.test(col.propertyName) && !TIMESTAMP_PROP_NAMES.has(col.propertyName)) return true;
|
|
9164
|
+
return false;
|
|
9165
|
+
}
|
|
9166
|
+
function isListBooleanColumn(col) {
|
|
9167
|
+
const tl = columnTypeLabel(col);
|
|
9168
|
+
return tl === "boolean" || tl === "bool" || col.type === Boolean;
|
|
9169
|
+
}
|
|
9170
|
+
function isListStringColumn(col) {
|
|
9171
|
+
const tl = columnTypeLabel(col);
|
|
9172
|
+
if (isListDateColumn(col) || isListNumericColumn(col) || isListBooleanColumn(col)) return false;
|
|
9173
|
+
if (["varchar", "character varying", "text", "citext", "uuid", "char", "character", "enum"].some(
|
|
9174
|
+
(x) => tl.includes(x)
|
|
9175
|
+
)) {
|
|
9176
|
+
return true;
|
|
9177
|
+
}
|
|
9178
|
+
if (col.type === String) return true;
|
|
9179
|
+
return false;
|
|
9180
|
+
}
|
|
9181
|
+
function mergeListWhereAnd(where, patch) {
|
|
9182
|
+
if (Object.keys(patch).length === 0) return where;
|
|
9183
|
+
if (Array.isArray(where)) {
|
|
9184
|
+
if (where.length === 0) return [patch];
|
|
9185
|
+
return where.map((w) => ({ ...w, ...patch }));
|
|
9186
|
+
}
|
|
9187
|
+
if (where && typeof where === "object" && Object.keys(where).length > 0) {
|
|
9188
|
+
return { ...where, ...patch };
|
|
9189
|
+
}
|
|
9190
|
+
return patch;
|
|
9191
|
+
}
|
|
9192
|
+
function buildListFilterAndFromSearchParams(repo, searchParams) {
|
|
9193
|
+
const and = {};
|
|
9194
|
+
const columnNames = new Set(repo.metadata.columns.map((c) => c.propertyName));
|
|
9195
|
+
for (const col of repo.metadata.columns) {
|
|
9196
|
+
const name = col.propertyName;
|
|
9197
|
+
if (!columnNames.has(name)) continue;
|
|
9198
|
+
if (name === "deleted" || name === "deletedAt" || name === "deletedBy") continue;
|
|
9199
|
+
if (!isListDateColumn(col)) continue;
|
|
9200
|
+
const from = searchParams.get(`${name}From`)?.trim();
|
|
9201
|
+
const to = searchParams.get(`${name}To`)?.trim();
|
|
9202
|
+
if (!from && !to) continue;
|
|
9203
|
+
if (from && to) {
|
|
9204
|
+
and[name] = (0, import_typeorm46.Between)(dayStartUtc(from), dayEndUtc(to));
|
|
9205
|
+
} else if (from) {
|
|
9206
|
+
and[name] = (0, import_typeorm46.MoreThanOrEqual)(dayStartUtc(from));
|
|
9207
|
+
} else if (to) {
|
|
9208
|
+
and[name] = (0, import_typeorm46.LessThanOrEqual)(dayEndUtc(to));
|
|
9209
|
+
}
|
|
9210
|
+
}
|
|
9211
|
+
for (const col of repo.metadata.columns) {
|
|
9212
|
+
const name = col.propertyName;
|
|
9213
|
+
if (!columnNames.has(name)) continue;
|
|
9214
|
+
if (name === "deleted" || name === "deletedAt" || name === "deletedBy") continue;
|
|
9215
|
+
if (!isListNumericColumn(col)) continue;
|
|
9216
|
+
if (Object.prototype.hasOwnProperty.call(and, name)) continue;
|
|
9217
|
+
const minRaw = searchParams.get(`${name}Min`)?.trim();
|
|
9218
|
+
const maxRaw = searchParams.get(`${name}Max`)?.trim();
|
|
9219
|
+
if (!minRaw && !maxRaw) continue;
|
|
9220
|
+
const parseNum = (s) => {
|
|
9221
|
+
const n = Number(s);
|
|
9222
|
+
return Number.isFinite(n) ? n : null;
|
|
9223
|
+
};
|
|
9224
|
+
const nMin = minRaw ? parseNum(minRaw) : null;
|
|
9225
|
+
const nMax = maxRaw ? parseNum(maxRaw) : null;
|
|
9226
|
+
if (nMin != null && nMax != null) {
|
|
9227
|
+
and[name] = (0, import_typeorm46.Between)(nMin, nMax);
|
|
9228
|
+
} else if (nMin != null) {
|
|
9229
|
+
and[name] = (0, import_typeorm46.MoreThanOrEqual)(nMin);
|
|
9230
|
+
} else if (nMax != null) {
|
|
9231
|
+
and[name] = (0, import_typeorm46.LessThanOrEqual)(nMax);
|
|
9232
|
+
}
|
|
9233
|
+
}
|
|
9234
|
+
for (const col of repo.metadata.columns) {
|
|
9235
|
+
const name = col.propertyName;
|
|
9236
|
+
if (!columnNames.has(name)) continue;
|
|
9237
|
+
if (LIST_QUERY_RESERVED.has(name)) continue;
|
|
9238
|
+
if (name === "deleted" || name === "deletedAt" || name === "deletedBy") continue;
|
|
9239
|
+
if (!isListStringColumn(col)) continue;
|
|
9240
|
+
if (Object.prototype.hasOwnProperty.call(and, name)) continue;
|
|
9241
|
+
const raw = searchParams.get(name)?.trim();
|
|
9242
|
+
if (!raw) continue;
|
|
9243
|
+
and[name] = (0, import_typeorm46.ILike)(`%${raw}%`);
|
|
9244
|
+
}
|
|
9245
|
+
return and;
|
|
9246
|
+
}
|
|
9247
|
+
function buildExactListParamWhere(repo, searchParams) {
|
|
9248
|
+
const extraWhere = {};
|
|
9249
|
+
const columnNames = new Set(repo.metadata.columns.map((c) => c.propertyName));
|
|
9250
|
+
for (const col of repo.metadata.columns) {
|
|
9251
|
+
const name = col.propertyName;
|
|
9252
|
+
if (!columnNames.has(name)) continue;
|
|
9253
|
+
if (name === "deleted" || name === "deletedAt" || name === "deletedBy") continue;
|
|
9254
|
+
if (!isListNumericColumn(col)) continue;
|
|
9255
|
+
const v = searchParams.get(name)?.trim();
|
|
9256
|
+
if (v == null || v === "") continue;
|
|
9257
|
+
const n = Number(v);
|
|
9258
|
+
if (!Number.isFinite(n)) continue;
|
|
9259
|
+
extraWhere[name] = n;
|
|
9260
|
+
}
|
|
9261
|
+
for (const col of repo.metadata.columns) {
|
|
9262
|
+
if (String(col.type) !== "boolean") continue;
|
|
9263
|
+
const name = col.propertyName;
|
|
9264
|
+
if (!columnNames.has(name)) continue;
|
|
9265
|
+
const raw = searchParams.get(name)?.trim();
|
|
9266
|
+
if (raw === "true" || raw === "false") {
|
|
9267
|
+
extraWhere[name] = raw === "true";
|
|
9268
|
+
}
|
|
9269
|
+
}
|
|
9270
|
+
return extraWhere;
|
|
9271
|
+
}
|
|
8875
9272
|
function mergeDeletedFalseWhere(repo, where) {
|
|
8876
9273
|
if (!entityHasSoftDelete(repo)) return where;
|
|
8877
9274
|
const d = { deleted: false };
|
|
@@ -8881,6 +9278,12 @@ function mergeDeletedFalseWhere(repo, where) {
|
|
|
8881
9278
|
}
|
|
8882
9279
|
return Object.keys(where).length > 0 ? { ...where, ...d } : d;
|
|
8883
9280
|
}
|
|
9281
|
+
function pickDefaultListSortField(columnNames, columns) {
|
|
9282
|
+
for (const candidate of ["createdAt", "updatedAt", "id", "name", "sortOrder", "title"]) {
|
|
9283
|
+
if (columnNames.has(candidate)) return candidate;
|
|
9284
|
+
}
|
|
9285
|
+
return columns[0]?.propertyName ?? "id";
|
|
9286
|
+
}
|
|
8884
9287
|
function normalizeProductSku(value) {
|
|
8885
9288
|
if (value == null) return null;
|
|
8886
9289
|
const s = String(value).trim();
|
|
@@ -8983,6 +9386,18 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
8983
9386
|
if (statusFilter) qb.andWhere("order.status = :status", { status: statusFilter });
|
|
8984
9387
|
if (dateFrom) qb.andWhere("order.createdAt >= :dateFrom", { dateFrom: /* @__PURE__ */ new Date(dateFrom + "T00:00:00.000Z") });
|
|
8985
9388
|
if (dateTo) qb.andWhere("order.createdAt <= :dateTo", { dateTo: /* @__PURE__ */ new Date(dateTo + "T23:59:59.999Z") });
|
|
9389
|
+
const totalMin = searchParams.get("totalMin")?.trim();
|
|
9390
|
+
const totalMax = searchParams.get("totalMax")?.trim();
|
|
9391
|
+
if (totalMin) {
|
|
9392
|
+
const n = Number(totalMin);
|
|
9393
|
+
if (Number.isFinite(n)) qb.andWhere("order.total >= :totalMin", { totalMin: n });
|
|
9394
|
+
}
|
|
9395
|
+
if (totalMax) {
|
|
9396
|
+
const n = Number(totalMax);
|
|
9397
|
+
if (Number.isFinite(n)) qb.andWhere("order.total <= :totalMax", { totalMax: n });
|
|
9398
|
+
}
|
|
9399
|
+
const currency = searchParams.get("currency")?.trim();
|
|
9400
|
+
if (currency) qb.andWhere("order.currency ILIKE :orderCurrency", { orderCurrency: `%${currency}%` });
|
|
8986
9401
|
if (orderIdsFromPayment && orderIdsFromPayment.length) qb.andWhere("order.id IN (:...orderIds)", { orderIds: orderIdsFromPayment });
|
|
8987
9402
|
const [rows, total2] = await qb.getManyAndCount();
|
|
8988
9403
|
const data2 = rows.map((order) => {
|
|
@@ -9021,8 +9436,30 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
9021
9436
|
if (statusFilter) qb.andWhere("payment.status = :status", { status: statusFilter });
|
|
9022
9437
|
if (dateFrom) qb.andWhere("payment.createdAt >= :dateFrom", { dateFrom: /* @__PURE__ */ new Date(dateFrom + "T00:00:00.000Z") });
|
|
9023
9438
|
if (dateTo) qb.andWhere("payment.createdAt <= :dateTo", { dateTo: /* @__PURE__ */ new Date(dateTo + "T23:59:59.999Z") });
|
|
9439
|
+
const paidAtFrom = searchParams.get("paidAtFrom")?.trim();
|
|
9440
|
+
const paidAtTo = searchParams.get("paidAtTo")?.trim();
|
|
9441
|
+
if (paidAtFrom) {
|
|
9442
|
+
qb.andWhere("payment.paidAt >= :paidAtFrom", { paidAtFrom: /* @__PURE__ */ new Date(paidAtFrom + "T00:00:00.000Z") });
|
|
9443
|
+
}
|
|
9444
|
+
if (paidAtTo) {
|
|
9445
|
+
qb.andWhere("payment.paidAt <= :paidAtTo", { paidAtTo: /* @__PURE__ */ new Date(paidAtTo + "T23:59:59.999Z") });
|
|
9446
|
+
}
|
|
9024
9447
|
if (methodFilter) qb.andWhere("payment.method = :method", { method: methodFilter });
|
|
9025
9448
|
if (orderNumberParam) qb.andWhere("ord.orderNumber ILIKE :orderNumber", { orderNumber: `%${orderNumberParam}%` });
|
|
9449
|
+
const amountMin = searchParams.get("amountMin")?.trim();
|
|
9450
|
+
const amountMax = searchParams.get("amountMax")?.trim();
|
|
9451
|
+
if (amountMin) {
|
|
9452
|
+
const n = Number(amountMin);
|
|
9453
|
+
if (Number.isFinite(n)) qb.andWhere("payment.amount >= :amountMin", { amountMin: n });
|
|
9454
|
+
}
|
|
9455
|
+
if (amountMax) {
|
|
9456
|
+
const n = Number(amountMax);
|
|
9457
|
+
if (Number.isFinite(n)) qb.andWhere("payment.amount <= :amountMax", { amountMax: n });
|
|
9458
|
+
}
|
|
9459
|
+
const extRef = searchParams.get("externalReference")?.trim();
|
|
9460
|
+
if (extRef) {
|
|
9461
|
+
qb.andWhere("payment.externalReference ILIKE :extRef", { extRef: `%${extRef}%` });
|
|
9462
|
+
}
|
|
9026
9463
|
const [rows, total2] = await qb.getManyAndCount();
|
|
9027
9464
|
const data2 = rows.map((payment) => {
|
|
9028
9465
|
const order = payment.order;
|
|
@@ -9041,7 +9478,10 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
9041
9478
|
const repo2 = dataSource.getRepository(entity);
|
|
9042
9479
|
const statusFilter = searchParams.get("status")?.trim();
|
|
9043
9480
|
const inventory = searchParams.get("inventory")?.trim();
|
|
9044
|
-
const productWhere = {
|
|
9481
|
+
const productWhere = {
|
|
9482
|
+
deleted: false,
|
|
9483
|
+
...buildListFilterAndFromSearchParams(repo2, searchParams)
|
|
9484
|
+
};
|
|
9045
9485
|
if (statusFilter) productWhere.status = statusFilter;
|
|
9046
9486
|
if (inventory === "in_stock") productWhere.quantity = (0, import_typeorm46.MoreThan)(0);
|
|
9047
9487
|
if (inventory === "out_of_stock") productWhere.quantity = 0;
|
|
@@ -9059,11 +9499,15 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
9059
9499
|
if (search && typeof search === "string" && search.trim()) {
|
|
9060
9500
|
productWhere.name = (0, import_typeorm46.ILike)(`%${search.trim()}%`);
|
|
9061
9501
|
}
|
|
9502
|
+
const productColumnNames = new Set(repo2.metadata.columns.map((c) => c.propertyName));
|
|
9503
|
+
const defaultProductSort = pickDefaultListSortField(productColumnNames, repo2.metadata.columns);
|
|
9504
|
+
const sortParam2 = (searchParams.get("sortField") ?? "").trim();
|
|
9505
|
+
const productSortField = sortParam2 && productColumnNames.has(sortParam2) ? sortParam2 : defaultProductSort;
|
|
9062
9506
|
const [data2, total2] = await repo2.findAndCount({
|
|
9063
9507
|
where: Object.keys(productWhere).length ? productWhere : void 0,
|
|
9064
9508
|
skip,
|
|
9065
9509
|
take: limit,
|
|
9066
|
-
order: { [
|
|
9510
|
+
order: { [productSortField]: sortOrder }
|
|
9067
9511
|
});
|
|
9068
9512
|
return json({ total: total2, page, limit, totalPages: Math.ceil(total2 / limit), data: data2 });
|
|
9069
9513
|
}
|
|
@@ -9156,36 +9600,22 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
9156
9600
|
}
|
|
9157
9601
|
return json({ total: total2, page, limit, totalPages: Math.ceil(total2 / limit), data: data2 });
|
|
9158
9602
|
}
|
|
9159
|
-
const
|
|
9603
|
+
const defaultSortField = pickDefaultListSortField(columnNames, repo.metadata.columns);
|
|
9604
|
+
const sortParam = (searchParams.get("sortField") ?? "").trim();
|
|
9605
|
+
const sortField = sortParam && columnNames.has(sortParam) ? sortParam : defaultSortField;
|
|
9160
9606
|
let where = {};
|
|
9161
9607
|
if (search) {
|
|
9162
9608
|
where = buildSearchWhereClause(repo, search);
|
|
9163
9609
|
}
|
|
9164
|
-
|
|
9165
|
-
const
|
|
9166
|
-
|
|
9167
|
-
const v = searchParams.get(key);
|
|
9168
|
-
if (v != null && v !== "" && columnNames.has(key)) {
|
|
9169
|
-
const n = Number(v);
|
|
9170
|
-
if (Number.isFinite(n)) extraWhere[key] = n;
|
|
9171
|
-
}
|
|
9172
|
-
}
|
|
9173
|
-
for (const col of repo.metadata.columns) {
|
|
9174
|
-
if (String(col.type) !== "boolean") continue;
|
|
9175
|
-
const name = col.propertyName;
|
|
9176
|
-
if (!columnNames.has(name)) continue;
|
|
9177
|
-
const raw = searchParams.get(name)?.trim();
|
|
9178
|
-
if (raw === "true" || raw === "false") {
|
|
9179
|
-
extraWhere[name] = raw === "true";
|
|
9180
|
-
}
|
|
9181
|
-
}
|
|
9182
|
-
if (Object.keys(extraWhere).length > 0) {
|
|
9610
|
+
where = mergeListWhereAnd(where, buildListFilterAndFromSearchParams(repo, searchParams));
|
|
9611
|
+
const exactParamWhere = buildExactListParamWhere(repo, searchParams);
|
|
9612
|
+
if (Object.keys(exactParamWhere).length > 0) {
|
|
9183
9613
|
if (Array.isArray(where)) {
|
|
9184
|
-
where = where.map((w) => ({ ...w, ...
|
|
9614
|
+
where = where.map((w) => ({ ...w, ...exactParamWhere }));
|
|
9185
9615
|
} else if (where && typeof where === "object" && Object.keys(where).length > 0) {
|
|
9186
|
-
where = { ...where, ...
|
|
9616
|
+
where = { ...where, ...exactParamWhere };
|
|
9187
9617
|
} else {
|
|
9188
|
-
where =
|
|
9618
|
+
where = exactParamWhere;
|
|
9189
9619
|
}
|
|
9190
9620
|
}
|
|
9191
9621
|
where = mergeDeletedFalseWhere(repo, where);
|
|
@@ -9265,6 +9695,10 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
9265
9695
|
}
|
|
9266
9696
|
const repo = dataSource.getRepository(entity);
|
|
9267
9697
|
const persistBody = resource === "media" ? body : pickColumnUpdates(repo, body);
|
|
9698
|
+
if (resource === "contacts" && "type" in persistBody) {
|
|
9699
|
+
const t = persistBody.type;
|
|
9700
|
+
if (t === "" || t === "none" || t == null) persistBody.type = null;
|
|
9701
|
+
}
|
|
9268
9702
|
if (resource !== "media" && Object.keys(persistBody).length === 0) {
|
|
9269
9703
|
logCrudClientError("POST create", {
|
|
9270
9704
|
reason: "no_scalar_columns_after_pick",
|
|
@@ -9615,6 +10049,10 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
9615
10049
|
if (!cur) return json({ message: "Not found" }, { status: 404 });
|
|
9616
10050
|
}
|
|
9617
10051
|
const updatePayload = rawBody && typeof rawBody === "object" ? pickColumnUpdates(repo, rawBody) : {};
|
|
10052
|
+
if (resource === "contacts" && "type" in updatePayload) {
|
|
10053
|
+
const t = updatePayload.type;
|
|
10054
|
+
if (t === "" || t === "none" || t == null) updatePayload.type = null;
|
|
10055
|
+
}
|
|
9618
10056
|
if (resource === "media") {
|
|
9619
10057
|
const u = updatePayload;
|
|
9620
10058
|
delete u.kind;
|
|
@@ -10874,7 +11312,7 @@ function createCmsApiHandler(config) {
|
|
|
10874
11312
|
} : usersApi;
|
|
10875
11313
|
const usersHandlers = usersApiMerged ? createUsersApiHandlers(mergePerm(usersApiMerged) ?? usersApiMerged) : null;
|
|
10876
11314
|
const avatarPost = userAvatar ? createUserAvatarHandler(userAvatar) : null;
|
|
10877
|
-
const
|
|
11315
|
+
const profileHandlers = userProfile ? createUserProfileHandler(userProfile) : null;
|
|
10878
11316
|
const settingsHandlers = settingsConfig ? createSettingsApiHandlers(settingsConfig) : null;
|
|
10879
11317
|
const smsMessageTemplateHandlers = createSmsMessageTemplateHandlers({
|
|
10880
11318
|
dataSource,
|
|
@@ -10973,7 +11411,10 @@ function createCmsApiHandler(config) {
|
|
|
10973
11411
|
}
|
|
10974
11412
|
if (path.length === 2) {
|
|
10975
11413
|
if (path[1] === "avatar" && m === "POST" && avatarPost) return avatarPost(req);
|
|
10976
|
-
if (path[1] === "profile" &&
|
|
11414
|
+
if (path[1] === "profile" && profileHandlers) {
|
|
11415
|
+
if (m === "GET") return profileHandlers.GET(req);
|
|
11416
|
+
if (m === "PUT") return profileHandlers.PUT(req);
|
|
11417
|
+
}
|
|
10977
11418
|
const id = path[1];
|
|
10978
11419
|
if (m === "GET") return usersHandlers.getById(req, id);
|
|
10979
11420
|
if (m === "PUT" || m === "PATCH") return usersHandlers.update(req, id);
|