@sonicjs-cms/core 2.2.0 → 2.3.1
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 +75 -1
- package/dist/app-Db0AfT5F.d.cts +100 -0
- package/dist/app-Db0AfT5F.d.ts +100 -0
- package/dist/chunk-23VPL6VI.cjs +1828 -0
- package/dist/chunk-23VPL6VI.cjs.map +1 -0
- package/dist/chunk-3MPQII4R.js +1826 -0
- package/dist/chunk-3MPQII4R.js.map +1 -0
- package/dist/{chunk-YTMFJLJZ.cjs → chunk-44LBCF3B.cjs} +5 -3
- package/dist/chunk-44LBCF3B.cjs.map +1 -0
- package/dist/{chunk-2DIWLDCA.cjs → chunk-5QJX2VMP.cjs} +541 -533
- package/dist/chunk-5QJX2VMP.cjs.map +1 -0
- package/dist/{chunk-UEYMFNBN.cjs → chunk-5UUYHAZT.cjs} +7 -36
- package/dist/chunk-5UUYHAZT.cjs.map +1 -0
- package/dist/{chunk-ZUK55KZB.js → chunk-6RJU7HL5.js} +5 -3
- package/dist/chunk-6RJU7HL5.js.map +1 -0
- package/dist/{chunk-K4Z3IHOK.js → chunk-7CXL5K7N.js} +5 -248
- package/dist/chunk-7CXL5K7N.js.map +1 -0
- package/dist/{chunk-WBX5YMTB.cjs → chunk-7KCDFDRI.cjs} +27 -15
- package/dist/chunk-7KCDFDRI.cjs.map +1 -0
- package/dist/{chunk-HKEK7UNV.js → chunk-CPXAVWCU.js} +3 -3
- package/dist/{chunk-HKEK7UNV.js.map → chunk-CPXAVWCU.js.map} +1 -1
- package/dist/{chunk-F5ESJXI2.cjs → chunk-DTLB6UIH.cjs} +3 -3
- package/dist/{chunk-F5ESJXI2.cjs.map → chunk-DTLB6UIH.cjs.map} +1 -1
- package/dist/{chunk-AINTFRTC.cjs → chunk-ES3BRZQJ.cjs} +252 -2
- package/dist/chunk-ES3BRZQJ.cjs.map +1 -0
- package/dist/{chunk-HV2I6API.cjs → chunk-NAYD76QF.cjs} +4 -251
- package/dist/chunk-NAYD76QF.cjs.map +1 -0
- package/dist/{chunk-L232U757.js → chunk-Q52ZQFMB.js} +249 -3
- package/dist/chunk-Q52ZQFMB.js.map +1 -0
- package/dist/{chunk-NMVOTNSL.js → chunk-RRKXFGIO.js} +28 -16
- package/dist/chunk-RRKXFGIO.js.map +1 -0
- package/dist/{chunk-OORGXYDA.js → chunk-WK5EUGBO.js} +5 -32
- package/dist/chunk-WK5EUGBO.js.map +1 -0
- package/dist/{chunk-R57VFNP3.js → chunk-ZPERJATF.js} +441 -433
- package/dist/chunk-ZPERJATF.js.map +1 -0
- package/dist/collection-config-FLlGtsh9.d.cts +107 -0
- package/dist/collection-config-FLlGtsh9.d.ts +107 -0
- package/dist/filter-bar.template-By4jeiw_.d.cts +140 -0
- package/dist/filter-bar.template-By4jeiw_.d.ts +140 -0
- package/dist/index.cjs +146 -165
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -0
- package/dist/index.d.ts +43 -5
- package/dist/index.js +19 -14
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +24 -33
- package/dist/middleware.d.cts +89 -0
- package/dist/middleware.d.ts +89 -2
- package/dist/middleware.js +3 -4
- package/dist/migrations-CCLAGJGP.js +4 -0
- package/dist/{migrations-IHERIQVD.js.map → migrations-CCLAGJGP.js.map} +1 -1
- package/dist/migrations-O6INOHRD.cjs +13 -0
- package/dist/{migrations-POFD5KNG.cjs.map → migrations-O6INOHRD.cjs.map} +1 -1
- package/dist/plugin-bootstrap-C0E3jdz-.d.cts +8339 -0
- package/dist/plugin-bootstrap-CDh0JHtW.d.ts +8339 -0
- package/dist/plugin-manifest-BCMx9CAq.d.cts +35 -0
- package/dist/plugin-manifest-BCMx9CAq.d.ts +35 -0
- package/dist/plugin-zvZpaiP5.d.cts +357 -0
- package/dist/plugin-zvZpaiP5.d.ts +357 -0
- package/dist/plugins.cjs +7 -7
- package/dist/plugins.d.cts +330 -0
- package/dist/plugins.d.ts +330 -2
- package/dist/plugins.js +1 -1
- package/dist/routes.cjs +27 -27
- package/dist/routes.d.cts +224 -0
- package/dist/routes.d.ts +224 -2
- package/dist/routes.js +7 -7
- package/dist/services.cjs +41 -41
- package/dist/services.d.cts +236 -0
- package/dist/services.d.ts +236 -2
- package/dist/services.js +4 -4
- package/dist/telemetry-BFBIjBxK.d.cts +36 -0
- package/dist/telemetry-BFBIjBxK.d.ts +36 -0
- package/dist/templates.d.cts +133 -0
- package/dist/templates.d.ts +133 -2
- package/dist/types.d.cts +7 -0
- package/dist/types.d.ts +7 -2
- package/dist/utils.cjs +27 -27
- package/dist/utils.d.cts +53 -0
- package/dist/utils.d.ts +53 -2
- package/dist/utils.js +2 -2
- package/dist/version-vktVAxhe.d.cts +195 -0
- package/dist/version-vktVAxhe.d.ts +195 -0
- package/migrations/001_initial_schema.sql +1 -1
- package/migrations/002_faq_plugin.sql +86 -0
- package/package.json +3 -1
- package/dist/chunk-2DIWLDCA.cjs.map +0 -1
- package/dist/chunk-AINTFRTC.cjs.map +0 -1
- package/dist/chunk-HV2I6API.cjs.map +0 -1
- package/dist/chunk-K4Z3IHOK.js.map +0 -1
- package/dist/chunk-L232U757.js.map +0 -1
- package/dist/chunk-NMVOTNSL.js.map +0 -1
- package/dist/chunk-OORGXYDA.js.map +0 -1
- package/dist/chunk-R57VFNP3.js.map +0 -1
- package/dist/chunk-T7IYBGGO.cjs +0 -746
- package/dist/chunk-T7IYBGGO.cjs.map +0 -1
- package/dist/chunk-UEYMFNBN.cjs.map +0 -1
- package/dist/chunk-WBX5YMTB.cjs.map +0 -1
- package/dist/chunk-YTMFJLJZ.cjs.map +0 -1
- package/dist/chunk-ZPMFT2JW.js +0 -744
- package/dist/chunk-ZPMFT2JW.js.map +0 -1
- package/dist/chunk-ZUK55KZB.js.map +0 -1
- package/dist/migrations-IHERIQVD.js +0 -4
- package/dist/migrations-POFD5KNG.cjs +0 -13
- /package/migrations/{021_add_otp_login.sql → 026_add_otp_login.sql} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
3
|
+
var chunkES3BRZQJ_cjs = require('./chunk-ES3BRZQJ.cjs');
|
|
4
|
+
var chunk5UUYHAZT_cjs = require('./chunk-5UUYHAZT.cjs');
|
|
5
|
+
var chunkNAYD76QF_cjs = require('./chunk-NAYD76QF.cjs');
|
|
6
|
+
var chunk23VPL6VI_cjs = require('./chunk-23VPL6VI.cjs');
|
|
7
7
|
var chunkYU6QFFI4_cjs = require('./chunk-YU6QFFI4.cjs');
|
|
8
|
-
var
|
|
8
|
+
var chunk44LBCF3B_cjs = require('./chunk-44LBCF3B.cjs');
|
|
9
9
|
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
10
10
|
var hono = require('hono');
|
|
11
11
|
var cors = require('hono/cors');
|
|
@@ -19,8 +19,8 @@ var apiContentCrudRoutes = new hono.Hono();
|
|
|
19
19
|
apiContentCrudRoutes.get("/:id", async (c) => {
|
|
20
20
|
try {
|
|
21
21
|
const id = c.req.param("id");
|
|
22
|
-
const
|
|
23
|
-
const stmt =
|
|
22
|
+
const db = c.env.DB;
|
|
23
|
+
const stmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
24
24
|
const content = await stmt.bind(id).first();
|
|
25
25
|
if (!content) {
|
|
26
26
|
return c.json({ error: "Content not found" }, 404);
|
|
@@ -44,9 +44,9 @@ apiContentCrudRoutes.get("/:id", async (c) => {
|
|
|
44
44
|
}, 500);
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
|
-
apiContentCrudRoutes.post("/",
|
|
47
|
+
apiContentCrudRoutes.post("/", chunk5UUYHAZT_cjs.requireAuth(), async (c) => {
|
|
48
48
|
try {
|
|
49
|
-
const
|
|
49
|
+
const db = c.env.DB;
|
|
50
50
|
const user = c.get("user");
|
|
51
51
|
const body = await c.req.json();
|
|
52
52
|
const { collectionId, title, slug, status, data } = body;
|
|
@@ -58,7 +58,7 @@ apiContentCrudRoutes.post("/", chunkUEYMFNBN_cjs.requireAuth(), async (c) => {
|
|
|
58
58
|
}
|
|
59
59
|
let finalSlug = slug || title;
|
|
60
60
|
finalSlug = finalSlug.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
|
|
61
|
-
const duplicateCheck =
|
|
61
|
+
const duplicateCheck = db.prepare(
|
|
62
62
|
"SELECT id FROM content WHERE collection_id = ? AND slug = ?"
|
|
63
63
|
);
|
|
64
64
|
const existing = await duplicateCheck.bind(collectionId, finalSlug).first();
|
|
@@ -67,7 +67,7 @@ apiContentCrudRoutes.post("/", chunkUEYMFNBN_cjs.requireAuth(), async (c) => {
|
|
|
67
67
|
}
|
|
68
68
|
const contentId = crypto.randomUUID();
|
|
69
69
|
const now = Date.now();
|
|
70
|
-
const insertStmt =
|
|
70
|
+
const insertStmt = db.prepare(`
|
|
71
71
|
INSERT INTO content (
|
|
72
72
|
id, collection_id, slug, title, data, status,
|
|
73
73
|
author_id, created_at, updated_at
|
|
@@ -85,10 +85,10 @@ apiContentCrudRoutes.post("/", chunkUEYMFNBN_cjs.requireAuth(), async (c) => {
|
|
|
85
85
|
now,
|
|
86
86
|
now
|
|
87
87
|
).run();
|
|
88
|
-
const cache =
|
|
88
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.api);
|
|
89
89
|
await cache.invalidate(`content:list:${collectionId}:*`);
|
|
90
90
|
await cache.invalidate("content-filtered:*");
|
|
91
|
-
const getStmt =
|
|
91
|
+
const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
92
92
|
const createdContent = await getStmt.bind(contentId).first();
|
|
93
93
|
return c.json({
|
|
94
94
|
data: {
|
|
@@ -110,12 +110,12 @@ apiContentCrudRoutes.post("/", chunkUEYMFNBN_cjs.requireAuth(), async (c) => {
|
|
|
110
110
|
}, 500);
|
|
111
111
|
}
|
|
112
112
|
});
|
|
113
|
-
apiContentCrudRoutes.put("/:id",
|
|
113
|
+
apiContentCrudRoutes.put("/:id", chunk5UUYHAZT_cjs.requireAuth(), async (c) => {
|
|
114
114
|
try {
|
|
115
115
|
const id = c.req.param("id");
|
|
116
|
-
const
|
|
116
|
+
const db = c.env.DB;
|
|
117
117
|
const body = await c.req.json();
|
|
118
|
-
const existingStmt =
|
|
118
|
+
const existingStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
119
119
|
const existing = await existingStmt.bind(id).first();
|
|
120
120
|
if (!existing) {
|
|
121
121
|
return c.json({ error: "Content not found" }, 404);
|
|
@@ -143,16 +143,16 @@ apiContentCrudRoutes.put("/:id", chunkUEYMFNBN_cjs.requireAuth(), async (c) => {
|
|
|
143
143
|
updates.push("updated_at = ?");
|
|
144
144
|
params.push(now);
|
|
145
145
|
params.push(id);
|
|
146
|
-
const updateStmt =
|
|
146
|
+
const updateStmt = db.prepare(`
|
|
147
147
|
UPDATE content SET ${updates.join(", ")}
|
|
148
148
|
WHERE id = ?
|
|
149
149
|
`);
|
|
150
150
|
await updateStmt.bind(...params).run();
|
|
151
|
-
const cache =
|
|
151
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.api);
|
|
152
152
|
await cache.delete(cache.generateKey("content", id));
|
|
153
153
|
await cache.invalidate(`content:list:${existing.collection_id}:*`);
|
|
154
154
|
await cache.invalidate("content-filtered:*");
|
|
155
|
-
const getStmt =
|
|
155
|
+
const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
156
156
|
const updatedContent = await getStmt.bind(id).first();
|
|
157
157
|
return c.json({
|
|
158
158
|
data: {
|
|
@@ -174,18 +174,18 @@ apiContentCrudRoutes.put("/:id", chunkUEYMFNBN_cjs.requireAuth(), async (c) => {
|
|
|
174
174
|
}, 500);
|
|
175
175
|
}
|
|
176
176
|
});
|
|
177
|
-
apiContentCrudRoutes.delete("/:id",
|
|
177
|
+
apiContentCrudRoutes.delete("/:id", chunk5UUYHAZT_cjs.requireAuth(), async (c) => {
|
|
178
178
|
try {
|
|
179
179
|
const id = c.req.param("id");
|
|
180
|
-
const
|
|
181
|
-
const existingStmt =
|
|
180
|
+
const db = c.env.DB;
|
|
181
|
+
const existingStmt = db.prepare("SELECT collection_id FROM content WHERE id = ?");
|
|
182
182
|
const existing = await existingStmt.bind(id).first();
|
|
183
183
|
if (!existing) {
|
|
184
184
|
return c.json({ error: "Content not found" }, 404);
|
|
185
185
|
}
|
|
186
|
-
const deleteStmt =
|
|
186
|
+
const deleteStmt = db.prepare("DELETE FROM content WHERE id = ?");
|
|
187
187
|
await deleteStmt.bind(id).run();
|
|
188
|
-
const cache =
|
|
188
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.api);
|
|
189
189
|
await cache.delete(cache.generateKey("content", id));
|
|
190
190
|
await cache.invalidate(`content:list:${existing.collection_id}:*`);
|
|
191
191
|
await cache.invalidate("content-filtered:*");
|
|
@@ -210,7 +210,7 @@ apiRoutes.use("*", async (c, next) => {
|
|
|
210
210
|
c.header("X-Response-Time", `${totalTime}ms`);
|
|
211
211
|
});
|
|
212
212
|
apiRoutes.use("*", async (c, next) => {
|
|
213
|
-
const cacheEnabled = await
|
|
213
|
+
const cacheEnabled = await chunk5UUYHAZT_cjs.isPluginActive(c.env.DB, "core-cache");
|
|
214
214
|
c.set("cacheEnabled", cacheEnabled);
|
|
215
215
|
await next();
|
|
216
216
|
});
|
|
@@ -256,9 +256,9 @@ apiRoutes.get("/health", (c) => {
|
|
|
256
256
|
apiRoutes.get("/collections", async (c) => {
|
|
257
257
|
const executionStart = Date.now();
|
|
258
258
|
try {
|
|
259
|
-
const
|
|
259
|
+
const db = c.env.DB;
|
|
260
260
|
const cacheEnabled = c.get("cacheEnabled");
|
|
261
|
-
const cache =
|
|
261
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.api);
|
|
262
262
|
const cacheKey = cache.generateKey("collections", "all");
|
|
263
263
|
if (cacheEnabled) {
|
|
264
264
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -284,7 +284,7 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
284
284
|
}
|
|
285
285
|
c.header("X-Cache-Status", "MISS");
|
|
286
286
|
c.header("X-Cache-Source", "database");
|
|
287
|
-
const stmt =
|
|
287
|
+
const stmt = db.prepare("SELECT * FROM collections WHERE is_active = 1");
|
|
288
288
|
const { results } = await stmt.all();
|
|
289
289
|
const transformedResults = results.map((row) => ({
|
|
290
290
|
...row,
|
|
@@ -315,11 +315,11 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
315
315
|
apiRoutes.get("/content", async (c) => {
|
|
316
316
|
const executionStart = Date.now();
|
|
317
317
|
try {
|
|
318
|
-
const
|
|
318
|
+
const db = c.env.DB;
|
|
319
319
|
const queryParams = c.req.query();
|
|
320
320
|
if (queryParams.collection) {
|
|
321
321
|
const collectionName = queryParams.collection;
|
|
322
|
-
const collectionStmt =
|
|
322
|
+
const collectionStmt = db.prepare("SELECT id FROM collections WHERE name = ? AND is_active = 1");
|
|
323
323
|
const collectionResult = await collectionStmt.bind(collectionName).first();
|
|
324
324
|
if (collectionResult) {
|
|
325
325
|
queryParams.collection_id = collectionResult.id;
|
|
@@ -335,12 +335,12 @@ apiRoutes.get("/content", async (c) => {
|
|
|
335
335
|
});
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
|
-
const filter =
|
|
338
|
+
const filter = chunk44LBCF3B_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
339
339
|
if (!filter.limit) {
|
|
340
340
|
filter.limit = 50;
|
|
341
341
|
}
|
|
342
342
|
filter.limit = Math.min(filter.limit, 1e3);
|
|
343
|
-
const builder3 = new
|
|
343
|
+
const builder3 = new chunk44LBCF3B_cjs.QueryFilterBuilder();
|
|
344
344
|
const queryResult = builder3.build("content", filter);
|
|
345
345
|
if (queryResult.errors.length > 0) {
|
|
346
346
|
return c.json({
|
|
@@ -349,7 +349,7 @@ apiRoutes.get("/content", async (c) => {
|
|
|
349
349
|
}, 400);
|
|
350
350
|
}
|
|
351
351
|
const cacheEnabled = c.get("cacheEnabled");
|
|
352
|
-
const cache =
|
|
352
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.api);
|
|
353
353
|
const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter, query: queryResult.sql }));
|
|
354
354
|
if (cacheEnabled) {
|
|
355
355
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -375,7 +375,7 @@ apiRoutes.get("/content", async (c) => {
|
|
|
375
375
|
}
|
|
376
376
|
c.header("X-Cache-Status", "MISS");
|
|
377
377
|
c.header("X-Cache-Source", "database");
|
|
378
|
-
const stmt =
|
|
378
|
+
const stmt = db.prepare(queryResult.sql);
|
|
379
379
|
const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
|
|
380
380
|
const { results } = await boundStmt.all();
|
|
381
381
|
const transformedResults = results.map((row) => ({
|
|
@@ -420,14 +420,14 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
420
420
|
const executionStart = Date.now();
|
|
421
421
|
try {
|
|
422
422
|
const collection = c.req.param("collection");
|
|
423
|
-
const
|
|
423
|
+
const db = c.env.DB;
|
|
424
424
|
const queryParams = c.req.query();
|
|
425
|
-
const collectionStmt =
|
|
425
|
+
const collectionStmt = db.prepare("SELECT * FROM collections WHERE name = ? AND is_active = 1");
|
|
426
426
|
const collectionResult = await collectionStmt.bind(collection).first();
|
|
427
427
|
if (!collectionResult) {
|
|
428
428
|
return c.json({ error: "Collection not found" }, 404);
|
|
429
429
|
}
|
|
430
|
-
const filter =
|
|
430
|
+
const filter = chunk44LBCF3B_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
431
431
|
if (!filter.where) {
|
|
432
432
|
filter.where = { and: [] };
|
|
433
433
|
}
|
|
@@ -443,7 +443,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
443
443
|
filter.limit = 50;
|
|
444
444
|
}
|
|
445
445
|
filter.limit = Math.min(filter.limit, 1e3);
|
|
446
|
-
const builder3 = new
|
|
446
|
+
const builder3 = new chunk44LBCF3B_cjs.QueryFilterBuilder();
|
|
447
447
|
const queryResult = builder3.build("content", filter);
|
|
448
448
|
if (queryResult.errors.length > 0) {
|
|
449
449
|
return c.json({
|
|
@@ -452,7 +452,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
452
452
|
}, 400);
|
|
453
453
|
}
|
|
454
454
|
const cacheEnabled = c.get("cacheEnabled");
|
|
455
|
-
const cache =
|
|
455
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.api);
|
|
456
456
|
const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter, query: queryResult.sql })}`);
|
|
457
457
|
if (cacheEnabled) {
|
|
458
458
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -478,7 +478,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
478
478
|
}
|
|
479
479
|
c.header("X-Cache-Status", "MISS");
|
|
480
480
|
c.header("X-Cache-Source", "database");
|
|
481
|
-
const stmt =
|
|
481
|
+
const stmt = db.prepare(queryResult.sql);
|
|
482
482
|
const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
|
|
483
483
|
const { results } = await boundStmt.all();
|
|
484
484
|
const transformedResults = results.map((row) => ({
|
|
@@ -568,7 +568,7 @@ var fileValidationSchema = zod.z.object({
|
|
|
568
568
|
// 50MB max
|
|
569
569
|
});
|
|
570
570
|
var apiMediaRoutes = new hono.Hono();
|
|
571
|
-
apiMediaRoutes.use("*",
|
|
571
|
+
apiMediaRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
572
572
|
apiMediaRoutes.post("/upload", async (c) => {
|
|
573
573
|
try {
|
|
574
574
|
const user = c.get("user");
|
|
@@ -1242,20 +1242,20 @@ apiSystemRoutes.get("/info", (c) => {
|
|
|
1242
1242
|
});
|
|
1243
1243
|
apiSystemRoutes.get("/stats", async (c) => {
|
|
1244
1244
|
try {
|
|
1245
|
-
const
|
|
1246
|
-
const contentStats = await
|
|
1245
|
+
const db = c.env.DB;
|
|
1246
|
+
const contentStats = await db.prepare(`
|
|
1247
1247
|
SELECT COUNT(*) as total_content
|
|
1248
1248
|
FROM content
|
|
1249
1249
|
WHERE deleted_at IS NULL
|
|
1250
1250
|
`).first();
|
|
1251
|
-
const mediaStats = await
|
|
1251
|
+
const mediaStats = await db.prepare(`
|
|
1252
1252
|
SELECT
|
|
1253
1253
|
COUNT(*) as total_files,
|
|
1254
1254
|
SUM(size) as total_size
|
|
1255
1255
|
FROM media
|
|
1256
1256
|
WHERE deleted_at IS NULL
|
|
1257
1257
|
`).first();
|
|
1258
|
-
const userStats = await
|
|
1258
|
+
const userStats = await db.prepare(`
|
|
1259
1259
|
SELECT COUNT(*) as total_users
|
|
1260
1260
|
FROM users
|
|
1261
1261
|
`).first();
|
|
@@ -1312,14 +1312,14 @@ apiSystemRoutes.get("/env", (c) => {
|
|
|
1312
1312
|
});
|
|
1313
1313
|
var api_system_default = apiSystemRoutes;
|
|
1314
1314
|
var adminApiRoutes = new hono.Hono();
|
|
1315
|
-
adminApiRoutes.use("*",
|
|
1316
|
-
adminApiRoutes.use("*",
|
|
1315
|
+
adminApiRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
1316
|
+
adminApiRoutes.use("*", chunk5UUYHAZT_cjs.requireRole(["admin", "editor"]));
|
|
1317
1317
|
adminApiRoutes.get("/stats", async (c) => {
|
|
1318
1318
|
try {
|
|
1319
|
-
const
|
|
1319
|
+
const db = c.env.DB;
|
|
1320
1320
|
let collectionsCount = 0;
|
|
1321
1321
|
try {
|
|
1322
|
-
const collectionsStmt =
|
|
1322
|
+
const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
|
|
1323
1323
|
const collectionsResult = await collectionsStmt.first();
|
|
1324
1324
|
collectionsCount = collectionsResult?.count || 0;
|
|
1325
1325
|
} catch (error) {
|
|
@@ -1327,7 +1327,7 @@ adminApiRoutes.get("/stats", async (c) => {
|
|
|
1327
1327
|
}
|
|
1328
1328
|
let contentCount = 0;
|
|
1329
1329
|
try {
|
|
1330
|
-
const contentStmt =
|
|
1330
|
+
const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE deleted_at IS NULL");
|
|
1331
1331
|
const contentResult = await contentStmt.first();
|
|
1332
1332
|
contentCount = contentResult?.count || 0;
|
|
1333
1333
|
} catch (error) {
|
|
@@ -1336,7 +1336,7 @@ adminApiRoutes.get("/stats", async (c) => {
|
|
|
1336
1336
|
let mediaCount = 0;
|
|
1337
1337
|
let mediaSize = 0;
|
|
1338
1338
|
try {
|
|
1339
|
-
const mediaStmt =
|
|
1339
|
+
const mediaStmt = db.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
|
|
1340
1340
|
const mediaResult = await mediaStmt.first();
|
|
1341
1341
|
mediaCount = mediaResult?.count || 0;
|
|
1342
1342
|
mediaSize = mediaResult?.total_size || 0;
|
|
@@ -1345,7 +1345,7 @@ adminApiRoutes.get("/stats", async (c) => {
|
|
|
1345
1345
|
}
|
|
1346
1346
|
let usersCount = 0;
|
|
1347
1347
|
try {
|
|
1348
|
-
const usersStmt =
|
|
1348
|
+
const usersStmt = db.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
|
|
1349
1349
|
const usersResult = await usersStmt.first();
|
|
1350
1350
|
usersCount = usersResult?.count || 0;
|
|
1351
1351
|
} catch (error) {
|
|
@@ -1366,17 +1366,17 @@ adminApiRoutes.get("/stats", async (c) => {
|
|
|
1366
1366
|
});
|
|
1367
1367
|
adminApiRoutes.get("/storage", async (c) => {
|
|
1368
1368
|
try {
|
|
1369
|
-
const
|
|
1369
|
+
const db = c.env.DB;
|
|
1370
1370
|
let databaseSize = 0;
|
|
1371
1371
|
try {
|
|
1372
|
-
const result = await
|
|
1372
|
+
const result = await db.prepare("SELECT 1").run();
|
|
1373
1373
|
databaseSize = result?.meta?.size_after || 0;
|
|
1374
1374
|
} catch (error) {
|
|
1375
1375
|
console.error("Error fetching database size:", error);
|
|
1376
1376
|
}
|
|
1377
1377
|
let mediaSize = 0;
|
|
1378
1378
|
try {
|
|
1379
|
-
const mediaStmt =
|
|
1379
|
+
const mediaStmt = db.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
|
|
1380
1380
|
const mediaResult = await mediaStmt.first();
|
|
1381
1381
|
mediaSize = mediaResult?.total_size || 0;
|
|
1382
1382
|
} catch (error) {
|
|
@@ -1395,9 +1395,9 @@ adminApiRoutes.get("/storage", async (c) => {
|
|
|
1395
1395
|
});
|
|
1396
1396
|
adminApiRoutes.get("/activity", async (c) => {
|
|
1397
1397
|
try {
|
|
1398
|
-
const
|
|
1398
|
+
const db = c.env.DB;
|
|
1399
1399
|
const limit = parseInt(c.req.query("limit") || "10");
|
|
1400
|
-
const activityStmt =
|
|
1400
|
+
const activityStmt = db.prepare(`
|
|
1401
1401
|
SELECT
|
|
1402
1402
|
a.id,
|
|
1403
1403
|
a.action,
|
|
@@ -1459,13 +1459,13 @@ var updateCollectionSchema = zod.z.object({
|
|
|
1459
1459
|
});
|
|
1460
1460
|
adminApiRoutes.get("/collections", async (c) => {
|
|
1461
1461
|
try {
|
|
1462
|
-
const
|
|
1462
|
+
const db = c.env.DB;
|
|
1463
1463
|
const search = c.req.query("search") || "";
|
|
1464
1464
|
const includeInactive = c.req.query("includeInactive") === "true";
|
|
1465
1465
|
let stmt;
|
|
1466
1466
|
let results;
|
|
1467
1467
|
if (search) {
|
|
1468
|
-
stmt =
|
|
1468
|
+
stmt = db.prepare(`
|
|
1469
1469
|
SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
|
|
1470
1470
|
FROM collections
|
|
1471
1471
|
WHERE ${includeInactive ? "1=1" : "is_active = 1"}
|
|
@@ -1476,7 +1476,7 @@ adminApiRoutes.get("/collections", async (c) => {
|
|
|
1476
1476
|
const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all();
|
|
1477
1477
|
results = queryResults.results;
|
|
1478
1478
|
} else {
|
|
1479
|
-
stmt =
|
|
1479
|
+
stmt = db.prepare(`
|
|
1480
1480
|
SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
|
|
1481
1481
|
FROM collections
|
|
1482
1482
|
${includeInactive ? "" : "WHERE is_active = 1"}
|
|
@@ -1485,7 +1485,7 @@ adminApiRoutes.get("/collections", async (c) => {
|
|
|
1485
1485
|
const queryResults = await stmt.all();
|
|
1486
1486
|
results = queryResults.results;
|
|
1487
1487
|
}
|
|
1488
|
-
const fieldCountStmt =
|
|
1488
|
+
const fieldCountStmt = db.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
|
|
1489
1489
|
const { results: fieldCountResults } = await fieldCountStmt.all();
|
|
1490
1490
|
const fieldCounts = new Map((fieldCountResults || []).map((row) => [String(row.collection_id), Number(row.count)]));
|
|
1491
1491
|
const collections = (results || []).map((row) => ({
|
|
@@ -1512,13 +1512,13 @@ adminApiRoutes.get("/collections", async (c) => {
|
|
|
1512
1512
|
adminApiRoutes.get("/collections/:id", async (c) => {
|
|
1513
1513
|
try {
|
|
1514
1514
|
const id = c.req.param("id");
|
|
1515
|
-
const
|
|
1516
|
-
const stmt =
|
|
1515
|
+
const db = c.env.DB;
|
|
1516
|
+
const stmt = db.prepare("SELECT * FROM collections WHERE id = ?");
|
|
1517
1517
|
const collection = await stmt.bind(id).first();
|
|
1518
1518
|
if (!collection) {
|
|
1519
1519
|
return c.json({ error: "Collection not found" }, 404);
|
|
1520
1520
|
}
|
|
1521
|
-
const fieldsStmt =
|
|
1521
|
+
const fieldsStmt = db.prepare(`
|
|
1522
1522
|
SELECT * FROM content_fields
|
|
1523
1523
|
WHERE collection_id = ?
|
|
1524
1524
|
ORDER BY field_order ASC
|
|
@@ -1567,13 +1567,13 @@ adminApiRoutes.post("/collections", async (c) => {
|
|
|
1567
1567
|
}
|
|
1568
1568
|
const validation = createCollectionSchema.safeParse(body);
|
|
1569
1569
|
if (!validation.success) {
|
|
1570
|
-
return c.json({ error: "Validation failed", details: validation.error.
|
|
1570
|
+
return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
|
|
1571
1571
|
}
|
|
1572
1572
|
const validatedData = validation.data;
|
|
1573
|
-
const
|
|
1573
|
+
const db = c.env.DB;
|
|
1574
1574
|
const ____user = c.get("user");
|
|
1575
1575
|
const displayName = validatedData.displayName || validatedData.display_name || "";
|
|
1576
|
-
const existingStmt =
|
|
1576
|
+
const existingStmt = db.prepare("SELECT id FROM collections WHERE name = ?");
|
|
1577
1577
|
const existing = await existingStmt.bind(validatedData.name).first();
|
|
1578
1578
|
if (existing) {
|
|
1579
1579
|
return c.json({ error: "A collection with this name already exists" }, 400);
|
|
@@ -1602,7 +1602,7 @@ adminApiRoutes.post("/collections", async (c) => {
|
|
|
1602
1602
|
};
|
|
1603
1603
|
const collectionId = crypto.randomUUID();
|
|
1604
1604
|
const now = Date.now();
|
|
1605
|
-
const insertStmt =
|
|
1605
|
+
const insertStmt = db.prepare(`
|
|
1606
1606
|
INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)
|
|
1607
1607
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
1608
1608
|
`);
|
|
@@ -1641,11 +1641,11 @@ adminApiRoutes.patch("/collections/:id", async (c) => {
|
|
|
1641
1641
|
const body = await c.req.json();
|
|
1642
1642
|
const validation = updateCollectionSchema.safeParse(body);
|
|
1643
1643
|
if (!validation.success) {
|
|
1644
|
-
return c.json({ error: "Validation failed", details: validation.error.
|
|
1644
|
+
return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
|
|
1645
1645
|
}
|
|
1646
1646
|
const validatedData = validation.data;
|
|
1647
|
-
const
|
|
1648
|
-
const checkStmt =
|
|
1647
|
+
const db = c.env.DB;
|
|
1648
|
+
const checkStmt = db.prepare("SELECT * FROM collections WHERE id = ?");
|
|
1649
1649
|
const existing = await checkStmt.bind(id).first();
|
|
1650
1650
|
if (!existing) {
|
|
1651
1651
|
return c.json({ error: "Collection not found" }, 404);
|
|
@@ -1670,7 +1670,7 @@ adminApiRoutes.patch("/collections/:id", async (c) => {
|
|
|
1670
1670
|
updateFields.push("updated_at = ?");
|
|
1671
1671
|
updateParams.push(Date.now());
|
|
1672
1672
|
updateParams.push(id);
|
|
1673
|
-
const updateStmt =
|
|
1673
|
+
const updateStmt = db.prepare(`
|
|
1674
1674
|
UPDATE collections
|
|
1675
1675
|
SET ${updateFields.join(", ")}
|
|
1676
1676
|
WHERE id = ?
|
|
@@ -1691,22 +1691,22 @@ adminApiRoutes.patch("/collections/:id", async (c) => {
|
|
|
1691
1691
|
adminApiRoutes.delete("/collections/:id", async (c) => {
|
|
1692
1692
|
try {
|
|
1693
1693
|
const id = c.req.param("id");
|
|
1694
|
-
const
|
|
1695
|
-
const collectionStmt =
|
|
1694
|
+
const db = c.env.DB;
|
|
1695
|
+
const collectionStmt = db.prepare("SELECT name FROM collections WHERE id = ?");
|
|
1696
1696
|
const collection = await collectionStmt.bind(id).first();
|
|
1697
1697
|
if (!collection) {
|
|
1698
1698
|
return c.json({ error: "Collection not found" }, 404);
|
|
1699
1699
|
}
|
|
1700
|
-
const contentStmt =
|
|
1700
|
+
const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
|
|
1701
1701
|
const contentResult = await contentStmt.bind(id).first();
|
|
1702
1702
|
if (contentResult && contentResult.count > 0) {
|
|
1703
1703
|
return c.json({
|
|
1704
1704
|
error: `Cannot delete collection: it contains ${contentResult.count} content item(s). Delete all content first.`
|
|
1705
1705
|
}, 400);
|
|
1706
1706
|
}
|
|
1707
|
-
const deleteFieldsStmt =
|
|
1707
|
+
const deleteFieldsStmt = db.prepare("DELETE FROM content_fields WHERE collection_id = ?");
|
|
1708
1708
|
await deleteFieldsStmt.bind(id).run();
|
|
1709
|
-
const deleteStmt =
|
|
1709
|
+
const deleteStmt = db.prepare("DELETE FROM collections WHERE id = ?");
|
|
1710
1710
|
await deleteStmt.bind(id).run();
|
|
1711
1711
|
try {
|
|
1712
1712
|
await c.env.CACHE_KV.delete("cache:collections:all");
|
|
@@ -1722,9 +1722,9 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
|
|
|
1722
1722
|
});
|
|
1723
1723
|
adminApiRoutes.get("/migrations/status", async (c) => {
|
|
1724
1724
|
try {
|
|
1725
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
1726
|
-
const
|
|
1727
|
-
const migrationService = new MigrationService2(
|
|
1725
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-O6INOHRD.cjs');
|
|
1726
|
+
const db = c.env.DB;
|
|
1727
|
+
const migrationService = new MigrationService2(db);
|
|
1728
1728
|
const status = await migrationService.getMigrationStatus();
|
|
1729
1729
|
return c.json({
|
|
1730
1730
|
success: true,
|
|
@@ -1747,9 +1747,9 @@ adminApiRoutes.post("/migrations/run", async (c) => {
|
|
|
1747
1747
|
error: "Unauthorized. Admin access required."
|
|
1748
1748
|
}, 403);
|
|
1749
1749
|
}
|
|
1750
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
1751
|
-
const
|
|
1752
|
-
const migrationService = new MigrationService2(
|
|
1750
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-O6INOHRD.cjs');
|
|
1751
|
+
const db = c.env.DB;
|
|
1752
|
+
const migrationService = new MigrationService2(db);
|
|
1753
1753
|
const result = await migrationService.runPendingMigrations();
|
|
1754
1754
|
return c.json({
|
|
1755
1755
|
success: result.success,
|
|
@@ -1766,9 +1766,9 @@ adminApiRoutes.post("/migrations/run", async (c) => {
|
|
|
1766
1766
|
});
|
|
1767
1767
|
adminApiRoutes.get("/migrations/validate", async (c) => {
|
|
1768
1768
|
try {
|
|
1769
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
1770
|
-
const
|
|
1771
|
-
const migrationService = new MigrationService2(
|
|
1769
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-O6INOHRD.cjs');
|
|
1770
|
+
const db = c.env.DB;
|
|
1771
|
+
const migrationService = new MigrationService2(db);
|
|
1772
1772
|
const validation = await migrationService.validateSchema();
|
|
1773
1773
|
return c.json({
|
|
1774
1774
|
success: true,
|
|
@@ -2119,19 +2119,20 @@ function renderRegisterPage(data) {
|
|
|
2119
2119
|
</html>
|
|
2120
2120
|
`;
|
|
2121
2121
|
}
|
|
2122
|
+
var baseRegistrationSchema = zod.z.object({
|
|
2123
|
+
email: zod.z.string().email("Valid email is required"),
|
|
2124
|
+
password: zod.z.string().min(8, "Password must be at least 8 characters"),
|
|
2125
|
+
username: zod.z.string().min(3, "Username must be at least 3 characters").optional(),
|
|
2126
|
+
firstName: zod.z.string().min(1, "First name is required").optional(),
|
|
2127
|
+
lastName: zod.z.string().min(1, "Last name is required").optional()
|
|
2128
|
+
});
|
|
2122
2129
|
var authValidationService = {
|
|
2123
2130
|
/**
|
|
2124
2131
|
* Build registration schema dynamically based on auth settings
|
|
2125
2132
|
* For now, returns a static schema with standard fields
|
|
2126
2133
|
*/
|
|
2127
2134
|
async buildRegistrationSchema(_db) {
|
|
2128
|
-
return
|
|
2129
|
-
email: zod.z.string().email("Valid email is required"),
|
|
2130
|
-
password: zod.z.string().min(8, "Password must be at least 8 characters"),
|
|
2131
|
-
username: zod.z.string().min(3, "Username must be at least 3 characters").optional(),
|
|
2132
|
-
firstName: zod.z.string().min(1, "First name is required").optional(),
|
|
2133
|
-
lastName: zod.z.string().min(1, "Last name is required").optional()
|
|
2134
|
-
});
|
|
2135
|
+
return baseRegistrationSchema;
|
|
2135
2136
|
},
|
|
2136
2137
|
/**
|
|
2137
2138
|
* Generate default values for optional fields
|
|
@@ -2160,10 +2161,10 @@ authRoutes.get("/login", async (c) => {
|
|
|
2160
2161
|
message: message || void 0,
|
|
2161
2162
|
version: c.get("appVersion")
|
|
2162
2163
|
};
|
|
2163
|
-
const
|
|
2164
|
+
const db = c.env.DB;
|
|
2164
2165
|
let demoLoginActive = false;
|
|
2165
2166
|
try {
|
|
2166
|
-
const plugin = await
|
|
2167
|
+
const plugin = await db.prepare("SELECT * FROM plugins WHERE id = ? AND status = ?").bind("demo-login-prefill", "active").first();
|
|
2167
2168
|
demoLoginActive = !!plugin;
|
|
2168
2169
|
} catch (error2) {
|
|
2169
2170
|
}
|
|
@@ -2184,21 +2185,21 @@ authRoutes.post(
|
|
|
2184
2185
|
"/register",
|
|
2185
2186
|
async (c) => {
|
|
2186
2187
|
try {
|
|
2187
|
-
const
|
|
2188
|
+
const db = c.env.DB;
|
|
2188
2189
|
let requestData;
|
|
2189
2190
|
try {
|
|
2190
2191
|
requestData = await c.req.json();
|
|
2191
2192
|
} catch (parseError) {
|
|
2192
2193
|
return c.json({ error: "Invalid JSON in request body" }, 400);
|
|
2193
2194
|
}
|
|
2194
|
-
const validationSchema = await authValidationService.buildRegistrationSchema(
|
|
2195
|
+
const validationSchema = await authValidationService.buildRegistrationSchema(db);
|
|
2195
2196
|
let validatedData;
|
|
2196
2197
|
try {
|
|
2197
2198
|
validatedData = await validationSchema.parseAsync(requestData);
|
|
2198
2199
|
} catch (validationError) {
|
|
2199
2200
|
return c.json({
|
|
2200
2201
|
error: "Validation failed",
|
|
2201
|
-
details: validationError.
|
|
2202
|
+
details: validationError.issues?.map((e) => e.message) || [validationError.message || "Invalid request data"]
|
|
2202
2203
|
}, 400);
|
|
2203
2204
|
}
|
|
2204
2205
|
const email = validatedData.email;
|
|
@@ -2207,14 +2208,14 @@ authRoutes.post(
|
|
|
2207
2208
|
const firstName = validatedData.firstName || authValidationService.generateDefaultValue("firstName", validatedData);
|
|
2208
2209
|
const lastName = validatedData.lastName || authValidationService.generateDefaultValue("lastName", validatedData);
|
|
2209
2210
|
const normalizedEmail = email.toLowerCase();
|
|
2210
|
-
const existingUser = await
|
|
2211
|
+
const existingUser = await db.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind(normalizedEmail, username).first();
|
|
2211
2212
|
if (existingUser) {
|
|
2212
2213
|
return c.json({ error: "User with this email or username already exists" }, 400);
|
|
2213
2214
|
}
|
|
2214
|
-
const passwordHash = await
|
|
2215
|
+
const passwordHash = await chunk5UUYHAZT_cjs.AuthManager.hashPassword(password);
|
|
2215
2216
|
const userId = crypto.randomUUID();
|
|
2216
2217
|
const now = /* @__PURE__ */ new Date();
|
|
2217
|
-
await
|
|
2218
|
+
await db.prepare(`
|
|
2218
2219
|
INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
|
|
2219
2220
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2220
2221
|
`).bind(
|
|
@@ -2231,7 +2232,7 @@ authRoutes.post(
|
|
|
2231
2232
|
now.getTime(),
|
|
2232
2233
|
now.getTime()
|
|
2233
2234
|
).run();
|
|
2234
|
-
const token = await
|
|
2235
|
+
const token = await chunk5UUYHAZT_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer");
|
|
2235
2236
|
cookie.setCookie(c, "auth_token", token, {
|
|
2236
2237
|
httpOnly: true,
|
|
2237
2238
|
secure: true,
|
|
@@ -2267,15 +2268,15 @@ authRoutes.post("/login", async (c) => {
|
|
|
2267
2268
|
const body = await c.req.json();
|
|
2268
2269
|
const validation = loginSchema.safeParse(body);
|
|
2269
2270
|
if (!validation.success) {
|
|
2270
|
-
return c.json({ error: "Validation failed", details: validation.error.
|
|
2271
|
+
return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
|
|
2271
2272
|
}
|
|
2272
2273
|
const { email, password } = validation.data;
|
|
2273
|
-
const
|
|
2274
|
+
const db = c.env.DB;
|
|
2274
2275
|
const normalizedEmail = email.toLowerCase();
|
|
2275
|
-
const cache =
|
|
2276
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.user);
|
|
2276
2277
|
let user = await cache.get(cache.generateKey("user", `email:${normalizedEmail}`));
|
|
2277
2278
|
if (!user) {
|
|
2278
|
-
user = await
|
|
2279
|
+
user = await db.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
|
|
2279
2280
|
if (user) {
|
|
2280
2281
|
await cache.set(cache.generateKey("user", `email:${normalizedEmail}`), user);
|
|
2281
2282
|
await cache.set(cache.generateKey("user", user.id), user);
|
|
@@ -2284,11 +2285,11 @@ authRoutes.post("/login", async (c) => {
|
|
|
2284
2285
|
if (!user) {
|
|
2285
2286
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2286
2287
|
}
|
|
2287
|
-
const isValidPassword = await
|
|
2288
|
+
const isValidPassword = await chunk5UUYHAZT_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2288
2289
|
if (!isValidPassword) {
|
|
2289
2290
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2290
2291
|
}
|
|
2291
|
-
const token = await
|
|
2292
|
+
const token = await chunk5UUYHAZT_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2292
2293
|
cookie.setCookie(c, "auth_token", token, {
|
|
2293
2294
|
httpOnly: true,
|
|
2294
2295
|
secure: true,
|
|
@@ -2296,7 +2297,7 @@ authRoutes.post("/login", async (c) => {
|
|
|
2296
2297
|
maxAge: 60 * 60 * 24
|
|
2297
2298
|
// 24 hours
|
|
2298
2299
|
});
|
|
2299
|
-
await
|
|
2300
|
+
await db.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
|
|
2300
2301
|
await cache.delete(cache.generateKey("user", user.id));
|
|
2301
2302
|
await cache.delete(cache.generateKey("user", `email:${normalizedEmail}`));
|
|
2302
2303
|
return c.json({
|
|
@@ -2337,14 +2338,14 @@ authRoutes.get("/logout", (c) => {
|
|
|
2337
2338
|
});
|
|
2338
2339
|
return c.redirect("/auth/login?message=You have been logged out successfully");
|
|
2339
2340
|
});
|
|
2340
|
-
authRoutes.get("/me",
|
|
2341
|
+
authRoutes.get("/me", chunk5UUYHAZT_cjs.requireAuth(), async (c) => {
|
|
2341
2342
|
try {
|
|
2342
2343
|
const user = c.get("user");
|
|
2343
2344
|
if (!user) {
|
|
2344
2345
|
return c.json({ error: "Not authenticated" }, 401);
|
|
2345
2346
|
}
|
|
2346
|
-
const
|
|
2347
|
-
const userData = await
|
|
2347
|
+
const db = c.env.DB;
|
|
2348
|
+
const userData = await db.prepare("SELECT id, email, username, first_name, last_name, role, created_at FROM users WHERE id = ?").bind(user.userId).first();
|
|
2348
2349
|
if (!userData) {
|
|
2349
2350
|
return c.json({ error: "User not found" }, 404);
|
|
2350
2351
|
}
|
|
@@ -2354,13 +2355,13 @@ authRoutes.get("/me", chunkUEYMFNBN_cjs.requireAuth(), async (c) => {
|
|
|
2354
2355
|
return c.json({ error: "Failed to get user" }, 500);
|
|
2355
2356
|
}
|
|
2356
2357
|
});
|
|
2357
|
-
authRoutes.post("/refresh",
|
|
2358
|
+
authRoutes.post("/refresh", chunk5UUYHAZT_cjs.requireAuth(), async (c) => {
|
|
2358
2359
|
try {
|
|
2359
2360
|
const user = c.get("user");
|
|
2360
2361
|
if (!user) {
|
|
2361
2362
|
return c.json({ error: "Not authenticated" }, 401);
|
|
2362
2363
|
}
|
|
2363
|
-
const token = await
|
|
2364
|
+
const token = await chunk5UUYHAZT_cjs.AuthManager.generateToken(user.userId, user.email, user.role);
|
|
2364
2365
|
cookie.setCookie(c, "auth_token", token, {
|
|
2365
2366
|
httpOnly: true,
|
|
2366
2367
|
secure: true,
|
|
@@ -2376,7 +2377,7 @@ authRoutes.post("/refresh", chunkUEYMFNBN_cjs.requireAuth(), async (c) => {
|
|
|
2376
2377
|
});
|
|
2377
2378
|
authRoutes.post("/register/form", async (c) => {
|
|
2378
2379
|
try {
|
|
2379
|
-
const
|
|
2380
|
+
const db = c.env.DB;
|
|
2380
2381
|
const formData = await c.req.formData();
|
|
2381
2382
|
const requestData = {
|
|
2382
2383
|
email: formData.get("email"),
|
|
@@ -2387,12 +2388,12 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2387
2388
|
};
|
|
2388
2389
|
const normalizedEmail = requestData.email?.toLowerCase();
|
|
2389
2390
|
requestData.email = normalizedEmail;
|
|
2390
|
-
const validationSchema = await authValidationService.buildRegistrationSchema(
|
|
2391
|
+
const validationSchema = await authValidationService.buildRegistrationSchema(db);
|
|
2391
2392
|
const validation = await validationSchema.safeParseAsync(requestData);
|
|
2392
2393
|
if (!validation.success) {
|
|
2393
2394
|
return c.html(html.html`
|
|
2394
2395
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
2395
|
-
${validation.error.
|
|
2396
|
+
${validation.error.issues.map((err) => err.message).join(", ")}
|
|
2396
2397
|
</div>
|
|
2397
2398
|
`);
|
|
2398
2399
|
}
|
|
@@ -2401,7 +2402,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2401
2402
|
const username = validatedData.username || authValidationService.generateDefaultValue("username", validatedData);
|
|
2402
2403
|
const firstName = validatedData.firstName || authValidationService.generateDefaultValue("firstName", validatedData);
|
|
2403
2404
|
const lastName = validatedData.lastName || authValidationService.generateDefaultValue("lastName", validatedData);
|
|
2404
|
-
const existingUser = await
|
|
2405
|
+
const existingUser = await db.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind(normalizedEmail, username).first();
|
|
2405
2406
|
if (existingUser) {
|
|
2406
2407
|
return c.html(html.html`
|
|
2407
2408
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2409,10 +2410,10 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2409
2410
|
</div>
|
|
2410
2411
|
`);
|
|
2411
2412
|
}
|
|
2412
|
-
const passwordHash = await
|
|
2413
|
+
const passwordHash = await chunk5UUYHAZT_cjs.AuthManager.hashPassword(password);
|
|
2413
2414
|
const userId = crypto.randomUUID();
|
|
2414
2415
|
const now = /* @__PURE__ */ new Date();
|
|
2415
|
-
await
|
|
2416
|
+
await db.prepare(`
|
|
2416
2417
|
INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
|
|
2417
2418
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2418
2419
|
`).bind(
|
|
@@ -2429,7 +2430,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2429
2430
|
now.getTime(),
|
|
2430
2431
|
now.getTime()
|
|
2431
2432
|
).run();
|
|
2432
|
-
const token = await
|
|
2433
|
+
const token = await chunk5UUYHAZT_cjs.AuthManager.generateToken(userId, normalizedEmail, "admin");
|
|
2433
2434
|
cookie.setCookie(c, "auth_token", token, {
|
|
2434
2435
|
httpOnly: true,
|
|
2435
2436
|
secure: false,
|
|
@@ -2467,12 +2468,12 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2467
2468
|
if (!validation.success) {
|
|
2468
2469
|
return c.html(html.html`
|
|
2469
2470
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
2470
|
-
${validation.error.
|
|
2471
|
+
${validation.error.issues.map((err) => err.message).join(", ")}
|
|
2471
2472
|
</div>
|
|
2472
2473
|
`);
|
|
2473
2474
|
}
|
|
2474
|
-
const
|
|
2475
|
-
const user = await
|
|
2475
|
+
const db = c.env.DB;
|
|
2476
|
+
const user = await db.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
|
|
2476
2477
|
if (!user) {
|
|
2477
2478
|
return c.html(html.html`
|
|
2478
2479
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2480,7 +2481,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2480
2481
|
</div>
|
|
2481
2482
|
`);
|
|
2482
2483
|
}
|
|
2483
|
-
const isValidPassword = await
|
|
2484
|
+
const isValidPassword = await chunk5UUYHAZT_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2484
2485
|
if (!isValidPassword) {
|
|
2485
2486
|
return c.html(html.html`
|
|
2486
2487
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2488,7 +2489,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2488
2489
|
</div>
|
|
2489
2490
|
`);
|
|
2490
2491
|
}
|
|
2491
|
-
const token = await
|
|
2492
|
+
const token = await chunk5UUYHAZT_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2492
2493
|
cookie.setCookie(c, "auth_token", token, {
|
|
2493
2494
|
httpOnly: true,
|
|
2494
2495
|
secure: false,
|
|
@@ -2497,7 +2498,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2497
2498
|
maxAge: 60 * 60 * 24
|
|
2498
2499
|
// 24 hours
|
|
2499
2500
|
});
|
|
2500
|
-
await
|
|
2501
|
+
await db.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
|
|
2501
2502
|
return c.html(html.html`
|
|
2502
2503
|
<div id="form-response">
|
|
2503
2504
|
<div class="rounded-lg bg-green-100 dark:bg-lime-500/10 p-4 ring-1 ring-green-400 dark:ring-lime-500/20">
|
|
@@ -2528,8 +2529,8 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2528
2529
|
});
|
|
2529
2530
|
authRoutes.post("/seed-admin", async (c) => {
|
|
2530
2531
|
try {
|
|
2531
|
-
const
|
|
2532
|
-
await
|
|
2532
|
+
const db = c.env.DB;
|
|
2533
|
+
await db.prepare(`
|
|
2533
2534
|
CREATE TABLE IF NOT EXISTS users (
|
|
2534
2535
|
id TEXT PRIMARY KEY,
|
|
2535
2536
|
email TEXT NOT NULL UNIQUE,
|
|
@@ -2545,10 +2546,10 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2545
2546
|
updated_at INTEGER NOT NULL
|
|
2546
2547
|
)
|
|
2547
2548
|
`).run();
|
|
2548
|
-
const existingAdmin = await
|
|
2549
|
+
const existingAdmin = await db.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind("admin@sonicjs.com", "admin").first();
|
|
2549
2550
|
if (existingAdmin) {
|
|
2550
|
-
const passwordHash2 = await
|
|
2551
|
-
await
|
|
2551
|
+
const passwordHash2 = await chunk5UUYHAZT_cjs.AuthManager.hashPassword("sonicjs!");
|
|
2552
|
+
await db.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?").bind(passwordHash2, Date.now(), existingAdmin.id).run();
|
|
2552
2553
|
return c.json({
|
|
2553
2554
|
message: "Admin user already exists (password updated)",
|
|
2554
2555
|
user: {
|
|
@@ -2559,11 +2560,11 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2559
2560
|
}
|
|
2560
2561
|
});
|
|
2561
2562
|
}
|
|
2562
|
-
const passwordHash = await
|
|
2563
|
+
const passwordHash = await chunk5UUYHAZT_cjs.AuthManager.hashPassword("sonicjs!");
|
|
2563
2564
|
const userId = "admin-user-id";
|
|
2564
2565
|
const now = Date.now();
|
|
2565
2566
|
const adminEmail = "admin@sonicjs.com".toLowerCase();
|
|
2566
|
-
await
|
|
2567
|
+
await db.prepare(`
|
|
2567
2568
|
INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
|
|
2568
2569
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2569
2570
|
`).bind(
|
|
@@ -2610,8 +2611,8 @@ authRoutes.get("/accept-invitation", async (c) => {
|
|
|
2610
2611
|
</html>
|
|
2611
2612
|
`);
|
|
2612
2613
|
}
|
|
2613
|
-
const
|
|
2614
|
-
const userStmt =
|
|
2614
|
+
const db = c.env.DB;
|
|
2615
|
+
const userStmt = db.prepare(`
|
|
2615
2616
|
SELECT id, email, first_name, last_name, role, invited_at
|
|
2616
2617
|
FROM users
|
|
2617
2618
|
WHERE invitation_token = ? AND is_active = 0
|
|
@@ -2757,8 +2758,8 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2757
2758
|
if (password.length < 8) {
|
|
2758
2759
|
return c.json({ error: "Password must be at least 8 characters long" }, 400);
|
|
2759
2760
|
}
|
|
2760
|
-
const
|
|
2761
|
-
const userStmt =
|
|
2761
|
+
const db = c.env.DB;
|
|
2762
|
+
const userStmt = db.prepare(`
|
|
2762
2763
|
SELECT id, email, first_name, last_name, role, invited_at
|
|
2763
2764
|
FROM users
|
|
2764
2765
|
WHERE invitation_token = ? AND is_active = 0
|
|
@@ -2772,15 +2773,15 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2772
2773
|
if (invitationAge > maxAge) {
|
|
2773
2774
|
return c.json({ error: "Invitation has expired" }, 400);
|
|
2774
2775
|
}
|
|
2775
|
-
const existingUsernameStmt =
|
|
2776
|
+
const existingUsernameStmt = db.prepare(`
|
|
2776
2777
|
SELECT id FROM users WHERE username = ? AND id != ?
|
|
2777
2778
|
`);
|
|
2778
2779
|
const existingUsername = await existingUsernameStmt.bind(username, invitedUser.id).first();
|
|
2779
2780
|
if (existingUsername) {
|
|
2780
2781
|
return c.json({ error: "Username is already taken" }, 400);
|
|
2781
2782
|
}
|
|
2782
|
-
const passwordHash = await
|
|
2783
|
-
const updateStmt =
|
|
2783
|
+
const passwordHash = await chunk5UUYHAZT_cjs.AuthManager.hashPassword(password);
|
|
2784
|
+
const updateStmt = db.prepare(`
|
|
2784
2785
|
UPDATE users SET
|
|
2785
2786
|
username = ?,
|
|
2786
2787
|
password_hash = ?,
|
|
@@ -2798,7 +2799,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2798
2799
|
Date.now(),
|
|
2799
2800
|
invitedUser.id
|
|
2800
2801
|
).run();
|
|
2801
|
-
const authToken = await
|
|
2802
|
+
const authToken = await chunk5UUYHAZT_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role);
|
|
2802
2803
|
cookie.setCookie(c, "auth_token", authToken, {
|
|
2803
2804
|
httpOnly: true,
|
|
2804
2805
|
secure: true,
|
|
@@ -2823,8 +2824,8 @@ authRoutes.post("/request-password-reset", async (c) => {
|
|
|
2823
2824
|
if (!emailRegex.test(email)) {
|
|
2824
2825
|
return c.json({ error: "Please enter a valid email address" }, 400);
|
|
2825
2826
|
}
|
|
2826
|
-
const
|
|
2827
|
-
const userStmt =
|
|
2827
|
+
const db = c.env.DB;
|
|
2828
|
+
const userStmt = db.prepare(`
|
|
2828
2829
|
SELECT id, email, first_name, last_name FROM users
|
|
2829
2830
|
WHERE email = ? AND is_active = 1
|
|
2830
2831
|
`);
|
|
@@ -2837,7 +2838,7 @@ authRoutes.post("/request-password-reset", async (c) => {
|
|
|
2837
2838
|
}
|
|
2838
2839
|
const resetToken = crypto.randomUUID();
|
|
2839
2840
|
const resetExpires = Date.now() + 60 * 60 * 1e3;
|
|
2840
|
-
const updateStmt =
|
|
2841
|
+
const updateStmt = db.prepare(`
|
|
2841
2842
|
UPDATE users SET
|
|
2842
2843
|
password_reset_token = ?,
|
|
2843
2844
|
password_reset_expires = ?,
|
|
@@ -2877,8 +2878,8 @@ authRoutes.get("/reset-password", async (c) => {
|
|
|
2877
2878
|
</html>
|
|
2878
2879
|
`);
|
|
2879
2880
|
}
|
|
2880
|
-
const
|
|
2881
|
-
const userStmt =
|
|
2881
|
+
const db = c.env.DB;
|
|
2882
|
+
const userStmt = db.prepare(`
|
|
2882
2883
|
SELECT id, email, first_name, last_name, password_reset_expires
|
|
2883
2884
|
FROM users
|
|
2884
2885
|
WHERE password_reset_token = ? AND is_active = 1
|
|
@@ -3015,8 +3016,8 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3015
3016
|
if (password.length < 8) {
|
|
3016
3017
|
return c.json({ error: "Password must be at least 8 characters long" }, 400);
|
|
3017
3018
|
}
|
|
3018
|
-
const
|
|
3019
|
-
const userStmt =
|
|
3019
|
+
const db = c.env.DB;
|
|
3020
|
+
const userStmt = db.prepare(`
|
|
3020
3021
|
SELECT id, email, password_hash, password_reset_expires
|
|
3021
3022
|
FROM users
|
|
3022
3023
|
WHERE password_reset_token = ? AND is_active = 1
|
|
@@ -3028,9 +3029,9 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3028
3029
|
if (Date.now() > user.password_reset_expires) {
|
|
3029
3030
|
return c.json({ error: "Reset token has expired" }, 400);
|
|
3030
3031
|
}
|
|
3031
|
-
const newPasswordHash = await
|
|
3032
|
+
const newPasswordHash = await chunk5UUYHAZT_cjs.AuthManager.hashPassword(password);
|
|
3032
3033
|
try {
|
|
3033
|
-
const historyStmt =
|
|
3034
|
+
const historyStmt = db.prepare(`
|
|
3034
3035
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
3035
3036
|
VALUES (?, ?, ?, ?)
|
|
3036
3037
|
`);
|
|
@@ -3043,7 +3044,7 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3043
3044
|
} catch (historyError) {
|
|
3044
3045
|
console.warn("Could not store password history:", historyError);
|
|
3045
3046
|
}
|
|
3046
|
-
const updateStmt =
|
|
3047
|
+
const updateStmt = db.prepare(`
|
|
3047
3048
|
UPDATE users SET
|
|
3048
3049
|
password_hash = ?,
|
|
3049
3050
|
password_reset_token = NULL,
|
|
@@ -3065,20 +3066,20 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3065
3066
|
var auth_default = authRoutes;
|
|
3066
3067
|
var app = new hono.Hono();
|
|
3067
3068
|
app.post("/test-cleanup", async (c) => {
|
|
3068
|
-
const
|
|
3069
|
+
const db = c.env.DB;
|
|
3069
3070
|
if (c.env.ENVIRONMENT === "production") {
|
|
3070
3071
|
return c.json({ error: "Cleanup endpoint not available in production" }, 403);
|
|
3071
3072
|
}
|
|
3072
3073
|
try {
|
|
3073
3074
|
let deletedCount = 0;
|
|
3074
|
-
await
|
|
3075
|
+
await db.prepare(`
|
|
3075
3076
|
DELETE FROM content_versions
|
|
3076
3077
|
WHERE content_id IN (
|
|
3077
3078
|
SELECT id FROM content
|
|
3078
3079
|
WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
|
|
3079
3080
|
)
|
|
3080
3081
|
`).run();
|
|
3081
|
-
await
|
|
3082
|
+
await db.prepare(`
|
|
3082
3083
|
DELETE FROM workflow_history
|
|
3083
3084
|
WHERE content_id IN (
|
|
3084
3085
|
SELECT id FROM content
|
|
@@ -3086,7 +3087,7 @@ app.post("/test-cleanup", async (c) => {
|
|
|
3086
3087
|
)
|
|
3087
3088
|
`).run();
|
|
3088
3089
|
try {
|
|
3089
|
-
await
|
|
3090
|
+
await db.prepare(`
|
|
3090
3091
|
DELETE FROM content_data
|
|
3091
3092
|
WHERE content_id IN (
|
|
3092
3093
|
SELECT id FROM content
|
|
@@ -3095,32 +3096,32 @@ app.post("/test-cleanup", async (c) => {
|
|
|
3095
3096
|
`).run();
|
|
3096
3097
|
} catch (e) {
|
|
3097
3098
|
}
|
|
3098
|
-
const contentResult = await
|
|
3099
|
+
const contentResult = await db.prepare(`
|
|
3099
3100
|
DELETE FROM content
|
|
3100
3101
|
WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
|
|
3101
3102
|
`).run();
|
|
3102
3103
|
deletedCount += contentResult.meta?.changes || 0;
|
|
3103
|
-
await
|
|
3104
|
+
await db.prepare(`
|
|
3104
3105
|
DELETE FROM api_tokens
|
|
3105
3106
|
WHERE user_id IN (
|
|
3106
3107
|
SELECT id FROM users
|
|
3107
3108
|
WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
|
|
3108
3109
|
)
|
|
3109
3110
|
`).run();
|
|
3110
|
-
await
|
|
3111
|
+
await db.prepare(`
|
|
3111
3112
|
DELETE FROM media
|
|
3112
3113
|
WHERE uploaded_by IN (
|
|
3113
3114
|
SELECT id FROM users
|
|
3114
3115
|
WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
|
|
3115
3116
|
)
|
|
3116
3117
|
`).run();
|
|
3117
|
-
const usersResult = await
|
|
3118
|
+
const usersResult = await db.prepare(`
|
|
3118
3119
|
DELETE FROM users
|
|
3119
3120
|
WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
|
|
3120
3121
|
`).run();
|
|
3121
3122
|
deletedCount += usersResult.meta?.changes || 0;
|
|
3122
3123
|
try {
|
|
3123
|
-
await
|
|
3124
|
+
await db.prepare(`
|
|
3124
3125
|
DELETE FROM collection_fields
|
|
3125
3126
|
WHERE collection_id IN (
|
|
3126
3127
|
SELECT id FROM collections
|
|
@@ -3129,43 +3130,43 @@ app.post("/test-cleanup", async (c) => {
|
|
|
3129
3130
|
`).run();
|
|
3130
3131
|
} catch (e) {
|
|
3131
3132
|
}
|
|
3132
|
-
await
|
|
3133
|
+
await db.prepare(`
|
|
3133
3134
|
DELETE FROM content
|
|
3134
3135
|
WHERE collection_id IN (
|
|
3135
3136
|
SELECT id FROM collections
|
|
3136
3137
|
WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
|
|
3137
3138
|
)
|
|
3138
3139
|
`).run();
|
|
3139
|
-
const collectionsResult = await
|
|
3140
|
+
const collectionsResult = await db.prepare(`
|
|
3140
3141
|
DELETE FROM collections
|
|
3141
3142
|
WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
|
|
3142
3143
|
`).run();
|
|
3143
3144
|
deletedCount += collectionsResult.meta?.changes || 0;
|
|
3144
3145
|
try {
|
|
3145
|
-
await
|
|
3146
|
+
await db.prepare(`
|
|
3146
3147
|
DELETE FROM content_data WHERE content_id NOT IN (SELECT id FROM content)
|
|
3147
3148
|
`).run();
|
|
3148
3149
|
} catch (e) {
|
|
3149
3150
|
}
|
|
3150
3151
|
try {
|
|
3151
|
-
await
|
|
3152
|
+
await db.prepare(`
|
|
3152
3153
|
DELETE FROM collection_fields WHERE collection_id NOT IN (SELECT id FROM collections)
|
|
3153
3154
|
`).run();
|
|
3154
3155
|
} catch (e) {
|
|
3155
3156
|
}
|
|
3156
3157
|
try {
|
|
3157
|
-
await
|
|
3158
|
+
await db.prepare(`
|
|
3158
3159
|
DELETE FROM content_versions WHERE content_id NOT IN (SELECT id FROM content)
|
|
3159
3160
|
`).run();
|
|
3160
3161
|
} catch (e) {
|
|
3161
3162
|
}
|
|
3162
3163
|
try {
|
|
3163
|
-
await
|
|
3164
|
+
await db.prepare(`
|
|
3164
3165
|
DELETE FROM workflow_history WHERE content_id NOT IN (SELECT id FROM content)
|
|
3165
3166
|
`).run();
|
|
3166
3167
|
} catch (e) {
|
|
3167
3168
|
}
|
|
3168
|
-
await
|
|
3169
|
+
await db.prepare(`
|
|
3169
3170
|
DELETE FROM activity_logs
|
|
3170
3171
|
WHERE id NOT IN (
|
|
3171
3172
|
SELECT id FROM activity_logs
|
|
@@ -3187,12 +3188,12 @@ app.post("/test-cleanup", async (c) => {
|
|
|
3187
3188
|
}
|
|
3188
3189
|
});
|
|
3189
3190
|
app.post("/test-cleanup/users", async (c) => {
|
|
3190
|
-
const
|
|
3191
|
+
const db = c.env.DB;
|
|
3191
3192
|
if (c.env.ENVIRONMENT === "production") {
|
|
3192
3193
|
return c.json({ error: "Cleanup endpoint not available in production" }, 403);
|
|
3193
3194
|
}
|
|
3194
3195
|
try {
|
|
3195
|
-
const result = await
|
|
3196
|
+
const result = await db.prepare(`
|
|
3196
3197
|
DELETE FROM users
|
|
3197
3198
|
WHERE email != 'admin@sonicjs.com'
|
|
3198
3199
|
AND (
|
|
@@ -3215,13 +3216,13 @@ app.post("/test-cleanup/users", async (c) => {
|
|
|
3215
3216
|
}
|
|
3216
3217
|
});
|
|
3217
3218
|
app.post("/test-cleanup/collections", async (c) => {
|
|
3218
|
-
const
|
|
3219
|
+
const db = c.env.DB;
|
|
3219
3220
|
if (c.env.ENVIRONMENT === "production") {
|
|
3220
3221
|
return c.json({ error: "Cleanup endpoint not available in production" }, 403);
|
|
3221
3222
|
}
|
|
3222
3223
|
try {
|
|
3223
3224
|
let deletedCount = 0;
|
|
3224
|
-
const collections = await
|
|
3225
|
+
const collections = await db.prepare(`
|
|
3225
3226
|
SELECT id FROM collections
|
|
3226
3227
|
WHERE name LIKE 'test_%'
|
|
3227
3228
|
OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
|
|
@@ -3229,12 +3230,12 @@ app.post("/test-cleanup/collections", async (c) => {
|
|
|
3229
3230
|
if (collections.results && collections.results.length > 0) {
|
|
3230
3231
|
const collectionIds = collections.results.map((c2) => c2.id);
|
|
3231
3232
|
for (const id of collectionIds) {
|
|
3232
|
-
await
|
|
3233
|
+
await db.prepare("DELETE FROM collection_fields WHERE collection_id = ?").bind(id).run();
|
|
3233
3234
|
}
|
|
3234
3235
|
for (const id of collectionIds) {
|
|
3235
|
-
await
|
|
3236
|
+
await db.prepare("DELETE FROM content WHERE collection_id = ?").bind(id).run();
|
|
3236
3237
|
}
|
|
3237
|
-
const result = await
|
|
3238
|
+
const result = await db.prepare(`
|
|
3238
3239
|
DELETE FROM collections
|
|
3239
3240
|
WHERE id IN (${collectionIds.map(() => "?").join(",")})
|
|
3240
3241
|
`).bind(...collectionIds).run();
|
|
@@ -3254,19 +3255,19 @@ app.post("/test-cleanup/collections", async (c) => {
|
|
|
3254
3255
|
}
|
|
3255
3256
|
});
|
|
3256
3257
|
app.post("/test-cleanup/content", async (c) => {
|
|
3257
|
-
const
|
|
3258
|
+
const db = c.env.DB;
|
|
3258
3259
|
if (c.env.ENVIRONMENT === "production") {
|
|
3259
3260
|
return c.json({ error: "Cleanup endpoint not available in production" }, 403);
|
|
3260
3261
|
}
|
|
3261
3262
|
try {
|
|
3262
|
-
const result = await
|
|
3263
|
+
const result = await db.prepare(`
|
|
3263
3264
|
DELETE FROM content
|
|
3264
3265
|
WHERE title LIKE 'Test %'
|
|
3265
3266
|
OR title LIKE '%E2E%'
|
|
3266
3267
|
OR title LIKE '%Playwright%'
|
|
3267
3268
|
OR title LIKE '%Sample%'
|
|
3268
3269
|
`).run();
|
|
3269
|
-
await
|
|
3270
|
+
await db.prepare(`
|
|
3270
3271
|
DELETE FROM content_data
|
|
3271
3272
|
WHERE content_id NOT IN (SELECT id FROM content)
|
|
3272
3273
|
`).run();
|
|
@@ -4233,8 +4234,7 @@ function createQuillEditorPlugin() {
|
|
|
4233
4234
|
email: "team@sonicjs.com"
|
|
4234
4235
|
},
|
|
4235
4236
|
license: "MIT",
|
|
4236
|
-
compatibility: "^2.0.0"
|
|
4237
|
-
tags: ["editor", "rich-text", "wysiwyg", "quill"]
|
|
4237
|
+
compatibility: "^2.0.0"
|
|
4238
4238
|
});
|
|
4239
4239
|
builder3.lifecycle({
|
|
4240
4240
|
activate: async () => {
|
|
@@ -5075,7 +5075,6 @@ function renderContentFormPage(data) {
|
|
|
5075
5075
|
})}</script>` : ""}
|
|
5076
5076
|
|
|
5077
5077
|
${data.mdxeditorEnabled ? `<script>${getMDXEditorInitScript({
|
|
5078
|
-
theme: data.mdxeditorSettings?.theme,
|
|
5079
5078
|
defaultHeight: data.mdxeditorSettings?.defaultHeight,
|
|
5080
5079
|
toolbar: data.mdxeditorSettings?.toolbar,
|
|
5081
5080
|
placeholder: data.mdxeditorSettings?.placeholder
|
|
@@ -5109,9 +5108,9 @@ function renderContentListPage(data) {
|
|
|
5109
5108
|
name: "model",
|
|
5110
5109
|
label: "Model",
|
|
5111
5110
|
options: [
|
|
5112
|
-
{
|
|
5111
|
+
{ value: "all", label: "All Models", selected: data.modelName === "all" },
|
|
5113
5112
|
...data.models.map((model) => ({
|
|
5114
|
-
|
|
5113
|
+
value: model.name,
|
|
5115
5114
|
label: model.displayName,
|
|
5116
5115
|
selected: data.modelName === model.name
|
|
5117
5116
|
}))
|
|
@@ -5121,13 +5120,13 @@ function renderContentListPage(data) {
|
|
|
5121
5120
|
name: "status",
|
|
5122
5121
|
label: "Status",
|
|
5123
5122
|
options: [
|
|
5124
|
-
{
|
|
5125
|
-
{
|
|
5126
|
-
{
|
|
5127
|
-
{
|
|
5128
|
-
{
|
|
5129
|
-
{
|
|
5130
|
-
{
|
|
5123
|
+
{ value: "all", label: "All Status", selected: data.status === "all" },
|
|
5124
|
+
{ value: "draft", label: "Draft", selected: data.status === "draft" },
|
|
5125
|
+
{ value: "review", label: "Under Review", selected: data.status === "review" },
|
|
5126
|
+
{ value: "scheduled", label: "Scheduled", selected: data.status === "scheduled" },
|
|
5127
|
+
{ value: "published", label: "Published", selected: data.status === "published" },
|
|
5128
|
+
{ value: "archived", label: "Archived", selected: data.status === "archived" },
|
|
5129
|
+
{ value: "deleted", label: "Deleted", selected: data.status === "deleted" }
|
|
5131
5130
|
]
|
|
5132
5131
|
}
|
|
5133
5132
|
],
|
|
@@ -5139,9 +5138,9 @@ function renderContentListPage(data) {
|
|
|
5139
5138
|
}
|
|
5140
5139
|
],
|
|
5141
5140
|
bulkActions: [
|
|
5142
|
-
{ label: "Publish",
|
|
5143
|
-
{ label: "Unpublish",
|
|
5144
|
-
{ label: "Delete",
|
|
5141
|
+
{ label: "Publish", value: "publish", icon: "check-circle" },
|
|
5142
|
+
{ label: "Unpublish", value: "unpublish", icon: "x-circle" },
|
|
5143
|
+
{ label: "Delete", value: "delete", icon: "trash", className: "text-pink-600" }
|
|
5145
5144
|
]
|
|
5146
5145
|
};
|
|
5147
5146
|
const tableColumns = [
|
|
@@ -5393,7 +5392,7 @@ function renderContentListPage(data) {
|
|
|
5393
5392
|
class="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white/5 dark:bg-white/5 py-1.5 ${filter.name === "status" ? "pl-8" : "pl-3"} pr-8 text-base text-zinc-950 dark:text-white outline outline-1 -outline-offset-1 outline-cyan-500/30 dark:outline-cyan-400/30 *:bg-white dark:*:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-cyan-500 dark:focus-visible:outline-cyan-400 sm:text-sm/6 min-w-48"
|
|
5394
5393
|
>
|
|
5395
5394
|
${filter.options.map((opt) => `
|
|
5396
|
-
<option value="${opt.
|
|
5395
|
+
<option value="${opt.value}" ${opt.selected ? "selected" : ""}>${opt.label}</option>
|
|
5397
5396
|
`).join("")}
|
|
5398
5397
|
</select>
|
|
5399
5398
|
<svg viewBox="0 0 16 16" fill="currentColor" data-slot="icon" aria-hidden="true" class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-cyan-600 dark:text-cyan-400 sm:size-4">
|
|
@@ -5913,9 +5912,9 @@ function escapeHtml3(text) {
|
|
|
5913
5912
|
}
|
|
5914
5913
|
|
|
5915
5914
|
// src/middleware/plugin-middleware.ts
|
|
5916
|
-
async function isPluginActive2(
|
|
5915
|
+
async function isPluginActive2(db, pluginId) {
|
|
5917
5916
|
try {
|
|
5918
|
-
const result = await
|
|
5917
|
+
const result = await db.prepare("SELECT status FROM plugins WHERE id = ?").bind(pluginId).first();
|
|
5919
5918
|
return result?.status === "active";
|
|
5920
5919
|
} catch (error) {
|
|
5921
5920
|
console.error(`[isPluginActive] Error checking plugin status for ${pluginId}:`, error);
|
|
@@ -5925,13 +5924,13 @@ async function isPluginActive2(db2, pluginId) {
|
|
|
5925
5924
|
|
|
5926
5925
|
// src/routes/admin-content.ts
|
|
5927
5926
|
var adminContentRoutes = new hono.Hono();
|
|
5928
|
-
adminContentRoutes.use("*",
|
|
5929
|
-
async function getCollectionFields(
|
|
5930
|
-
const cache =
|
|
5927
|
+
adminContentRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
5928
|
+
async function getCollectionFields(db, collectionId) {
|
|
5929
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.collection);
|
|
5931
5930
|
return cache.getOrSet(
|
|
5932
5931
|
cache.generateKey("fields", collectionId),
|
|
5933
5932
|
async () => {
|
|
5934
|
-
const collectionStmt =
|
|
5933
|
+
const collectionStmt = db.prepare("SELECT schema FROM collections WHERE id = ?");
|
|
5935
5934
|
const collectionRow = await collectionStmt.bind(collectionId).first();
|
|
5936
5935
|
if (collectionRow && collectionRow.schema) {
|
|
5937
5936
|
try {
|
|
@@ -5962,7 +5961,7 @@ async function getCollectionFields(db2, collectionId) {
|
|
|
5962
5961
|
console.error("Error parsing collection schema:", e);
|
|
5963
5962
|
}
|
|
5964
5963
|
}
|
|
5965
|
-
const stmt =
|
|
5964
|
+
const stmt = db.prepare(`
|
|
5966
5965
|
SELECT * FROM content_fields
|
|
5967
5966
|
WHERE collection_id = ?
|
|
5968
5967
|
ORDER BY field_order ASC
|
|
@@ -5981,12 +5980,12 @@ async function getCollectionFields(db2, collectionId) {
|
|
|
5981
5980
|
}
|
|
5982
5981
|
);
|
|
5983
5982
|
}
|
|
5984
|
-
async function getCollection(
|
|
5985
|
-
const cache =
|
|
5983
|
+
async function getCollection(db, collectionId) {
|
|
5984
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.collection);
|
|
5986
5985
|
return cache.getOrSet(
|
|
5987
5986
|
cache.generateKey("collection", collectionId),
|
|
5988
5987
|
async () => {
|
|
5989
|
-
const stmt =
|
|
5988
|
+
const stmt = db.prepare("SELECT * FROM collections WHERE id = ? AND is_active = 1");
|
|
5990
5989
|
const collection = await stmt.bind(collectionId).first();
|
|
5991
5990
|
if (!collection) return null;
|
|
5992
5991
|
return {
|
|
@@ -6003,14 +6002,14 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
6003
6002
|
try {
|
|
6004
6003
|
const user = c.get("user");
|
|
6005
6004
|
const url = new URL(c.req.url);
|
|
6006
|
-
const
|
|
6005
|
+
const db = c.env.DB;
|
|
6007
6006
|
const page = parseInt(url.searchParams.get("page") || "1");
|
|
6008
6007
|
const limit = parseInt(url.searchParams.get("limit") || "20");
|
|
6009
6008
|
const modelName = url.searchParams.get("model") || "all";
|
|
6010
6009
|
const status = url.searchParams.get("status") || "all";
|
|
6011
6010
|
const search = url.searchParams.get("search") || "";
|
|
6012
6011
|
const offset = (page - 1) * limit;
|
|
6013
|
-
const collectionsStmt =
|
|
6012
|
+
const collectionsStmt = db.prepare("SELECT id, name, display_name FROM collections WHERE is_active = 1 ORDER BY display_name");
|
|
6014
6013
|
const { results: collectionsResults } = await collectionsStmt.all();
|
|
6015
6014
|
const models = (collectionsResults || []).map((row) => ({
|
|
6016
6015
|
name: row.name,
|
|
@@ -6036,7 +6035,7 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
6036
6035
|
conditions.push("c.status = 'deleted'");
|
|
6037
6036
|
}
|
|
6038
6037
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
6039
|
-
const countStmt =
|
|
6038
|
+
const countStmt = db.prepare(`
|
|
6040
6039
|
SELECT COUNT(*) as count
|
|
6041
6040
|
FROM content c
|
|
6042
6041
|
JOIN collections col ON c.collection_id = col.id
|
|
@@ -6044,7 +6043,7 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
6044
6043
|
`);
|
|
6045
6044
|
const countResult = await countStmt.bind(...params).first();
|
|
6046
6045
|
const totalItems = countResult?.count || 0;
|
|
6047
|
-
const contentStmt =
|
|
6046
|
+
const contentStmt = db.prepare(`
|
|
6048
6047
|
SELECT c.id, c.title, c.slug, c.status, c.created_at, c.updated_at,
|
|
6049
6048
|
col.name as collection_name, col.display_name as collection_display_name,
|
|
6050
6049
|
u.first_name, u.last_name, u.email as author_email
|
|
@@ -6145,8 +6144,8 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
6145
6144
|
const url = new URL(c.req.url);
|
|
6146
6145
|
const collectionId = url.searchParams.get("collection");
|
|
6147
6146
|
if (!collectionId) {
|
|
6148
|
-
const
|
|
6149
|
-
const collectionsStmt =
|
|
6147
|
+
const db2 = c.env.DB;
|
|
6148
|
+
const collectionsStmt = db2.prepare("SELECT id, name, display_name, description FROM collections WHERE is_active = 1 ORDER BY display_name");
|
|
6150
6149
|
const { results } = await collectionsStmt.all();
|
|
6151
6150
|
const collections = (results || []).map((row) => ({
|
|
6152
6151
|
id: row.id,
|
|
@@ -6187,8 +6186,8 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
6187
6186
|
`;
|
|
6188
6187
|
return c.html(selectionHTML);
|
|
6189
6188
|
}
|
|
6190
|
-
const
|
|
6191
|
-
const collection = await getCollection(
|
|
6189
|
+
const db = c.env.DB;
|
|
6190
|
+
const collection = await getCollection(db, collectionId);
|
|
6192
6191
|
if (!collection) {
|
|
6193
6192
|
const formData2 = {
|
|
6194
6193
|
collection: { id: "", name: "", display_name: "Unknown", schema: {} },
|
|
@@ -6202,26 +6201,26 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
6202
6201
|
};
|
|
6203
6202
|
return c.html(renderContentFormPage(formData2));
|
|
6204
6203
|
}
|
|
6205
|
-
const fields = await getCollectionFields(
|
|
6206
|
-
const workflowEnabled = await isPluginActive2(
|
|
6207
|
-
const tinymceEnabled = await isPluginActive2(
|
|
6204
|
+
const fields = await getCollectionFields(db, collectionId);
|
|
6205
|
+
const workflowEnabled = await isPluginActive2(db, "workflow");
|
|
6206
|
+
const tinymceEnabled = await isPluginActive2(db, "tinymce-plugin");
|
|
6208
6207
|
let tinymceSettings;
|
|
6209
6208
|
if (tinymceEnabled) {
|
|
6210
|
-
const pluginService = new
|
|
6209
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
6211
6210
|
const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
|
|
6212
6211
|
tinymceSettings = tinymcePlugin2?.settings;
|
|
6213
6212
|
}
|
|
6214
|
-
const quillEnabled = await isPluginActive2(
|
|
6213
|
+
const quillEnabled = await isPluginActive2(db, "quill-editor");
|
|
6215
6214
|
let quillSettings;
|
|
6216
6215
|
if (quillEnabled) {
|
|
6217
|
-
const pluginService = new
|
|
6216
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
6218
6217
|
const quillPlugin = await pluginService.getPlugin("quill-editor");
|
|
6219
6218
|
quillSettings = quillPlugin?.settings;
|
|
6220
6219
|
}
|
|
6221
|
-
const mdxeditorEnabled = await isPluginActive2(
|
|
6220
|
+
const mdxeditorEnabled = await isPluginActive2(db, "easy-mdx");
|
|
6222
6221
|
let mdxeditorSettings;
|
|
6223
6222
|
if (mdxeditorEnabled) {
|
|
6224
|
-
const pluginService = new
|
|
6223
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
6225
6224
|
const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
|
|
6226
6225
|
mdxeditorSettings = mdxeditorPlugin?.settings;
|
|
6227
6226
|
}
|
|
@@ -6268,14 +6267,14 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
6268
6267
|
try {
|
|
6269
6268
|
const id = c.req.param("id");
|
|
6270
6269
|
const user = c.get("user");
|
|
6271
|
-
const
|
|
6270
|
+
const db = c.env.DB;
|
|
6272
6271
|
const url = new URL(c.req.url);
|
|
6273
6272
|
const referrerParams = url.searchParams.get("ref") || "";
|
|
6274
|
-
const cache =
|
|
6273
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.content);
|
|
6275
6274
|
const content = await cache.getOrSet(
|
|
6276
6275
|
cache.generateKey("content", id),
|
|
6277
6276
|
async () => {
|
|
6278
|
-
const contentStmt =
|
|
6277
|
+
const contentStmt = db.prepare(`
|
|
6279
6278
|
SELECT c.*, col.id as collection_id, col.name as collection_name,
|
|
6280
6279
|
col.display_name as collection_display_name, col.description as collection_description,
|
|
6281
6280
|
col.schema as collection_schema
|
|
@@ -6306,27 +6305,27 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
6306
6305
|
description: content.collection_description,
|
|
6307
6306
|
schema: content.collection_schema ? JSON.parse(content.collection_schema) : {}
|
|
6308
6307
|
};
|
|
6309
|
-
const fields = await getCollectionFields(
|
|
6308
|
+
const fields = await getCollectionFields(db, content.collection_id);
|
|
6310
6309
|
const contentData = content.data ? JSON.parse(content.data) : {};
|
|
6311
|
-
const workflowEnabled = await isPluginActive2(
|
|
6312
|
-
const tinymceEnabled = await isPluginActive2(
|
|
6310
|
+
const workflowEnabled = await isPluginActive2(db, "workflow");
|
|
6311
|
+
const tinymceEnabled = await isPluginActive2(db, "tinymce-plugin");
|
|
6313
6312
|
let tinymceSettings;
|
|
6314
6313
|
if (tinymceEnabled) {
|
|
6315
|
-
const pluginService = new
|
|
6314
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
6316
6315
|
const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
|
|
6317
6316
|
tinymceSettings = tinymcePlugin2?.settings;
|
|
6318
6317
|
}
|
|
6319
|
-
const quillEnabled = await isPluginActive2(
|
|
6318
|
+
const quillEnabled = await isPluginActive2(db, "quill-editor");
|
|
6320
6319
|
let quillSettings;
|
|
6321
6320
|
if (quillEnabled) {
|
|
6322
|
-
const pluginService = new
|
|
6321
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
6323
6322
|
const quillPlugin = await pluginService.getPlugin("quill-editor");
|
|
6324
6323
|
quillSettings = quillPlugin?.settings;
|
|
6325
6324
|
}
|
|
6326
|
-
const mdxeditorEnabled = await isPluginActive2(
|
|
6325
|
+
const mdxeditorEnabled = await isPluginActive2(db, "easy-mdx");
|
|
6327
6326
|
let mdxeditorSettings;
|
|
6328
6327
|
if (mdxeditorEnabled) {
|
|
6329
|
-
const pluginService = new
|
|
6328
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
6330
6329
|
const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
|
|
6331
6330
|
mdxeditorSettings = mdxeditorPlugin?.settings;
|
|
6332
6331
|
}
|
|
@@ -6388,8 +6387,8 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6388
6387
|
</div>
|
|
6389
6388
|
`);
|
|
6390
6389
|
}
|
|
6391
|
-
const
|
|
6392
|
-
const collection = await getCollection(
|
|
6390
|
+
const db = c.env.DB;
|
|
6391
|
+
const collection = await getCollection(db, collectionId);
|
|
6393
6392
|
if (!collection) {
|
|
6394
6393
|
return c.html(html.html`
|
|
6395
6394
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -6397,7 +6396,7 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6397
6396
|
</div>
|
|
6398
6397
|
`);
|
|
6399
6398
|
}
|
|
6400
|
-
const fields = await getCollectionFields(
|
|
6399
|
+
const fields = await getCollectionFields(db, collectionId);
|
|
6401
6400
|
const data = {};
|
|
6402
6401
|
const errors = {};
|
|
6403
6402
|
for (const field of fields) {
|
|
@@ -6455,7 +6454,7 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6455
6454
|
const scheduledUnpublishAt = formData.get("scheduled_unpublish_at");
|
|
6456
6455
|
const contentId = crypto.randomUUID();
|
|
6457
6456
|
const now = Date.now();
|
|
6458
|
-
const insertStmt =
|
|
6457
|
+
const insertStmt = db.prepare(`
|
|
6459
6458
|
INSERT INTO content (
|
|
6460
6459
|
id, collection_id, slug, title, data, status,
|
|
6461
6460
|
scheduled_publish_at, scheduled_unpublish_at,
|
|
@@ -6479,9 +6478,9 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6479
6478
|
now,
|
|
6480
6479
|
now
|
|
6481
6480
|
).run();
|
|
6482
|
-
const cache =
|
|
6481
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.content);
|
|
6483
6482
|
await cache.invalidate(`content:list:${collectionId}:*`);
|
|
6484
|
-
const versionStmt =
|
|
6483
|
+
const versionStmt = db.prepare(`
|
|
6485
6484
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
6486
6485
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
6487
6486
|
`);
|
|
@@ -6493,7 +6492,7 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6493
6492
|
user?.userId || "unknown",
|
|
6494
6493
|
now
|
|
6495
6494
|
).run();
|
|
6496
|
-
const workflowStmt =
|
|
6495
|
+
const workflowStmt = db.prepare(`
|
|
6497
6496
|
INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, created_at)
|
|
6498
6497
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
6499
6498
|
`);
|
|
@@ -6531,8 +6530,8 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6531
6530
|
const user = c.get("user");
|
|
6532
6531
|
const formData = await c.req.formData();
|
|
6533
6532
|
const action = formData.get("action");
|
|
6534
|
-
const
|
|
6535
|
-
const contentStmt =
|
|
6533
|
+
const db = c.env.DB;
|
|
6534
|
+
const contentStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
6536
6535
|
const existingContent = await contentStmt.bind(id).first();
|
|
6537
6536
|
if (!existingContent) {
|
|
6538
6537
|
return c.html(html.html`
|
|
@@ -6541,7 +6540,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6541
6540
|
</div>
|
|
6542
6541
|
`);
|
|
6543
6542
|
}
|
|
6544
|
-
const collection = await getCollection(
|
|
6543
|
+
const collection = await getCollection(db, existingContent.collection_id);
|
|
6545
6544
|
if (!collection) {
|
|
6546
6545
|
return c.html(html.html`
|
|
6547
6546
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -6549,7 +6548,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6549
6548
|
</div>
|
|
6550
6549
|
`);
|
|
6551
6550
|
}
|
|
6552
|
-
const fields = await getCollectionFields(
|
|
6551
|
+
const fields = await getCollectionFields(db, existingContent.collection_id);
|
|
6553
6552
|
const data = {};
|
|
6554
6553
|
const errors = {};
|
|
6555
6554
|
for (const field of fields) {
|
|
@@ -6608,7 +6607,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6608
6607
|
const scheduledPublishAt = formData.get("scheduled_publish_at");
|
|
6609
6608
|
const scheduledUnpublishAt = formData.get("scheduled_unpublish_at");
|
|
6610
6609
|
const now = Date.now();
|
|
6611
|
-
const updateStmt =
|
|
6610
|
+
const updateStmt = db.prepare(`
|
|
6612
6611
|
UPDATE content SET
|
|
6613
6612
|
slug = ?, title = ?, data = ?, status = ?,
|
|
6614
6613
|
scheduled_publish_at = ?, scheduled_unpublish_at = ?,
|
|
@@ -6627,15 +6626,15 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6627
6626
|
now,
|
|
6628
6627
|
id
|
|
6629
6628
|
).run();
|
|
6630
|
-
const cache =
|
|
6629
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.content);
|
|
6631
6630
|
await cache.delete(cache.generateKey("content", id));
|
|
6632
6631
|
await cache.invalidate(`content:list:${existingContent.collection_id}:*`);
|
|
6633
6632
|
const existingData = JSON.parse(existingContent.data || "{}");
|
|
6634
6633
|
if (JSON.stringify(existingData) !== JSON.stringify(data)) {
|
|
6635
|
-
const versionCountStmt =
|
|
6634
|
+
const versionCountStmt = db.prepare("SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?");
|
|
6636
6635
|
const versionResult = await versionCountStmt.bind(id).first();
|
|
6637
6636
|
const nextVersion = (versionResult?.max_version || 0) + 1;
|
|
6638
|
-
const versionStmt =
|
|
6637
|
+
const versionStmt = db.prepare(`
|
|
6639
6638
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
6640
6639
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
6641
6640
|
`);
|
|
@@ -6649,7 +6648,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6649
6648
|
).run();
|
|
6650
6649
|
}
|
|
6651
6650
|
if (status !== existingContent.status) {
|
|
6652
|
-
const workflowStmt =
|
|
6651
|
+
const workflowStmt = db.prepare(`
|
|
6653
6652
|
INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, created_at)
|
|
6654
6653
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
6655
6654
|
`);
|
|
@@ -6686,12 +6685,12 @@ adminContentRoutes.post("/preview", async (c) => {
|
|
|
6686
6685
|
try {
|
|
6687
6686
|
const formData = await c.req.formData();
|
|
6688
6687
|
const collectionId = formData.get("collection_id");
|
|
6689
|
-
const
|
|
6690
|
-
const collection = await getCollection(
|
|
6688
|
+
const db = c.env.DB;
|
|
6689
|
+
const collection = await getCollection(db, collectionId);
|
|
6691
6690
|
if (!collection) {
|
|
6692
6691
|
return c.html("<p>Collection not found</p>");
|
|
6693
6692
|
}
|
|
6694
|
-
const fields = await getCollectionFields(
|
|
6693
|
+
const fields = await getCollectionFields(db, collectionId);
|
|
6695
6694
|
const data = {};
|
|
6696
6695
|
for (const field of fields) {
|
|
6697
6696
|
const value = formData.get(field.field_name);
|
|
@@ -6765,8 +6764,8 @@ adminContentRoutes.post("/duplicate", async (c) => {
|
|
|
6765
6764
|
if (!originalId) {
|
|
6766
6765
|
return c.json({ success: false, error: "Content ID required" });
|
|
6767
6766
|
}
|
|
6768
|
-
const
|
|
6769
|
-
const contentStmt =
|
|
6767
|
+
const db = c.env.DB;
|
|
6768
|
+
const contentStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
6770
6769
|
const original = await contentStmt.bind(originalId).first();
|
|
6771
6770
|
if (!original) {
|
|
6772
6771
|
return c.json({ success: false, error: "Content not found" });
|
|
@@ -6775,7 +6774,7 @@ adminContentRoutes.post("/duplicate", async (c) => {
|
|
|
6775
6774
|
const now = Date.now();
|
|
6776
6775
|
const originalData = JSON.parse(original.data || "{}");
|
|
6777
6776
|
originalData.title = `${originalData.title || "Untitled"} (Copy)`;
|
|
6778
|
-
const insertStmt =
|
|
6777
|
+
const insertStmt = db.prepare(`
|
|
6779
6778
|
INSERT INTO content (
|
|
6780
6779
|
id, collection_id, slug, title, data, status,
|
|
6781
6780
|
author_id, created_at, updated_at
|
|
@@ -6898,11 +6897,11 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
6898
6897
|
if (!action || !ids || ids.length === 0) {
|
|
6899
6898
|
return c.json({ success: false, error: "Action and IDs required" });
|
|
6900
6899
|
}
|
|
6901
|
-
const
|
|
6900
|
+
const db = c.env.DB;
|
|
6902
6901
|
const now = Date.now();
|
|
6903
6902
|
if (action === "delete") {
|
|
6904
6903
|
const placeholders = ids.map(() => "?").join(",");
|
|
6905
|
-
const stmt =
|
|
6904
|
+
const stmt = db.prepare(`
|
|
6906
6905
|
UPDATE content
|
|
6907
6906
|
SET status = 'deleted', updated_at = ?
|
|
6908
6907
|
WHERE id IN (${placeholders})
|
|
@@ -6911,7 +6910,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
6911
6910
|
} else if (action === "publish" || action === "draft") {
|
|
6912
6911
|
const placeholders = ids.map(() => "?").join(",");
|
|
6913
6912
|
const publishedAt = action === "publish" ? now : null;
|
|
6914
|
-
const stmt =
|
|
6913
|
+
const stmt = db.prepare(`
|
|
6915
6914
|
UPDATE content
|
|
6916
6915
|
SET status = ?, published_at = ?, updated_at = ?
|
|
6917
6916
|
WHERE id IN (${placeholders})
|
|
@@ -6920,7 +6919,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
6920
6919
|
} else {
|
|
6921
6920
|
return c.json({ success: false, error: "Invalid action" });
|
|
6922
6921
|
}
|
|
6923
|
-
const cache =
|
|
6922
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.content);
|
|
6924
6923
|
for (const contentId of ids) {
|
|
6925
6924
|
await cache.delete(cache.generateKey("content", contentId));
|
|
6926
6925
|
}
|
|
@@ -6934,21 +6933,21 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
6934
6933
|
adminContentRoutes.delete("/:id", async (c) => {
|
|
6935
6934
|
try {
|
|
6936
6935
|
const id = c.req.param("id");
|
|
6937
|
-
const
|
|
6936
|
+
const db = c.env.DB;
|
|
6938
6937
|
const user = c.get("user");
|
|
6939
|
-
const contentStmt =
|
|
6938
|
+
const contentStmt = db.prepare("SELECT id, title FROM content WHERE id = ?");
|
|
6940
6939
|
const content = await contentStmt.bind(id).first();
|
|
6941
6940
|
if (!content) {
|
|
6942
6941
|
return c.json({ success: false, error: "Content not found" }, 404);
|
|
6943
6942
|
}
|
|
6944
6943
|
const now = Date.now();
|
|
6945
|
-
const deleteStmt =
|
|
6944
|
+
const deleteStmt = db.prepare(`
|
|
6946
6945
|
UPDATE content
|
|
6947
6946
|
SET status = 'deleted', updated_at = ?
|
|
6948
6947
|
WHERE id = ?
|
|
6949
6948
|
`);
|
|
6950
6949
|
await deleteStmt.bind(now, id).run();
|
|
6951
|
-
const cache =
|
|
6950
|
+
const cache = chunkES3BRZQJ_cjs.getCacheService(chunkES3BRZQJ_cjs.CACHE_CONFIGS.content);
|
|
6952
6951
|
await cache.delete(cache.generateKey("content", id));
|
|
6953
6952
|
await cache.invalidate("content:list:*");
|
|
6954
6953
|
return c.html(`
|
|
@@ -6971,13 +6970,13 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
6971
6970
|
adminContentRoutes.get("/:id/versions", async (c) => {
|
|
6972
6971
|
try {
|
|
6973
6972
|
const id = c.req.param("id");
|
|
6974
|
-
const
|
|
6975
|
-
const contentStmt =
|
|
6973
|
+
const db = c.env.DB;
|
|
6974
|
+
const contentStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
6976
6975
|
const content = await contentStmt.bind(id).first();
|
|
6977
6976
|
if (!content) {
|
|
6978
6977
|
return c.html("<p>Content not found</p>");
|
|
6979
6978
|
}
|
|
6980
|
-
const versionsStmt =
|
|
6979
|
+
const versionsStmt = db.prepare(`
|
|
6981
6980
|
SELECT cv.*, u.first_name, u.last_name, u.email
|
|
6982
6981
|
FROM content_versions cv
|
|
6983
6982
|
LEFT JOIN users u ON cv.author_id = u.id
|
|
@@ -7014,8 +7013,8 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
|
|
|
7014
7013
|
const id = c.req.param("id");
|
|
7015
7014
|
const version = parseInt(c.req.param("version"));
|
|
7016
7015
|
const user = c.get("user");
|
|
7017
|
-
const
|
|
7018
|
-
const versionStmt =
|
|
7016
|
+
const db = c.env.DB;
|
|
7017
|
+
const versionStmt = db.prepare(`
|
|
7019
7018
|
SELECT * FROM content_versions
|
|
7020
7019
|
WHERE content_id = ? AND version = ?
|
|
7021
7020
|
`);
|
|
@@ -7023,14 +7022,14 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
|
|
|
7023
7022
|
if (!versionData) {
|
|
7024
7023
|
return c.json({ success: false, error: "Version not found" });
|
|
7025
7024
|
}
|
|
7026
|
-
const contentStmt =
|
|
7025
|
+
const contentStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
7027
7026
|
const currentContent = await contentStmt.bind(id).first();
|
|
7028
7027
|
if (!currentContent) {
|
|
7029
7028
|
return c.json({ success: false, error: "Content not found" });
|
|
7030
7029
|
}
|
|
7031
7030
|
const restoredData = JSON.parse(versionData.data);
|
|
7032
7031
|
const now = Date.now();
|
|
7033
|
-
const updateStmt =
|
|
7032
|
+
const updateStmt = db.prepare(`
|
|
7034
7033
|
UPDATE content SET
|
|
7035
7034
|
title = ?, data = ?, updated_at = ?
|
|
7036
7035
|
WHERE id = ?
|
|
@@ -7041,10 +7040,10 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
|
|
|
7041
7040
|
now,
|
|
7042
7041
|
id
|
|
7043
7042
|
).run();
|
|
7044
|
-
const nextVersionStmt =
|
|
7043
|
+
const nextVersionStmt = db.prepare("SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?");
|
|
7045
7044
|
const nextVersionResult = await nextVersionStmt.bind(id).first();
|
|
7046
7045
|
const nextVersion = (nextVersionResult?.max_version || 0) + 1;
|
|
7047
|
-
const newVersionStmt =
|
|
7046
|
+
const newVersionStmt = db.prepare(`
|
|
7048
7047
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
7049
7048
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
7050
7049
|
`);
|
|
@@ -7056,7 +7055,7 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
|
|
|
7056
7055
|
user?.userId || "unknown",
|
|
7057
7056
|
now
|
|
7058
7057
|
).run();
|
|
7059
|
-
const workflowStmt =
|
|
7058
|
+
const workflowStmt = db.prepare(`
|
|
7060
7059
|
INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, comment, created_at)
|
|
7061
7060
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
7062
7061
|
`);
|
|
@@ -7080,8 +7079,8 @@ adminContentRoutes.get("/:id/version/:version/preview", async (c) => {
|
|
|
7080
7079
|
try {
|
|
7081
7080
|
const id = c.req.param("id");
|
|
7082
7081
|
const version = parseInt(c.req.param("version"));
|
|
7083
|
-
const
|
|
7084
|
-
const versionStmt =
|
|
7082
|
+
const db = c.env.DB;
|
|
7083
|
+
const versionStmt = db.prepare(`
|
|
7085
7084
|
SELECT cv.*, c.collection_id, col.display_name as collection_name
|
|
7086
7085
|
FROM content_versions cv
|
|
7087
7086
|
JOIN content c ON cv.content_id = c.id
|
|
@@ -7992,7 +7991,7 @@ function renderUserEditPage(data) {
|
|
|
7992
7991
|
<input
|
|
7993
7992
|
type="text"
|
|
7994
7993
|
name="first_name"
|
|
7995
|
-
value="${
|
|
7994
|
+
value="${chunk44LBCF3B_cjs.escapeHtml(data.userToEdit.firstName || "")}"
|
|
7996
7995
|
required
|
|
7997
7996
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
7998
7997
|
/>
|
|
@@ -8003,7 +8002,7 @@ function renderUserEditPage(data) {
|
|
|
8003
8002
|
<input
|
|
8004
8003
|
type="text"
|
|
8005
8004
|
name="last_name"
|
|
8006
|
-
value="${
|
|
8005
|
+
value="${chunk44LBCF3B_cjs.escapeHtml(data.userToEdit.lastName || "")}"
|
|
8007
8006
|
required
|
|
8008
8007
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8009
8008
|
/>
|
|
@@ -8014,7 +8013,7 @@ function renderUserEditPage(data) {
|
|
|
8014
8013
|
<input
|
|
8015
8014
|
type="text"
|
|
8016
8015
|
name="username"
|
|
8017
|
-
value="${
|
|
8016
|
+
value="${chunk44LBCF3B_cjs.escapeHtml(data.userToEdit.username || "")}"
|
|
8018
8017
|
required
|
|
8019
8018
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8020
8019
|
/>
|
|
@@ -8025,7 +8024,7 @@ function renderUserEditPage(data) {
|
|
|
8025
8024
|
<input
|
|
8026
8025
|
type="email"
|
|
8027
8026
|
name="email"
|
|
8028
|
-
value="${
|
|
8027
|
+
value="${chunk44LBCF3B_cjs.escapeHtml(data.userToEdit.email || "")}"
|
|
8029
8028
|
required
|
|
8030
8029
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8031
8030
|
/>
|
|
@@ -8036,7 +8035,7 @@ function renderUserEditPage(data) {
|
|
|
8036
8035
|
<input
|
|
8037
8036
|
type="tel"
|
|
8038
8037
|
name="phone"
|
|
8039
|
-
value="${
|
|
8038
|
+
value="${chunk44LBCF3B_cjs.escapeHtml(data.userToEdit.phone || "")}"
|
|
8040
8039
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8041
8040
|
/>
|
|
8042
8041
|
</div>
|
|
@@ -8050,7 +8049,7 @@ function renderUserEditPage(data) {
|
|
|
8050
8049
|
class="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white/5 dark:bg-white/5 py-1.5 pl-3 pr-8 text-base text-zinc-950 dark:text-white outline outline-1 -outline-offset-1 outline-zinc-500/30 dark:outline-zinc-400/30 *:bg-white dark:*:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-zinc-500 dark:focus-visible:outline-zinc-400 sm:text-sm/6"
|
|
8051
8050
|
>
|
|
8052
8051
|
${data.roles.map((role) => `
|
|
8053
|
-
<option value="${
|
|
8052
|
+
<option value="${chunk44LBCF3B_cjs.escapeHtml(role.value)}" ${data.userToEdit.role === role.value ? "selected" : ""}>${chunk44LBCF3B_cjs.escapeHtml(role.label)}</option>
|
|
8054
8053
|
`).join("")}
|
|
8055
8054
|
</select>
|
|
8056
8055
|
<svg viewBox="0 0 16 16" fill="currentColor" data-slot="icon" aria-hidden="true" class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-zinc-600 dark:text-zinc-400 sm:size-4">
|
|
@@ -8066,7 +8065,7 @@ function renderUserEditPage(data) {
|
|
|
8066
8065
|
name="bio"
|
|
8067
8066
|
rows="3"
|
|
8068
8067
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8069
|
-
>${
|
|
8068
|
+
>${chunk44LBCF3B_cjs.escapeHtml(data.userToEdit.bio || "")}</textarea>
|
|
8070
8069
|
</div>
|
|
8071
8070
|
</div>
|
|
8072
8071
|
|
|
@@ -8966,7 +8965,7 @@ function renderUsersListPage(data) {
|
|
|
8966
8965
|
|
|
8967
8966
|
// src/routes/admin-users.ts
|
|
8968
8967
|
var userRoutes = new hono.Hono();
|
|
8969
|
-
userRoutes.use("*",
|
|
8968
|
+
userRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
8970
8969
|
userRoutes.get("/", (c) => {
|
|
8971
8970
|
return c.redirect("/admin/dashboard");
|
|
8972
8971
|
});
|
|
@@ -9002,9 +9001,9 @@ var ROLES = [
|
|
|
9002
9001
|
];
|
|
9003
9002
|
userRoutes.get("/profile", async (c) => {
|
|
9004
9003
|
const user = c.get("user");
|
|
9005
|
-
const
|
|
9004
|
+
const db = c.env.DB;
|
|
9006
9005
|
try {
|
|
9007
|
-
const userStmt =
|
|
9006
|
+
const userStmt = db.prepare(`
|
|
9008
9007
|
SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
|
|
9009
9008
|
timezone, language, theme, email_notifications, two_factor_enabled,
|
|
9010
9009
|
role, created_at, last_login_at
|
|
@@ -9062,15 +9061,15 @@ userRoutes.get("/profile", async (c) => {
|
|
|
9062
9061
|
});
|
|
9063
9062
|
userRoutes.put("/profile", async (c) => {
|
|
9064
9063
|
const user = c.get("user");
|
|
9065
|
-
const
|
|
9064
|
+
const db = c.env.DB;
|
|
9066
9065
|
try {
|
|
9067
9066
|
const formData = await c.req.formData();
|
|
9068
|
-
const firstName =
|
|
9069
|
-
const lastName =
|
|
9070
|
-
const username =
|
|
9067
|
+
const firstName = chunk44LBCF3B_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9068
|
+
const lastName = chunk44LBCF3B_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9069
|
+
const username = chunk44LBCF3B_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
9071
9070
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9072
|
-
const phone =
|
|
9073
|
-
const bio =
|
|
9071
|
+
const phone = chunk44LBCF3B_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9072
|
+
const bio = chunk44LBCF3B_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
9074
9073
|
const timezone = formData.get("timezone")?.toString() || "UTC";
|
|
9075
9074
|
const language = formData.get("language")?.toString() || "en";
|
|
9076
9075
|
const emailNotifications = formData.get("email_notifications") === "1";
|
|
@@ -9089,7 +9088,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
9089
9088
|
dismissible: true
|
|
9090
9089
|
}));
|
|
9091
9090
|
}
|
|
9092
|
-
const checkStmt =
|
|
9091
|
+
const checkStmt = db.prepare(`
|
|
9093
9092
|
SELECT id FROM users
|
|
9094
9093
|
WHERE (username = ? OR email = ?) AND id != ? AND is_active = 1
|
|
9095
9094
|
`);
|
|
@@ -9101,7 +9100,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
9101
9100
|
dismissible: true
|
|
9102
9101
|
}));
|
|
9103
9102
|
}
|
|
9104
|
-
const updateStmt =
|
|
9103
|
+
const updateStmt = db.prepare(`
|
|
9105
9104
|
UPDATE users SET
|
|
9106
9105
|
first_name = ?, last_name = ?, username = ?, email = ?,
|
|
9107
9106
|
phone = ?, bio = ?, timezone = ?, language = ?,
|
|
@@ -9121,8 +9120,8 @@ userRoutes.put("/profile", async (c) => {
|
|
|
9121
9120
|
Date.now(),
|
|
9122
9121
|
user.userId
|
|
9123
9122
|
).run();
|
|
9124
|
-
await
|
|
9125
|
-
|
|
9123
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9124
|
+
db,
|
|
9126
9125
|
user.userId,
|
|
9127
9126
|
"profile.update",
|
|
9128
9127
|
"users",
|
|
@@ -9147,7 +9146,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
9147
9146
|
});
|
|
9148
9147
|
userRoutes.post("/profile/avatar", async (c) => {
|
|
9149
9148
|
const user = c.get("user");
|
|
9150
|
-
const
|
|
9149
|
+
const db = c.env.DB;
|
|
9151
9150
|
try {
|
|
9152
9151
|
const formData = await c.req.formData();
|
|
9153
9152
|
const avatarFile = formData.get("avatar");
|
|
@@ -9175,17 +9174,17 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
9175
9174
|
}));
|
|
9176
9175
|
}
|
|
9177
9176
|
const avatarUrl = `/uploads/avatars/${user.userId}-${Date.now()}.${avatarFile.type.split("/")[1]}`;
|
|
9178
|
-
const updateStmt =
|
|
9177
|
+
const updateStmt = db.prepare(`
|
|
9179
9178
|
UPDATE users SET avatar_url = ?, updated_at = ?
|
|
9180
9179
|
WHERE id = ?
|
|
9181
9180
|
`);
|
|
9182
9181
|
await updateStmt.bind(avatarUrl, Date.now(), user.userId).run();
|
|
9183
|
-
const userStmt =
|
|
9182
|
+
const userStmt = db.prepare(`
|
|
9184
9183
|
SELECT first_name, last_name FROM users WHERE id = ?
|
|
9185
9184
|
`);
|
|
9186
9185
|
const userData = await userStmt.bind(user.userId).first();
|
|
9187
|
-
await
|
|
9188
|
-
|
|
9186
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9187
|
+
db,
|
|
9189
9188
|
user.userId,
|
|
9190
9189
|
"profile.avatar_update",
|
|
9191
9190
|
"users",
|
|
@@ -9217,7 +9216,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
9217
9216
|
});
|
|
9218
9217
|
userRoutes.post("/profile/password", async (c) => {
|
|
9219
9218
|
const user = c.get("user");
|
|
9220
|
-
const
|
|
9219
|
+
const db = c.env.DB;
|
|
9221
9220
|
try {
|
|
9222
9221
|
const formData = await c.req.formData();
|
|
9223
9222
|
const currentPassword = formData.get("current_password")?.toString() || "";
|
|
@@ -9244,7 +9243,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9244
9243
|
dismissible: true
|
|
9245
9244
|
}));
|
|
9246
9245
|
}
|
|
9247
|
-
const userStmt =
|
|
9246
|
+
const userStmt = db.prepare(`
|
|
9248
9247
|
SELECT password_hash FROM users WHERE id = ? AND is_active = 1
|
|
9249
9248
|
`);
|
|
9250
9249
|
const userData = await userStmt.bind(user.userId).first();
|
|
@@ -9255,7 +9254,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9255
9254
|
dismissible: true
|
|
9256
9255
|
}));
|
|
9257
9256
|
}
|
|
9258
|
-
const validPassword = await
|
|
9257
|
+
const validPassword = await chunk5UUYHAZT_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
|
|
9259
9258
|
if (!validPassword) {
|
|
9260
9259
|
return c.html(renderAlert2({
|
|
9261
9260
|
type: "error",
|
|
@@ -9263,8 +9262,8 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9263
9262
|
dismissible: true
|
|
9264
9263
|
}));
|
|
9265
9264
|
}
|
|
9266
|
-
const newPasswordHash = await
|
|
9267
|
-
const historyStmt =
|
|
9265
|
+
const newPasswordHash = await chunk5UUYHAZT_cjs.AuthManager.hashPassword(newPassword);
|
|
9266
|
+
const historyStmt = db.prepare(`
|
|
9268
9267
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
9269
9268
|
VALUES (?, ?, ?, ?)
|
|
9270
9269
|
`);
|
|
@@ -9274,13 +9273,13 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9274
9273
|
userData.password_hash,
|
|
9275
9274
|
Date.now()
|
|
9276
9275
|
).run();
|
|
9277
|
-
const updateStmt =
|
|
9276
|
+
const updateStmt = db.prepare(`
|
|
9278
9277
|
UPDATE users SET password_hash = ?, updated_at = ?
|
|
9279
9278
|
WHERE id = ?
|
|
9280
9279
|
`);
|
|
9281
9280
|
await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
|
|
9282
|
-
await
|
|
9283
|
-
|
|
9281
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9282
|
+
db,
|
|
9284
9283
|
user.userId,
|
|
9285
9284
|
"profile.password_change",
|
|
9286
9285
|
"users",
|
|
@@ -9304,7 +9303,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9304
9303
|
}
|
|
9305
9304
|
});
|
|
9306
9305
|
userRoutes.get("/users", async (c) => {
|
|
9307
|
-
const
|
|
9306
|
+
const db = c.env.DB;
|
|
9308
9307
|
const user = c.get("user");
|
|
9309
9308
|
try {
|
|
9310
9309
|
const page = parseInt(c.req.query("page") || "1");
|
|
@@ -9331,7 +9330,7 @@ userRoutes.get("/users", async (c) => {
|
|
|
9331
9330
|
whereClause += " AND u.role = ?";
|
|
9332
9331
|
params.push(roleFilter);
|
|
9333
9332
|
}
|
|
9334
|
-
const usersStmt =
|
|
9333
|
+
const usersStmt = db.prepare(`
|
|
9335
9334
|
SELECT u.id, u.email, u.username, u.first_name, u.last_name,
|
|
9336
9335
|
u.role, u.avatar_url, u.created_at, u.last_login_at, u.updated_at,
|
|
9337
9336
|
u.email_verified, u.two_factor_enabled, u.is_active
|
|
@@ -9341,13 +9340,13 @@ userRoutes.get("/users", async (c) => {
|
|
|
9341
9340
|
LIMIT ? OFFSET ?
|
|
9342
9341
|
`);
|
|
9343
9342
|
const { results: usersData } = await usersStmt.bind(...params, limit, offset).all();
|
|
9344
|
-
const countStmt =
|
|
9343
|
+
const countStmt = db.prepare(`
|
|
9345
9344
|
SELECT COUNT(*) as total FROM users u ${whereClause}
|
|
9346
9345
|
`);
|
|
9347
9346
|
const countResult = await countStmt.bind(...params).first();
|
|
9348
9347
|
const totalUsers = countResult?.total || 0;
|
|
9349
|
-
await
|
|
9350
|
-
|
|
9348
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9349
|
+
db,
|
|
9351
9350
|
user.userId,
|
|
9352
9351
|
"users.list_view",
|
|
9353
9352
|
"users",
|
|
@@ -9444,16 +9443,16 @@ userRoutes.get("/users/new", async (c) => {
|
|
|
9444
9443
|
}
|
|
9445
9444
|
});
|
|
9446
9445
|
userRoutes.post("/users/new", async (c) => {
|
|
9447
|
-
const
|
|
9446
|
+
const db = c.env.DB;
|
|
9448
9447
|
const user = c.get("user");
|
|
9449
9448
|
try {
|
|
9450
9449
|
const formData = await c.req.formData();
|
|
9451
|
-
const firstName =
|
|
9452
|
-
const lastName =
|
|
9453
|
-
const username =
|
|
9450
|
+
const firstName = chunk44LBCF3B_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9451
|
+
const lastName = chunk44LBCF3B_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9452
|
+
const username = chunk44LBCF3B_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
9454
9453
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9455
|
-
const phone =
|
|
9456
|
-
const bio =
|
|
9454
|
+
const phone = chunk44LBCF3B_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9455
|
+
const bio = chunk44LBCF3B_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
9457
9456
|
const role = formData.get("role")?.toString() || "viewer";
|
|
9458
9457
|
const password = formData.get("password")?.toString() || "";
|
|
9459
9458
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
@@ -9488,7 +9487,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9488
9487
|
dismissible: true
|
|
9489
9488
|
}));
|
|
9490
9489
|
}
|
|
9491
|
-
const checkStmt =
|
|
9490
|
+
const checkStmt = db.prepare(`
|
|
9492
9491
|
SELECT id FROM users
|
|
9493
9492
|
WHERE username = ? OR email = ?
|
|
9494
9493
|
`);
|
|
@@ -9500,9 +9499,9 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9500
9499
|
dismissible: true
|
|
9501
9500
|
}));
|
|
9502
9501
|
}
|
|
9503
|
-
const passwordHash = await
|
|
9502
|
+
const passwordHash = await chunk5UUYHAZT_cjs.AuthManager.hashPassword(password);
|
|
9504
9503
|
const userId = crypto.randomUUID();
|
|
9505
|
-
const createStmt =
|
|
9504
|
+
const createStmt = db.prepare(`
|
|
9506
9505
|
INSERT INTO users (
|
|
9507
9506
|
id, email, username, first_name, last_name, phone, bio,
|
|
9508
9507
|
password_hash, role, is_active, email_verified, created_at, updated_at
|
|
@@ -9523,8 +9522,8 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9523
9522
|
Date.now(),
|
|
9524
9523
|
Date.now()
|
|
9525
9524
|
).run();
|
|
9526
|
-
await
|
|
9527
|
-
|
|
9525
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9526
|
+
db,
|
|
9528
9527
|
user.userId,
|
|
9529
9528
|
"user!.create",
|
|
9530
9529
|
"users",
|
|
@@ -9547,11 +9546,11 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
9547
9546
|
if (c.req.path.endsWith("/edit")) {
|
|
9548
9547
|
return c.notFound();
|
|
9549
9548
|
}
|
|
9550
|
-
const
|
|
9549
|
+
const db = c.env.DB;
|
|
9551
9550
|
const user = c.get("user");
|
|
9552
9551
|
const userId = c.req.param("id");
|
|
9553
9552
|
try {
|
|
9554
|
-
const userStmt =
|
|
9553
|
+
const userStmt = db.prepare(`
|
|
9555
9554
|
SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
|
|
9556
9555
|
role, is_active, email_verified, two_factor_enabled, created_at, last_login_at
|
|
9557
9556
|
FROM users
|
|
@@ -9561,8 +9560,8 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
9561
9560
|
if (!userRecord) {
|
|
9562
9561
|
return c.json({ error: "User not found" }, 404);
|
|
9563
9562
|
}
|
|
9564
|
-
await
|
|
9565
|
-
|
|
9563
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9564
|
+
db,
|
|
9566
9565
|
user.userId,
|
|
9567
9566
|
"user!.view",
|
|
9568
9567
|
"users",
|
|
@@ -9595,11 +9594,11 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
9595
9594
|
}
|
|
9596
9595
|
});
|
|
9597
9596
|
userRoutes.get("/users/:id/edit", async (c) => {
|
|
9598
|
-
const
|
|
9597
|
+
const db = c.env.DB;
|
|
9599
9598
|
const user = c.get("user");
|
|
9600
9599
|
const userId = c.req.param("id");
|
|
9601
9600
|
try {
|
|
9602
|
-
const userStmt =
|
|
9601
|
+
const userStmt = db.prepare(`
|
|
9603
9602
|
SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
|
|
9604
9603
|
role, is_active, email_verified, two_factor_enabled, created_at, last_login_at
|
|
9605
9604
|
FROM users
|
|
@@ -9649,17 +9648,17 @@ userRoutes.get("/users/:id/edit", async (c) => {
|
|
|
9649
9648
|
}
|
|
9650
9649
|
});
|
|
9651
9650
|
userRoutes.put("/users/:id", async (c) => {
|
|
9652
|
-
const
|
|
9651
|
+
const db = c.env.DB;
|
|
9653
9652
|
const user = c.get("user");
|
|
9654
9653
|
const userId = c.req.param("id");
|
|
9655
9654
|
try {
|
|
9656
9655
|
const formData = await c.req.formData();
|
|
9657
|
-
const firstName =
|
|
9658
|
-
const lastName =
|
|
9659
|
-
const username =
|
|
9656
|
+
const firstName = chunk44LBCF3B_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9657
|
+
const lastName = chunk44LBCF3B_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9658
|
+
const username = chunk44LBCF3B_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
9660
9659
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9661
|
-
const phone =
|
|
9662
|
-
const bio =
|
|
9660
|
+
const phone = chunk44LBCF3B_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9661
|
+
const bio = chunk44LBCF3B_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
9663
9662
|
const role = formData.get("role")?.toString() || "viewer";
|
|
9664
9663
|
const isActive = formData.get("is_active") === "1";
|
|
9665
9664
|
const emailVerified = formData.get("email_verified") === "1";
|
|
@@ -9678,7 +9677,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9678
9677
|
dismissible: true
|
|
9679
9678
|
}));
|
|
9680
9679
|
}
|
|
9681
|
-
const checkStmt =
|
|
9680
|
+
const checkStmt = db.prepare(`
|
|
9682
9681
|
SELECT id FROM users
|
|
9683
9682
|
WHERE (username = ? OR email = ?) AND id != ?
|
|
9684
9683
|
`);
|
|
@@ -9690,7 +9689,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9690
9689
|
dismissible: true
|
|
9691
9690
|
}));
|
|
9692
9691
|
}
|
|
9693
|
-
const updateStmt =
|
|
9692
|
+
const updateStmt = db.prepare(`
|
|
9694
9693
|
UPDATE users SET
|
|
9695
9694
|
first_name = ?, last_name = ?, username = ?, email = ?,
|
|
9696
9695
|
phone = ?, bio = ?, role = ?, is_active = ?, email_verified = ?,
|
|
@@ -9710,8 +9709,8 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9710
9709
|
Date.now(),
|
|
9711
9710
|
userId
|
|
9712
9711
|
).run();
|
|
9713
|
-
await
|
|
9714
|
-
|
|
9712
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9713
|
+
db,
|
|
9715
9714
|
user.userId,
|
|
9716
9715
|
"user!.update",
|
|
9717
9716
|
"users",
|
|
@@ -9735,7 +9734,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9735
9734
|
}
|
|
9736
9735
|
});
|
|
9737
9736
|
userRoutes.post("/users/:id/toggle", async (c) => {
|
|
9738
|
-
const
|
|
9737
|
+
const db = c.env.DB;
|
|
9739
9738
|
const user = c.get("user");
|
|
9740
9739
|
const userId = c.req.param("id");
|
|
9741
9740
|
try {
|
|
@@ -9744,19 +9743,19 @@ userRoutes.post("/users/:id/toggle", async (c) => {
|
|
|
9744
9743
|
if (userId === user.userId && !active) {
|
|
9745
9744
|
return c.json({ error: "You cannot deactivate your own account" }, 400);
|
|
9746
9745
|
}
|
|
9747
|
-
const userStmt =
|
|
9746
|
+
const userStmt = db.prepare(`
|
|
9748
9747
|
SELECT id, email FROM users WHERE id = ?
|
|
9749
9748
|
`);
|
|
9750
9749
|
const userToToggle = await userStmt.bind(userId).first();
|
|
9751
9750
|
if (!userToToggle) {
|
|
9752
9751
|
return c.json({ error: "User not found" }, 404);
|
|
9753
9752
|
}
|
|
9754
|
-
const toggleStmt =
|
|
9753
|
+
const toggleStmt = db.prepare(`
|
|
9755
9754
|
UPDATE users SET is_active = ?, updated_at = ? WHERE id = ?
|
|
9756
9755
|
`);
|
|
9757
9756
|
await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run();
|
|
9758
|
-
await
|
|
9759
|
-
|
|
9757
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9758
|
+
db,
|
|
9760
9759
|
user.userId,
|
|
9761
9760
|
active ? "user.activate" : "user.deactivate",
|
|
9762
9761
|
"users",
|
|
@@ -9775,7 +9774,7 @@ userRoutes.post("/users/:id/toggle", async (c) => {
|
|
|
9775
9774
|
}
|
|
9776
9775
|
});
|
|
9777
9776
|
userRoutes.delete("/users/:id", async (c) => {
|
|
9778
|
-
const
|
|
9777
|
+
const db = c.env.DB;
|
|
9779
9778
|
const user = c.get("user");
|
|
9780
9779
|
const userId = c.req.param("id");
|
|
9781
9780
|
try {
|
|
@@ -9784,7 +9783,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9784
9783
|
if (userId === user.userId) {
|
|
9785
9784
|
return c.json({ error: "You cannot delete your own account" }, 400);
|
|
9786
9785
|
}
|
|
9787
|
-
const userStmt =
|
|
9786
|
+
const userStmt = db.prepare(`
|
|
9788
9787
|
SELECT id, email FROM users WHERE id = ?
|
|
9789
9788
|
`);
|
|
9790
9789
|
const userToDelete = await userStmt.bind(userId).first();
|
|
@@ -9792,12 +9791,12 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9792
9791
|
return c.json({ error: "User not found" }, 404);
|
|
9793
9792
|
}
|
|
9794
9793
|
if (hardDelete) {
|
|
9795
|
-
const deleteStmt =
|
|
9794
|
+
const deleteStmt = db.prepare(`
|
|
9796
9795
|
DELETE FROM users WHERE id = ?
|
|
9797
9796
|
`);
|
|
9798
9797
|
await deleteStmt.bind(userId).run();
|
|
9799
|
-
await
|
|
9800
|
-
|
|
9798
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9799
|
+
db,
|
|
9801
9800
|
user.userId,
|
|
9802
9801
|
"user!.hard_delete",
|
|
9803
9802
|
"users",
|
|
@@ -9811,12 +9810,12 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9811
9810
|
message: "User permanently deleted"
|
|
9812
9811
|
});
|
|
9813
9812
|
} else {
|
|
9814
|
-
const deleteStmt =
|
|
9813
|
+
const deleteStmt = db.prepare(`
|
|
9815
9814
|
UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?
|
|
9816
9815
|
`);
|
|
9817
9816
|
await deleteStmt.bind(Date.now(), userId).run();
|
|
9818
|
-
await
|
|
9819
|
-
|
|
9817
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9818
|
+
db,
|
|
9820
9819
|
user.userId,
|
|
9821
9820
|
"user!.soft_delete",
|
|
9822
9821
|
"users",
|
|
@@ -9836,14 +9835,14 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9836
9835
|
}
|
|
9837
9836
|
});
|
|
9838
9837
|
userRoutes.post("/invite-user", async (c) => {
|
|
9839
|
-
const
|
|
9838
|
+
const db = c.env.DB;
|
|
9840
9839
|
const user = c.get("user");
|
|
9841
9840
|
try {
|
|
9842
9841
|
const formData = await c.req.formData();
|
|
9843
9842
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9844
9843
|
const role = formData.get("role")?.toString()?.trim() || "viewer";
|
|
9845
|
-
const firstName =
|
|
9846
|
-
const lastName =
|
|
9844
|
+
const firstName = chunk44LBCF3B_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9845
|
+
const lastName = chunk44LBCF3B_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9847
9846
|
if (!email || !firstName || !lastName) {
|
|
9848
9847
|
return c.json({ error: "Email, first name, and last name are required" }, 400);
|
|
9849
9848
|
}
|
|
@@ -9851,7 +9850,7 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9851
9850
|
if (!emailRegex.test(email)) {
|
|
9852
9851
|
return c.json({ error: "Please enter a valid email address" }, 400);
|
|
9853
9852
|
}
|
|
9854
|
-
const existingUserStmt =
|
|
9853
|
+
const existingUserStmt = db.prepare(`
|
|
9855
9854
|
SELECT id FROM users WHERE email = ?
|
|
9856
9855
|
`);
|
|
9857
9856
|
const existingUser = await existingUserStmt.bind(email).first();
|
|
@@ -9860,7 +9859,7 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9860
9859
|
}
|
|
9861
9860
|
const invitationToken = crypto.randomUUID();
|
|
9862
9861
|
const userId = crypto.randomUUID();
|
|
9863
|
-
const createUserStmt =
|
|
9862
|
+
const createUserStmt = db.prepare(`
|
|
9864
9863
|
INSERT INTO users (
|
|
9865
9864
|
id, email, first_name, last_name, role,
|
|
9866
9865
|
invitation_token, invited_by, invited_at,
|
|
@@ -9881,8 +9880,8 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9881
9880
|
Date.now(),
|
|
9882
9881
|
Date.now()
|
|
9883
9882
|
).run();
|
|
9884
|
-
await
|
|
9885
|
-
|
|
9883
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9884
|
+
db,
|
|
9886
9885
|
user.userId,
|
|
9887
9886
|
"user!.invite_sent",
|
|
9888
9887
|
"users",
|
|
@@ -9911,11 +9910,11 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9911
9910
|
}
|
|
9912
9911
|
});
|
|
9913
9912
|
userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
9914
|
-
const
|
|
9913
|
+
const db = c.env.DB;
|
|
9915
9914
|
const user = c.get("user");
|
|
9916
9915
|
const userId = c.req.param("id");
|
|
9917
9916
|
try {
|
|
9918
|
-
const userStmt =
|
|
9917
|
+
const userStmt = db.prepare(`
|
|
9919
9918
|
SELECT id, email, first_name, last_name, role, invitation_token
|
|
9920
9919
|
FROM users
|
|
9921
9920
|
WHERE id = ? AND is_active = 0 AND invitation_token IS NOT NULL
|
|
@@ -9925,7 +9924,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
9925
9924
|
return c.json({ error: "User not found or invitation not valid" }, 404);
|
|
9926
9925
|
}
|
|
9927
9926
|
const newInvitationToken = crypto.randomUUID();
|
|
9928
|
-
const updateStmt =
|
|
9927
|
+
const updateStmt = db.prepare(`
|
|
9929
9928
|
UPDATE users SET
|
|
9930
9929
|
invitation_token = ?,
|
|
9931
9930
|
invited_at = ?,
|
|
@@ -9938,8 +9937,8 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
9938
9937
|
Date.now(),
|
|
9939
9938
|
userId
|
|
9940
9939
|
).run();
|
|
9941
|
-
await
|
|
9942
|
-
|
|
9940
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9941
|
+
db,
|
|
9943
9942
|
user.userId,
|
|
9944
9943
|
"user!.invitation_resent",
|
|
9945
9944
|
"users",
|
|
@@ -9960,11 +9959,11 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
9960
9959
|
}
|
|
9961
9960
|
});
|
|
9962
9961
|
userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
9963
|
-
const
|
|
9962
|
+
const db = c.env.DB;
|
|
9964
9963
|
const user = c.get("user");
|
|
9965
9964
|
const userId = c.req.param("id");
|
|
9966
9965
|
try {
|
|
9967
|
-
const userStmt =
|
|
9966
|
+
const userStmt = db.prepare(`
|
|
9968
9967
|
SELECT id, email FROM users
|
|
9969
9968
|
WHERE id = ? AND is_active = 0 AND invitation_token IS NOT NULL
|
|
9970
9969
|
`);
|
|
@@ -9972,10 +9971,10 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
|
9972
9971
|
if (!invitedUser) {
|
|
9973
9972
|
return c.json({ error: "User not found or invitation not valid" }, 404);
|
|
9974
9973
|
}
|
|
9975
|
-
const deleteStmt =
|
|
9974
|
+
const deleteStmt = db.prepare(`DELETE FROM users WHERE id = ?`);
|
|
9976
9975
|
await deleteStmt.bind(userId).run();
|
|
9977
|
-
await
|
|
9978
|
-
|
|
9976
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
9977
|
+
db,
|
|
9979
9978
|
user.userId,
|
|
9980
9979
|
"user!.invitation_cancelled",
|
|
9981
9980
|
"users",
|
|
@@ -9994,7 +9993,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
|
9994
9993
|
}
|
|
9995
9994
|
});
|
|
9996
9995
|
userRoutes.get("/activity-logs", async (c) => {
|
|
9997
|
-
const
|
|
9996
|
+
const db = c.env.DB;
|
|
9998
9997
|
const user = c.get("user");
|
|
9999
9998
|
try {
|
|
10000
9999
|
const page = parseInt(c.req.query("page") || "1");
|
|
@@ -10032,7 +10031,7 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
10032
10031
|
params.push(toTimestamp);
|
|
10033
10032
|
}
|
|
10034
10033
|
const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
|
|
10035
|
-
const logsStmt =
|
|
10034
|
+
const logsStmt = db.prepare(`
|
|
10036
10035
|
SELECT
|
|
10037
10036
|
al.id, al.user_id, al.action, al.resource_type, al.resource_id,
|
|
10038
10037
|
al.details, al.ip_address, al.user_agent, al.created_at,
|
|
@@ -10045,7 +10044,7 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
10045
10044
|
LIMIT ? OFFSET ?
|
|
10046
10045
|
`);
|
|
10047
10046
|
const { results: logs } = await logsStmt.bind(...params, limit, offset).all();
|
|
10048
|
-
const countStmt =
|
|
10047
|
+
const countStmt = db.prepare(`
|
|
10049
10048
|
SELECT COUNT(*) as total
|
|
10050
10049
|
FROM activity_logs al
|
|
10051
10050
|
LEFT JOIN users u ON al.user_id = u.id
|
|
@@ -10057,8 +10056,8 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
10057
10056
|
...log,
|
|
10058
10057
|
details: log.details ? JSON.parse(log.details) : null
|
|
10059
10058
|
}));
|
|
10060
|
-
await
|
|
10061
|
-
|
|
10059
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
10060
|
+
db,
|
|
10062
10061
|
user.userId,
|
|
10063
10062
|
"activity.logs_viewed",
|
|
10064
10063
|
void 0,
|
|
@@ -10100,7 +10099,7 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
10100
10099
|
}
|
|
10101
10100
|
});
|
|
10102
10101
|
userRoutes.get("/activity-logs/export", async (c) => {
|
|
10103
|
-
const
|
|
10102
|
+
const db = c.env.DB;
|
|
10104
10103
|
const user = c.get("user");
|
|
10105
10104
|
try {
|
|
10106
10105
|
const filters = {
|
|
@@ -10135,7 +10134,7 @@ userRoutes.get("/activity-logs/export", async (c) => {
|
|
|
10135
10134
|
params.push(toTimestamp);
|
|
10136
10135
|
}
|
|
10137
10136
|
const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
|
|
10138
|
-
const logsStmt =
|
|
10137
|
+
const logsStmt = db.prepare(`
|
|
10139
10138
|
SELECT
|
|
10140
10139
|
al.id, al.user_id, al.action, al.resource_type, al.resource_id,
|
|
10141
10140
|
al.details, al.ip_address, al.user_agent, al.created_at,
|
|
@@ -10164,8 +10163,8 @@ userRoutes.get("/activity-logs/export", async (c) => {
|
|
|
10164
10163
|
csvRows.push(row.join(","));
|
|
10165
10164
|
}
|
|
10166
10165
|
const csvContent = csvRows.join("\n");
|
|
10167
|
-
await
|
|
10168
|
-
|
|
10166
|
+
await chunk5UUYHAZT_cjs.logActivity(
|
|
10167
|
+
db,
|
|
10169
10168
|
user.userId,
|
|
10170
10169
|
"activity.logs_exported",
|
|
10171
10170
|
void 0,
|
|
@@ -11503,7 +11502,7 @@ var fileValidationSchema2 = zod.z.object({
|
|
|
11503
11502
|
// 50MB max
|
|
11504
11503
|
});
|
|
11505
11504
|
var adminMediaRoutes = new hono.Hono();
|
|
11506
|
-
adminMediaRoutes.use("*",
|
|
11505
|
+
adminMediaRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
11507
11506
|
adminMediaRoutes.get("/", async (c) => {
|
|
11508
11507
|
try {
|
|
11509
11508
|
const user = c.get("user");
|
|
@@ -11515,7 +11514,7 @@ adminMediaRoutes.get("/", async (c) => {
|
|
|
11515
11514
|
const ____cacheBust = searchParams.get("t");
|
|
11516
11515
|
const limit = 24;
|
|
11517
11516
|
const offset = (page - 1) * limit;
|
|
11518
|
-
const
|
|
11517
|
+
const db = c.env.DB;
|
|
11519
11518
|
let query = "SELECT * FROM media";
|
|
11520
11519
|
const params = [];
|
|
11521
11520
|
const conditions = ["deleted_at IS NULL"];
|
|
@@ -11543,9 +11542,9 @@ adminMediaRoutes.get("/", async (c) => {
|
|
|
11543
11542
|
query += ` WHERE ${conditions.join(" AND ")}`;
|
|
11544
11543
|
}
|
|
11545
11544
|
query += ` ORDER BY uploaded_at DESC LIMIT ${limit} OFFSET ${offset}`;
|
|
11546
|
-
const stmt =
|
|
11545
|
+
const stmt = db.prepare(query);
|
|
11547
11546
|
const { results } = await stmt.bind(...params).all();
|
|
11548
|
-
const foldersStmt =
|
|
11547
|
+
const foldersStmt = db.prepare(`
|
|
11549
11548
|
SELECT folder, COUNT(*) as count, SUM(size) as totalSize
|
|
11550
11549
|
FROM media
|
|
11551
11550
|
WHERE deleted_at IS NULL
|
|
@@ -11553,7 +11552,7 @@ adminMediaRoutes.get("/", async (c) => {
|
|
|
11553
11552
|
ORDER BY folder
|
|
11554
11553
|
`);
|
|
11555
11554
|
const { results: folders } = await foldersStmt.all();
|
|
11556
|
-
const typesStmt =
|
|
11555
|
+
const typesStmt = db.prepare(`
|
|
11557
11556
|
SELECT
|
|
11558
11557
|
CASE
|
|
11559
11558
|
WHEN mime_type LIKE 'image/%' THEN 'images'
|
|
@@ -11619,7 +11618,7 @@ adminMediaRoutes.get("/selector", async (c) => {
|
|
|
11619
11618
|
try {
|
|
11620
11619
|
const { searchParams } = new URL(c.req.url);
|
|
11621
11620
|
const search = searchParams.get("search") || "";
|
|
11622
|
-
const
|
|
11621
|
+
const db = c.env.DB;
|
|
11623
11622
|
let query = "SELECT * FROM media WHERE deleted_at IS NULL";
|
|
11624
11623
|
const params = [];
|
|
11625
11624
|
if (search.trim()) {
|
|
@@ -11628,7 +11627,7 @@ adminMediaRoutes.get("/selector", async (c) => {
|
|
|
11628
11627
|
params.push(searchTerm, searchTerm, searchTerm);
|
|
11629
11628
|
}
|
|
11630
11629
|
query += " ORDER BY uploaded_at DESC LIMIT 24";
|
|
11631
|
-
const stmt =
|
|
11630
|
+
const stmt = db.prepare(query);
|
|
11632
11631
|
const { results } = await stmt.bind(...params).all();
|
|
11633
11632
|
const mediaFiles = results.map((row) => ({
|
|
11634
11633
|
id: row.id,
|
|
@@ -11735,7 +11734,7 @@ adminMediaRoutes.get("/search", async (c) => {
|
|
|
11735
11734
|
const search = searchParams.get("search") || "";
|
|
11736
11735
|
const folder = searchParams.get("folder") || "all";
|
|
11737
11736
|
const type = searchParams.get("type") || "all";
|
|
11738
|
-
const
|
|
11737
|
+
const db = c.env.DB;
|
|
11739
11738
|
let query = "SELECT * FROM media";
|
|
11740
11739
|
const params = [];
|
|
11741
11740
|
const conditions = [];
|
|
@@ -11768,7 +11767,7 @@ adminMediaRoutes.get("/search", async (c) => {
|
|
|
11768
11767
|
query += ` WHERE ${conditions.join(" AND ")}`;
|
|
11769
11768
|
}
|
|
11770
11769
|
query += ` ORDER BY uploaded_at DESC LIMIT 24`;
|
|
11771
|
-
const stmt =
|
|
11770
|
+
const stmt = db.prepare(query);
|
|
11772
11771
|
const { results } = await stmt.bind(...params).all();
|
|
11773
11772
|
const mediaFiles = results.map((row) => ({
|
|
11774
11773
|
...row,
|
|
@@ -11791,8 +11790,8 @@ adminMediaRoutes.get("/search", async (c) => {
|
|
|
11791
11790
|
adminMediaRoutes.get("/:id/details", async (c) => {
|
|
11792
11791
|
try {
|
|
11793
11792
|
const id = c.req.param("id");
|
|
11794
|
-
const
|
|
11795
|
-
const stmt =
|
|
11793
|
+
const db = c.env.DB;
|
|
11794
|
+
const stmt = db.prepare("SELECT * FROM media WHERE id = ?");
|
|
11796
11795
|
const result = await stmt.bind(id).first();
|
|
11797
11796
|
if (!result) {
|
|
11798
11797
|
return c.html('<div class="text-red-500">File not found</div>');
|
|
@@ -11829,7 +11828,13 @@ adminMediaRoutes.post("/upload", async (c) => {
|
|
|
11829
11828
|
try {
|
|
11830
11829
|
const user = c.get("user");
|
|
11831
11830
|
const formData = await c.req.formData();
|
|
11832
|
-
const
|
|
11831
|
+
const fileEntries = formData.getAll("files");
|
|
11832
|
+
const files = [];
|
|
11833
|
+
for (const entry of fileEntries) {
|
|
11834
|
+
if (entry instanceof File) {
|
|
11835
|
+
files.push(entry);
|
|
11836
|
+
}
|
|
11837
|
+
}
|
|
11833
11838
|
if (!files || files.length === 0) {
|
|
11834
11839
|
return c.html(html.html`
|
|
11835
11840
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -11865,7 +11870,7 @@ adminMediaRoutes.post("/upload", async (c) => {
|
|
|
11865
11870
|
});
|
|
11866
11871
|
continue;
|
|
11867
11872
|
}
|
|
11868
|
-
const fileId =
|
|
11873
|
+
const fileId = crypto.randomUUID();
|
|
11869
11874
|
const fileExtension = file.name.split(".").pop() || "";
|
|
11870
11875
|
const filename = `${fileId}.${fileExtension}`;
|
|
11871
11876
|
const folder = formData.get("folder") || "uploads";
|
|
@@ -11938,10 +11943,11 @@ adminMediaRoutes.post("/upload", async (c) => {
|
|
|
11938
11943
|
});
|
|
11939
11944
|
}
|
|
11940
11945
|
}
|
|
11941
|
-
let
|
|
11946
|
+
let mediaGridHTML = "";
|
|
11942
11947
|
if (uploadResults.length > 0) {
|
|
11943
11948
|
try {
|
|
11944
|
-
const
|
|
11949
|
+
const folderEntry = formData.get("folder");
|
|
11950
|
+
const folder = typeof folderEntry === "string" ? folderEntry : "uploads";
|
|
11945
11951
|
const query = "SELECT * FROM media WHERE deleted_at IS NULL ORDER BY uploaded_at DESC LIMIT 24";
|
|
11946
11952
|
const stmt = c.env.DB.prepare(query);
|
|
11947
11953
|
const { results } = await stmt.all();
|
|
@@ -12082,15 +12088,15 @@ adminMediaRoutes.put("/:id", async (c) => {
|
|
|
12082
12088
|
`);
|
|
12083
12089
|
}
|
|
12084
12090
|
});
|
|
12085
|
-
adminMediaRoutes.delete("/cleanup",
|
|
12091
|
+
adminMediaRoutes.delete("/cleanup", chunk5UUYHAZT_cjs.requireRole("admin"), async (c) => {
|
|
12086
12092
|
try {
|
|
12087
|
-
const
|
|
12088
|
-
const allMediaStmt =
|
|
12093
|
+
const db = c.env.DB;
|
|
12094
|
+
const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
|
|
12089
12095
|
const { results: allMedia } = await allMediaStmt.all();
|
|
12090
|
-
const contentStmt =
|
|
12096
|
+
const contentStmt = db.prepare("SELECT data FROM content");
|
|
12091
12097
|
const { results: contentRecords } = await contentStmt.all();
|
|
12092
12098
|
const referencedUrls = /* @__PURE__ */ new Set();
|
|
12093
|
-
for (const record of contentRecords) {
|
|
12099
|
+
for (const record of contentRecords || []) {
|
|
12094
12100
|
if (record.data) {
|
|
12095
12101
|
const dataStr = typeof record.data === "string" ? record.data : JSON.stringify(record.data);
|
|
12096
12102
|
const urlMatches = dataStr.matchAll(/\/files\/([^\s"',]+)/g);
|
|
@@ -12099,7 +12105,8 @@ adminMediaRoutes.delete("/cleanup", chunkUEYMFNBN_cjs.requireRole("admin"), asyn
|
|
|
12099
12105
|
}
|
|
12100
12106
|
}
|
|
12101
12107
|
}
|
|
12102
|
-
const
|
|
12108
|
+
const mediaRows = allMedia || [];
|
|
12109
|
+
const unusedFiles = mediaRows.filter((file) => !referencedUrls.has(file.r2_key));
|
|
12103
12110
|
if (unusedFiles.length === 0) {
|
|
12104
12111
|
return c.html(html.html`
|
|
12105
12112
|
<div class="bg-blue-100 border border-blue-400 text-blue-700 px-4 py-3 rounded">
|
|
@@ -12117,7 +12124,7 @@ adminMediaRoutes.delete("/cleanup", chunkUEYMFNBN_cjs.requireRole("admin"), asyn
|
|
|
12117
12124
|
for (const file of unusedFiles) {
|
|
12118
12125
|
try {
|
|
12119
12126
|
await c.env.MEDIA_BUCKET.delete(file.r2_key);
|
|
12120
|
-
const deleteStmt =
|
|
12127
|
+
const deleteStmt = db.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
|
|
12121
12128
|
await deleteStmt.bind(Math.floor(Date.now() / 1e3), file.id).run();
|
|
12122
12129
|
deletedCount++;
|
|
12123
12130
|
} catch (error) {
|
|
@@ -13686,7 +13693,7 @@ function formatTimestamp(timestamp) {
|
|
|
13686
13693
|
|
|
13687
13694
|
// src/routes/admin-plugins.ts
|
|
13688
13695
|
var adminPluginRoutes = new hono.Hono();
|
|
13689
|
-
adminPluginRoutes.use("*",
|
|
13696
|
+
adminPluginRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
13690
13697
|
var AVAILABLE_PLUGINS = [
|
|
13691
13698
|
{
|
|
13692
13699
|
id: "third-party-faq",
|
|
@@ -13783,11 +13790,11 @@ var AVAILABLE_PLUGINS = [
|
|
|
13783
13790
|
adminPluginRoutes.get("/", async (c) => {
|
|
13784
13791
|
try {
|
|
13785
13792
|
const user = c.get("user");
|
|
13786
|
-
const
|
|
13793
|
+
const db = c.env.DB;
|
|
13787
13794
|
if (user?.role !== "admin") {
|
|
13788
13795
|
return c.text("Access denied", 403);
|
|
13789
13796
|
}
|
|
13790
|
-
const pluginService = new
|
|
13797
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
13791
13798
|
let installedPlugins = [];
|
|
13792
13799
|
let stats = { total: 0, active: 0, inactive: 0, errors: 0, uninstalled: 0 };
|
|
13793
13800
|
try {
|
|
@@ -13854,12 +13861,12 @@ adminPluginRoutes.get("/", async (c) => {
|
|
|
13854
13861
|
adminPluginRoutes.get("/:id", async (c) => {
|
|
13855
13862
|
try {
|
|
13856
13863
|
const user = c.get("user");
|
|
13857
|
-
const
|
|
13864
|
+
const db = c.env.DB;
|
|
13858
13865
|
const pluginId = c.req.param("id");
|
|
13859
13866
|
if (user?.role !== "admin") {
|
|
13860
13867
|
return c.redirect("/admin/plugins");
|
|
13861
13868
|
}
|
|
13862
|
-
const pluginService = new
|
|
13869
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
13863
13870
|
const plugin = await pluginService.getPlugin(pluginId);
|
|
13864
13871
|
if (!plugin) {
|
|
13865
13872
|
return c.text("Plugin not found", 404);
|
|
@@ -13908,12 +13915,12 @@ adminPluginRoutes.get("/:id", async (c) => {
|
|
|
13908
13915
|
adminPluginRoutes.post("/:id/activate", async (c) => {
|
|
13909
13916
|
try {
|
|
13910
13917
|
const user = c.get("user");
|
|
13911
|
-
const
|
|
13918
|
+
const db = c.env.DB;
|
|
13912
13919
|
const pluginId = c.req.param("id");
|
|
13913
13920
|
if (user?.role !== "admin") {
|
|
13914
13921
|
return c.json({ error: "Access denied" }, 403);
|
|
13915
13922
|
}
|
|
13916
|
-
const pluginService = new
|
|
13923
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
13917
13924
|
await pluginService.activatePlugin(pluginId);
|
|
13918
13925
|
return c.json({ success: true });
|
|
13919
13926
|
} catch (error) {
|
|
@@ -13925,12 +13932,12 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
|
|
|
13925
13932
|
adminPluginRoutes.post("/:id/deactivate", async (c) => {
|
|
13926
13933
|
try {
|
|
13927
13934
|
const user = c.get("user");
|
|
13928
|
-
const
|
|
13935
|
+
const db = c.env.DB;
|
|
13929
13936
|
const pluginId = c.req.param("id");
|
|
13930
13937
|
if (user?.role !== "admin") {
|
|
13931
13938
|
return c.json({ error: "Access denied" }, 403);
|
|
13932
13939
|
}
|
|
13933
|
-
const pluginService = new
|
|
13940
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
13934
13941
|
await pluginService.deactivatePlugin(pluginId);
|
|
13935
13942
|
return c.json({ success: true });
|
|
13936
13943
|
} catch (error) {
|
|
@@ -13942,12 +13949,12 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
|
|
|
13942
13949
|
adminPluginRoutes.post("/install", async (c) => {
|
|
13943
13950
|
try {
|
|
13944
13951
|
const user = c.get("user");
|
|
13945
|
-
const
|
|
13952
|
+
const db = c.env.DB;
|
|
13946
13953
|
if (user?.role !== "admin") {
|
|
13947
13954
|
return c.json({ error: "Access denied" }, 403);
|
|
13948
13955
|
}
|
|
13949
13956
|
const body = await c.req.json();
|
|
13950
|
-
const pluginService = new
|
|
13957
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
13951
13958
|
if (body.name === "faq-plugin") {
|
|
13952
13959
|
const faqPlugin = await pluginService.installPlugin({
|
|
13953
13960
|
id: "third-party-faq",
|
|
@@ -14158,12 +14165,12 @@ adminPluginRoutes.post("/install", async (c) => {
|
|
|
14158
14165
|
adminPluginRoutes.post("/:id/uninstall", async (c) => {
|
|
14159
14166
|
try {
|
|
14160
14167
|
const user = c.get("user");
|
|
14161
|
-
const
|
|
14168
|
+
const db = c.env.DB;
|
|
14162
14169
|
const pluginId = c.req.param("id");
|
|
14163
14170
|
if (user?.role !== "admin") {
|
|
14164
14171
|
return c.json({ error: "Access denied" }, 403);
|
|
14165
14172
|
}
|
|
14166
|
-
const pluginService = new
|
|
14173
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
14167
14174
|
await pluginService.uninstallPlugin(pluginId);
|
|
14168
14175
|
return c.json({ success: true });
|
|
14169
14176
|
} catch (error) {
|
|
@@ -14175,13 +14182,13 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
|
|
|
14175
14182
|
adminPluginRoutes.post("/:id/settings", async (c) => {
|
|
14176
14183
|
try {
|
|
14177
14184
|
const user = c.get("user");
|
|
14178
|
-
const
|
|
14185
|
+
const db = c.env.DB;
|
|
14179
14186
|
const pluginId = c.req.param("id");
|
|
14180
14187
|
if (user?.role !== "admin") {
|
|
14181
14188
|
return c.json({ error: "Access denied" }, 403);
|
|
14182
14189
|
}
|
|
14183
14190
|
const settings = await c.req.json();
|
|
14184
|
-
const pluginService = new
|
|
14191
|
+
const pluginService = new chunkNAYD76QF_cjs.PluginService(db);
|
|
14185
14192
|
await pluginService.updatePluginSettings(pluginId, settings);
|
|
14186
14193
|
return c.json({ success: true });
|
|
14187
14194
|
} catch (error) {
|
|
@@ -14977,11 +14984,11 @@ function renderLogConfigPage(data) {
|
|
|
14977
14984
|
|
|
14978
14985
|
// src/routes/admin-logs.ts
|
|
14979
14986
|
var adminLogsRoutes = new hono.Hono();
|
|
14980
|
-
adminLogsRoutes.use("*",
|
|
14987
|
+
adminLogsRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
14981
14988
|
adminLogsRoutes.get("/", async (c) => {
|
|
14982
14989
|
try {
|
|
14983
14990
|
const user = c.get("user");
|
|
14984
|
-
const logger =
|
|
14991
|
+
const logger = chunkES3BRZQJ_cjs.getLogger(c.env.DB);
|
|
14985
14992
|
const query = c.req.query();
|
|
14986
14993
|
const page = parseInt(query.page || "1");
|
|
14987
14994
|
const limit = parseInt(query.limit || "50");
|
|
@@ -15061,7 +15068,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
15061
15068
|
try {
|
|
15062
15069
|
const id = c.req.param("id");
|
|
15063
15070
|
const user = c.get("user");
|
|
15064
|
-
const logger =
|
|
15071
|
+
const logger = chunkES3BRZQJ_cjs.getLogger(c.env.DB);
|
|
15065
15072
|
const { logs } = await logger.getLogs({
|
|
15066
15073
|
limit: 1,
|
|
15067
15074
|
offset: 0,
|
|
@@ -15098,7 +15105,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
15098
15105
|
adminLogsRoutes.get("/config", async (c) => {
|
|
15099
15106
|
try {
|
|
15100
15107
|
const user = c.get("user");
|
|
15101
|
-
const logger =
|
|
15108
|
+
const logger = chunkES3BRZQJ_cjs.getLogger(c.env.DB);
|
|
15102
15109
|
const configs = await logger.getAllConfigs();
|
|
15103
15110
|
const pageData = {
|
|
15104
15111
|
configs,
|
|
@@ -15122,7 +15129,7 @@ adminLogsRoutes.post("/config/:category", async (c) => {
|
|
|
15122
15129
|
const level = formData.get("level");
|
|
15123
15130
|
const retention = parseInt(formData.get("retention"));
|
|
15124
15131
|
const maxSize = parseInt(formData.get("max_size"));
|
|
15125
|
-
const logger =
|
|
15132
|
+
const logger = chunkES3BRZQJ_cjs.getLogger(c.env.DB);
|
|
15126
15133
|
await logger.updateConfig(category, {
|
|
15127
15134
|
enabled,
|
|
15128
15135
|
level,
|
|
@@ -15151,7 +15158,7 @@ adminLogsRoutes.get("/export", async (c) => {
|
|
|
15151
15158
|
const category = query.category;
|
|
15152
15159
|
const startDate = query.start_date;
|
|
15153
15160
|
const endDate = query.end_date;
|
|
15154
|
-
const logger =
|
|
15161
|
+
const logger = chunkES3BRZQJ_cjs.getLogger(c.env.DB);
|
|
15155
15162
|
const filter = {
|
|
15156
15163
|
limit: 1e4,
|
|
15157
15164
|
// Export up to 10k logs
|
|
@@ -15232,7 +15239,7 @@ adminLogsRoutes.post("/cleanup", async (c) => {
|
|
|
15232
15239
|
error: "Unauthorized. Admin access required."
|
|
15233
15240
|
}, 403);
|
|
15234
15241
|
}
|
|
15235
|
-
const logger =
|
|
15242
|
+
const logger = chunkES3BRZQJ_cjs.getLogger(c.env.DB);
|
|
15236
15243
|
await logger.cleanupByRetention();
|
|
15237
15244
|
return c.html(html.html`
|
|
15238
15245
|
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded">
|
|
@@ -15254,7 +15261,7 @@ adminLogsRoutes.post("/search", async (c) => {
|
|
|
15254
15261
|
const search = formData.get("search");
|
|
15255
15262
|
const level = formData.get("level");
|
|
15256
15263
|
const category = formData.get("category");
|
|
15257
|
-
const logger =
|
|
15264
|
+
const logger = chunkES3BRZQJ_cjs.getLogger(c.env.DB);
|
|
15258
15265
|
const filter = {
|
|
15259
15266
|
limit: 20,
|
|
15260
15267
|
offset: 0,
|
|
@@ -15642,8 +15649,8 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
15642
15649
|
const currentPage = parseInt(page, 10) || 1;
|
|
15643
15650
|
const limit = 20;
|
|
15644
15651
|
const offset = (currentPage - 1) * limit;
|
|
15645
|
-
const
|
|
15646
|
-
if (!
|
|
15652
|
+
const db = c.env?.DB;
|
|
15653
|
+
if (!db) {
|
|
15647
15654
|
return c.html(chunkYU6QFFI4_cjs.renderTestimonialsList({
|
|
15648
15655
|
testimonials: [],
|
|
15649
15656
|
totalCount: 0,
|
|
@@ -15674,7 +15681,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
15674
15681
|
params.push(searchTerm, searchTerm, searchTerm);
|
|
15675
15682
|
}
|
|
15676
15683
|
const countQuery = `SELECT COUNT(*) as count FROM testimonials ${whereClause}`;
|
|
15677
|
-
const { results: countResults } = await
|
|
15684
|
+
const { results: countResults } = await db.prepare(countQuery).bind(...params).all();
|
|
15678
15685
|
const totalCount = countResults?.[0]?.count || 0;
|
|
15679
15686
|
const dataQuery = `
|
|
15680
15687
|
SELECT * FROM testimonials
|
|
@@ -15682,7 +15689,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
15682
15689
|
ORDER BY sortOrder ASC, created_at DESC
|
|
15683
15690
|
LIMIT ? OFFSET ?
|
|
15684
15691
|
`;
|
|
15685
|
-
const { results: testimonials } = await
|
|
15692
|
+
const { results: testimonials } = await db.prepare(dataQuery).bind(...params, limit, offset).all();
|
|
15686
15693
|
const totalPages = Math.ceil(totalCount / limit);
|
|
15687
15694
|
return c.html(chunkYU6QFFI4_cjs.renderTestimonialsList({
|
|
15688
15695
|
testimonials: testimonials || [],
|
|
@@ -15730,8 +15737,8 @@ adminTestimonialsRoutes.post("/", async (c) => {
|
|
|
15730
15737
|
const data = Object.fromEntries(formData.entries());
|
|
15731
15738
|
const validatedData = testimonialSchema.parse(data);
|
|
15732
15739
|
const user = c.get("user");
|
|
15733
|
-
const
|
|
15734
|
-
if (!
|
|
15740
|
+
const db = c.env?.DB;
|
|
15741
|
+
if (!db) {
|
|
15735
15742
|
return c.html(renderTestimonialsForm({
|
|
15736
15743
|
isEdit: false,
|
|
15737
15744
|
user: user ? {
|
|
@@ -15743,7 +15750,7 @@ adminTestimonialsRoutes.post("/", async (c) => {
|
|
|
15743
15750
|
messageType: "error"
|
|
15744
15751
|
}));
|
|
15745
15752
|
}
|
|
15746
|
-
const { results } = await
|
|
15753
|
+
const { results } = await db.prepare(`
|
|
15747
15754
|
INSERT INTO testimonials (author_name, author_title, author_company, testimonial_text, rating, isPublished, sortOrder)
|
|
15748
15755
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
15749
15756
|
RETURNING *
|
|
@@ -15775,7 +15782,7 @@ adminTestimonialsRoutes.post("/", async (c) => {
|
|
|
15775
15782
|
const user = c.get("user");
|
|
15776
15783
|
if (error instanceof zod.z.ZodError) {
|
|
15777
15784
|
const errors = {};
|
|
15778
|
-
error.
|
|
15785
|
+
error.issues.forEach((err) => {
|
|
15779
15786
|
const field = err.path[0];
|
|
15780
15787
|
if (!errors[field]) errors[field] = [];
|
|
15781
15788
|
errors[field].push(err.message);
|
|
@@ -15808,8 +15815,8 @@ adminTestimonialsRoutes.get("/:id", async (c) => {
|
|
|
15808
15815
|
try {
|
|
15809
15816
|
const id = parseInt(c.req.param("id"));
|
|
15810
15817
|
const user = c.get("user");
|
|
15811
|
-
const
|
|
15812
|
-
if (!
|
|
15818
|
+
const db = c.env?.DB;
|
|
15819
|
+
if (!db) {
|
|
15813
15820
|
return c.html(renderTestimonialsForm({
|
|
15814
15821
|
isEdit: true,
|
|
15815
15822
|
user: user ? {
|
|
@@ -15821,7 +15828,7 @@ adminTestimonialsRoutes.get("/:id", async (c) => {
|
|
|
15821
15828
|
messageType: "error"
|
|
15822
15829
|
}));
|
|
15823
15830
|
}
|
|
15824
|
-
const { results } = await
|
|
15831
|
+
const { results } = await db.prepare("SELECT * FROM testimonials WHERE id = ?").bind(id).all();
|
|
15825
15832
|
if (!results || results.length === 0) {
|
|
15826
15833
|
return c.redirect("/admin/testimonials?message=Testimonial not found&type=error");
|
|
15827
15834
|
}
|
|
@@ -15866,8 +15873,8 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
|
|
|
15866
15873
|
const data = Object.fromEntries(formData.entries());
|
|
15867
15874
|
const validatedData = testimonialSchema.parse(data);
|
|
15868
15875
|
const user = c.get("user");
|
|
15869
|
-
const
|
|
15870
|
-
if (!
|
|
15876
|
+
const db = c.env?.DB;
|
|
15877
|
+
if (!db) {
|
|
15871
15878
|
return c.html(renderTestimonialsForm({
|
|
15872
15879
|
isEdit: true,
|
|
15873
15880
|
user: user ? {
|
|
@@ -15879,7 +15886,7 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
|
|
|
15879
15886
|
messageType: "error"
|
|
15880
15887
|
}));
|
|
15881
15888
|
}
|
|
15882
|
-
const { results } = await
|
|
15889
|
+
const { results } = await db.prepare(`
|
|
15883
15890
|
UPDATE testimonials
|
|
15884
15891
|
SET author_name = ?, author_title = ?, author_company = ?, testimonial_text = ?, rating = ?, isPublished = ?, sortOrder = ?
|
|
15885
15892
|
WHERE id = ?
|
|
@@ -15924,7 +15931,7 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
|
|
|
15924
15931
|
const id = parseInt(c.req.param("id"));
|
|
15925
15932
|
if (error instanceof zod.z.ZodError) {
|
|
15926
15933
|
const errors = {};
|
|
15927
|
-
error.
|
|
15934
|
+
error.issues.forEach((err) => {
|
|
15928
15935
|
const field = err.path[0];
|
|
15929
15936
|
if (!errors[field]) errors[field] = [];
|
|
15930
15937
|
errors[field].push(err.message);
|
|
@@ -15976,11 +15983,11 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
|
|
|
15976
15983
|
adminTestimonialsRoutes.delete("/:id", async (c) => {
|
|
15977
15984
|
try {
|
|
15978
15985
|
const id = parseInt(c.req.param("id"));
|
|
15979
|
-
const
|
|
15980
|
-
if (!
|
|
15986
|
+
const db = c.env?.DB;
|
|
15987
|
+
if (!db) {
|
|
15981
15988
|
return c.json({ error: "Database not available" }, 500);
|
|
15982
15989
|
}
|
|
15983
|
-
const { changes } = await
|
|
15990
|
+
const { changes } = await db.prepare("DELETE FROM testimonials WHERE id = ?").bind(id).run();
|
|
15984
15991
|
if (changes === 0) {
|
|
15985
15992
|
return c.json({ error: "Testimonial not found" }, 404);
|
|
15986
15993
|
}
|
|
@@ -16312,8 +16319,8 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
16312
16319
|
const currentPage = parseInt(page, 10) || 1;
|
|
16313
16320
|
const limit = 20;
|
|
16314
16321
|
const offset = (currentPage - 1) * limit;
|
|
16315
|
-
const
|
|
16316
|
-
if (!
|
|
16322
|
+
const db = c.env?.DB;
|
|
16323
|
+
if (!db) {
|
|
16317
16324
|
return c.html(chunkYU6QFFI4_cjs.renderCodeExamplesList({
|
|
16318
16325
|
codeExamples: [],
|
|
16319
16326
|
totalCount: 0,
|
|
@@ -16344,7 +16351,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
16344
16351
|
params.push(searchTerm, searchTerm, searchTerm, searchTerm);
|
|
16345
16352
|
}
|
|
16346
16353
|
const countQuery = `SELECT COUNT(*) as count FROM code_examples ${whereClause}`;
|
|
16347
|
-
const { results: countResults } = await
|
|
16354
|
+
const { results: countResults } = await db.prepare(countQuery).bind(...params).all();
|
|
16348
16355
|
const totalCount = countResults?.[0]?.count || 0;
|
|
16349
16356
|
const dataQuery = `
|
|
16350
16357
|
SELECT * FROM code_examples
|
|
@@ -16352,7 +16359,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
16352
16359
|
ORDER BY sortOrder ASC, created_at DESC
|
|
16353
16360
|
LIMIT ? OFFSET ?
|
|
16354
16361
|
`;
|
|
16355
|
-
const { results: codeExamples } = await
|
|
16362
|
+
const { results: codeExamples } = await db.prepare(dataQuery).bind(...params, limit, offset).all();
|
|
16356
16363
|
const totalPages = Math.ceil(totalCount / limit);
|
|
16357
16364
|
return c.html(chunkYU6QFFI4_cjs.renderCodeExamplesList({
|
|
16358
16365
|
codeExamples: codeExamples || [],
|
|
@@ -16400,8 +16407,8 @@ adminCodeExamplesRoutes.post("/", async (c) => {
|
|
|
16400
16407
|
const data = Object.fromEntries(formData.entries());
|
|
16401
16408
|
const validatedData = codeExampleSchema.parse(data);
|
|
16402
16409
|
const user = c.get("user");
|
|
16403
|
-
const
|
|
16404
|
-
if (!
|
|
16410
|
+
const db = c.env?.DB;
|
|
16411
|
+
if (!db) {
|
|
16405
16412
|
return c.html(renderCodeExamplesForm({
|
|
16406
16413
|
isEdit: false,
|
|
16407
16414
|
user: user ? {
|
|
@@ -16413,7 +16420,7 @@ adminCodeExamplesRoutes.post("/", async (c) => {
|
|
|
16413
16420
|
messageType: "error"
|
|
16414
16421
|
}));
|
|
16415
16422
|
}
|
|
16416
|
-
const { results } = await
|
|
16423
|
+
const { results } = await db.prepare(`
|
|
16417
16424
|
INSERT INTO code_examples (title, description, code, language, category, tags, isPublished, sortOrder)
|
|
16418
16425
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
16419
16426
|
RETURNING *
|
|
@@ -16446,7 +16453,7 @@ adminCodeExamplesRoutes.post("/", async (c) => {
|
|
|
16446
16453
|
const user = c.get("user");
|
|
16447
16454
|
if (error instanceof zod.z.ZodError) {
|
|
16448
16455
|
const errors = {};
|
|
16449
|
-
error.
|
|
16456
|
+
error.issues.forEach((err) => {
|
|
16450
16457
|
const field = err.path[0];
|
|
16451
16458
|
if (!errors[field]) errors[field] = [];
|
|
16452
16459
|
errors[field].push(err.message);
|
|
@@ -16479,8 +16486,8 @@ adminCodeExamplesRoutes.get("/:id", async (c) => {
|
|
|
16479
16486
|
try {
|
|
16480
16487
|
const id = parseInt(c.req.param("id"));
|
|
16481
16488
|
const user = c.get("user");
|
|
16482
|
-
const
|
|
16483
|
-
if (!
|
|
16489
|
+
const db = c.env?.DB;
|
|
16490
|
+
if (!db) {
|
|
16484
16491
|
return c.html(renderCodeExamplesForm({
|
|
16485
16492
|
isEdit: true,
|
|
16486
16493
|
user: user ? {
|
|
@@ -16492,7 +16499,7 @@ adminCodeExamplesRoutes.get("/:id", async (c) => {
|
|
|
16492
16499
|
messageType: "error"
|
|
16493
16500
|
}));
|
|
16494
16501
|
}
|
|
16495
|
-
const { results } = await
|
|
16502
|
+
const { results } = await db.prepare("SELECT * FROM code_examples WHERE id = ?").bind(id).all();
|
|
16496
16503
|
if (!results || results.length === 0) {
|
|
16497
16504
|
return c.redirect("/admin/code-examples?message=Code example not found&type=error");
|
|
16498
16505
|
}
|
|
@@ -16538,8 +16545,8 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
|
|
|
16538
16545
|
const data = Object.fromEntries(formData.entries());
|
|
16539
16546
|
const validatedData = codeExampleSchema.parse(data);
|
|
16540
16547
|
const user = c.get("user");
|
|
16541
|
-
const
|
|
16542
|
-
if (!
|
|
16548
|
+
const db = c.env?.DB;
|
|
16549
|
+
if (!db) {
|
|
16543
16550
|
return c.html(renderCodeExamplesForm({
|
|
16544
16551
|
isEdit: true,
|
|
16545
16552
|
user: user ? {
|
|
@@ -16551,7 +16558,7 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
|
|
|
16551
16558
|
messageType: "error"
|
|
16552
16559
|
}));
|
|
16553
16560
|
}
|
|
16554
|
-
const { results } = await
|
|
16561
|
+
const { results } = await db.prepare(`
|
|
16555
16562
|
UPDATE code_examples
|
|
16556
16563
|
SET title = ?, description = ?, code = ?, language = ?, category = ?, tags = ?, isPublished = ?, sortOrder = ?
|
|
16557
16564
|
WHERE id = ?
|
|
@@ -16598,7 +16605,7 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
|
|
|
16598
16605
|
const id = parseInt(c.req.param("id"));
|
|
16599
16606
|
if (error instanceof zod.z.ZodError) {
|
|
16600
16607
|
const errors = {};
|
|
16601
|
-
error.
|
|
16608
|
+
error.issues.forEach((err) => {
|
|
16602
16609
|
const field = err.path[0];
|
|
16603
16610
|
if (!errors[field]) errors[field] = [];
|
|
16604
16611
|
errors[field].push(err.message);
|
|
@@ -16652,11 +16659,11 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
|
|
|
16652
16659
|
adminCodeExamplesRoutes.delete("/:id", async (c) => {
|
|
16653
16660
|
try {
|
|
16654
16661
|
const id = parseInt(c.req.param("id"));
|
|
16655
|
-
const
|
|
16656
|
-
if (!
|
|
16662
|
+
const db = c.env?.DB;
|
|
16663
|
+
if (!db) {
|
|
16657
16664
|
return c.json({ error: "Database not available" }, 500);
|
|
16658
16665
|
}
|
|
16659
|
-
const { changes } = await
|
|
16666
|
+
const { changes } = await db.prepare("DELETE FROM code_examples WHERE id = ?").bind(id).run();
|
|
16660
16667
|
if (changes === 0) {
|
|
16661
16668
|
return c.json({ error: "Code example not found" }, 404);
|
|
16662
16669
|
}
|
|
@@ -17305,9 +17312,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
|
|
|
17305
17312
|
}
|
|
17306
17313
|
|
|
17307
17314
|
// src/routes/admin-dashboard.ts
|
|
17308
|
-
var VERSION =
|
|
17315
|
+
var VERSION = chunk44LBCF3B_cjs.getCoreVersion();
|
|
17309
17316
|
var router = new hono.Hono();
|
|
17310
|
-
router.use("*",
|
|
17317
|
+
router.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
17311
17318
|
router.get("/", async (c) => {
|
|
17312
17319
|
const user = c.get("user");
|
|
17313
17320
|
try {
|
|
@@ -17335,10 +17342,10 @@ router.get("/", async (c) => {
|
|
|
17335
17342
|
});
|
|
17336
17343
|
router.get("/stats", async (c) => {
|
|
17337
17344
|
try {
|
|
17338
|
-
const
|
|
17345
|
+
const db = c.env.DB;
|
|
17339
17346
|
let collectionsCount = 0;
|
|
17340
17347
|
try {
|
|
17341
|
-
const collectionsStmt =
|
|
17348
|
+
const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
|
|
17342
17349
|
const collectionsResult = await collectionsStmt.first();
|
|
17343
17350
|
collectionsCount = collectionsResult?.count || 0;
|
|
17344
17351
|
} catch (error) {
|
|
@@ -17346,7 +17353,7 @@ router.get("/stats", async (c) => {
|
|
|
17346
17353
|
}
|
|
17347
17354
|
let contentCount = 0;
|
|
17348
17355
|
try {
|
|
17349
|
-
const contentStmt =
|
|
17356
|
+
const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content");
|
|
17350
17357
|
const contentResult = await contentStmt.first();
|
|
17351
17358
|
contentCount = contentResult?.count || 0;
|
|
17352
17359
|
} catch (error) {
|
|
@@ -17355,7 +17362,7 @@ router.get("/stats", async (c) => {
|
|
|
17355
17362
|
let mediaCount = 0;
|
|
17356
17363
|
let mediaSize = 0;
|
|
17357
17364
|
try {
|
|
17358
|
-
const mediaStmt =
|
|
17365
|
+
const mediaStmt = db.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
|
|
17359
17366
|
const mediaResult = await mediaStmt.first();
|
|
17360
17367
|
mediaCount = mediaResult?.count || 0;
|
|
17361
17368
|
mediaSize = mediaResult?.total_size || 0;
|
|
@@ -17364,7 +17371,7 @@ router.get("/stats", async (c) => {
|
|
|
17364
17371
|
}
|
|
17365
17372
|
let usersCount = 0;
|
|
17366
17373
|
try {
|
|
17367
|
-
const usersStmt =
|
|
17374
|
+
const usersStmt = db.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
|
|
17368
17375
|
const usersResult = await usersStmt.first();
|
|
17369
17376
|
usersCount = usersResult?.count || 0;
|
|
17370
17377
|
} catch (error) {
|
|
@@ -17385,17 +17392,17 @@ router.get("/stats", async (c) => {
|
|
|
17385
17392
|
});
|
|
17386
17393
|
router.get("/storage", async (c) => {
|
|
17387
17394
|
try {
|
|
17388
|
-
const
|
|
17395
|
+
const db = c.env.DB;
|
|
17389
17396
|
let databaseSize = 0;
|
|
17390
17397
|
try {
|
|
17391
|
-
const result = await
|
|
17398
|
+
const result = await db.prepare("SELECT 1").run();
|
|
17392
17399
|
databaseSize = result?.meta?.size_after || 0;
|
|
17393
17400
|
} catch (error) {
|
|
17394
17401
|
console.error("Error fetching database size:", error);
|
|
17395
17402
|
}
|
|
17396
17403
|
let mediaSize = 0;
|
|
17397
17404
|
try {
|
|
17398
|
-
const mediaStmt =
|
|
17405
|
+
const mediaStmt = db.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
|
|
17399
17406
|
const mediaResult = await mediaStmt.first();
|
|
17400
17407
|
mediaSize = mediaResult?.total_size || 0;
|
|
17401
17408
|
} catch (error) {
|
|
@@ -17410,9 +17417,9 @@ router.get("/storage", async (c) => {
|
|
|
17410
17417
|
});
|
|
17411
17418
|
router.get("/recent-activity", async (c) => {
|
|
17412
17419
|
try {
|
|
17413
|
-
const
|
|
17420
|
+
const db = c.env.DB;
|
|
17414
17421
|
const limit = parseInt(c.req.query("limit") || "5");
|
|
17415
|
-
const activityStmt =
|
|
17422
|
+
const activityStmt = db.prepare(`
|
|
17416
17423
|
SELECT
|
|
17417
17424
|
a.id,
|
|
17418
17425
|
a.action,
|
|
@@ -19061,17 +19068,17 @@ function renderCollectionFormPage(data) {
|
|
|
19061
19068
|
|
|
19062
19069
|
// src/routes/admin-collections.ts
|
|
19063
19070
|
var adminCollectionsRoutes = new hono.Hono();
|
|
19064
|
-
adminCollectionsRoutes.use("*",
|
|
19071
|
+
adminCollectionsRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
19065
19072
|
adminCollectionsRoutes.get("/", async (c) => {
|
|
19066
19073
|
try {
|
|
19067
19074
|
const user = c.get("user");
|
|
19068
|
-
const
|
|
19075
|
+
const db = c.env.DB;
|
|
19069
19076
|
const url = new URL(c.req.url);
|
|
19070
19077
|
const search = url.searchParams.get("search") || "";
|
|
19071
19078
|
let stmt;
|
|
19072
19079
|
let results;
|
|
19073
19080
|
if (search) {
|
|
19074
|
-
stmt =
|
|
19081
|
+
stmt = db.prepare(`
|
|
19075
19082
|
SELECT id, name, display_name, description, created_at, managed, schema
|
|
19076
19083
|
FROM collections
|
|
19077
19084
|
WHERE is_active = 1
|
|
@@ -19082,11 +19089,11 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
19082
19089
|
const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all();
|
|
19083
19090
|
results = queryResults.results;
|
|
19084
19091
|
} else {
|
|
19085
|
-
stmt =
|
|
19092
|
+
stmt = db.prepare("SELECT id, name, display_name, description, created_at, managed, schema FROM collections WHERE is_active = 1 ORDER BY created_at DESC");
|
|
19086
19093
|
const queryResults = await stmt.all();
|
|
19087
19094
|
results = queryResults.results;
|
|
19088
19095
|
}
|
|
19089
|
-
const fieldCountStmt =
|
|
19096
|
+
const fieldCountStmt = db.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
|
|
19090
19097
|
const { results: fieldCountResults } = await fieldCountStmt.all();
|
|
19091
19098
|
const fieldCounts = new Map((fieldCountResults || []).map((row) => [String(row.collection_id), Number(row.count)]));
|
|
19092
19099
|
const collections = (results || []).filter((row) => row && row.id).map((row) => {
|
|
@@ -19127,16 +19134,17 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
19127
19134
|
return c.html(renderCollectionsListPage(pageData));
|
|
19128
19135
|
} catch (error) {
|
|
19129
19136
|
console.error("Error fetching collections:", error);
|
|
19130
|
-
|
|
19137
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
19138
|
+
return c.html(html.html`<p>Error loading collections: ${errorMessage}</p>`);
|
|
19131
19139
|
}
|
|
19132
19140
|
});
|
|
19133
19141
|
adminCollectionsRoutes.get("/new", async (c) => {
|
|
19134
19142
|
const user = c.get("user");
|
|
19135
|
-
const
|
|
19143
|
+
const db = c.env.DB;
|
|
19136
19144
|
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
19137
|
-
isPluginActive2(
|
|
19138
|
-
isPluginActive2(
|
|
19139
|
-
isPluginActive2(
|
|
19145
|
+
isPluginActive2(db, "tinymce-plugin"),
|
|
19146
|
+
isPluginActive2(db, "quill-editor"),
|
|
19147
|
+
isPluginActive2(db, "easy-mdx")
|
|
19140
19148
|
]);
|
|
19141
19149
|
console.log("[Collections /new] Editor plugins status:", {
|
|
19142
19150
|
tinymce: tinymceActive,
|
|
@@ -19190,8 +19198,8 @@ adminCollectionsRoutes.post("/", async (c) => {
|
|
|
19190
19198
|
return c.redirect("/admin/collections/new");
|
|
19191
19199
|
}
|
|
19192
19200
|
}
|
|
19193
|
-
const
|
|
19194
|
-
const existingStmt =
|
|
19201
|
+
const db = c.env.DB;
|
|
19202
|
+
const existingStmt = db.prepare("SELECT id FROM collections WHERE name = ?");
|
|
19195
19203
|
const existing = await existingStmt.bind(name).first();
|
|
19196
19204
|
if (existing) {
|
|
19197
19205
|
const errorMsg = "A collection with this name already exists.";
|
|
@@ -19227,9 +19235,9 @@ adminCollectionsRoutes.post("/", async (c) => {
|
|
|
19227
19235
|
},
|
|
19228
19236
|
required: ["title"]
|
|
19229
19237
|
};
|
|
19230
|
-
const collectionId =
|
|
19238
|
+
const collectionId = crypto.randomUUID();
|
|
19231
19239
|
const now = Date.now();
|
|
19232
|
-
const insertStmt =
|
|
19240
|
+
const insertStmt = db.prepare(`
|
|
19233
19241
|
INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)
|
|
19234
19242
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
19235
19243
|
`);
|
|
@@ -19281,17 +19289,17 @@ adminCollectionsRoutes.post("/", async (c) => {
|
|
|
19281
19289
|
}
|
|
19282
19290
|
});
|
|
19283
19291
|
adminCollectionsRoutes.get("/:id", async (c) => {
|
|
19292
|
+
const db = c.env.DB;
|
|
19284
19293
|
try {
|
|
19285
19294
|
const id = c.req.param("id");
|
|
19286
19295
|
const user = c.get("user");
|
|
19287
|
-
const
|
|
19288
|
-
const stmt = db2.prepare("SELECT * FROM collections WHERE id = ?");
|
|
19296
|
+
const stmt = db.prepare("SELECT * FROM collections WHERE id = ?");
|
|
19289
19297
|
const collection = await stmt.bind(id).first();
|
|
19290
19298
|
if (!collection) {
|
|
19291
19299
|
const [tinymceActive2, quillActive2, mdxeditorActive2] = await Promise.all([
|
|
19292
|
-
isPluginActive2(
|
|
19293
|
-
isPluginActive2(
|
|
19294
|
-
isPluginActive2(
|
|
19300
|
+
isPluginActive2(db, "tinymce-plugin"),
|
|
19301
|
+
isPluginActive2(db, "quill-editor"),
|
|
19302
|
+
isPluginActive2(db, "easy-mdx")
|
|
19295
19303
|
]);
|
|
19296
19304
|
const formData2 = {
|
|
19297
19305
|
isEdit: true,
|
|
@@ -19332,7 +19340,7 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
19332
19340
|
}
|
|
19333
19341
|
}
|
|
19334
19342
|
if (fields.length === 0) {
|
|
19335
|
-
const fieldsStmt =
|
|
19343
|
+
const fieldsStmt = db.prepare(`
|
|
19336
19344
|
SELECT * FROM content_fields
|
|
19337
19345
|
WHERE collection_id = ?
|
|
19338
19346
|
ORDER BY field_order ASC
|
|
@@ -19361,9 +19369,9 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
19361
19369
|
});
|
|
19362
19370
|
}
|
|
19363
19371
|
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
19364
|
-
isPluginActive2(
|
|
19365
|
-
isPluginActive2(
|
|
19366
|
-
isPluginActive2(
|
|
19372
|
+
isPluginActive2(db, "tinymce-plugin"),
|
|
19373
|
+
isPluginActive2(db, "quill-editor"),
|
|
19374
|
+
isPluginActive2(db, "easy-mdx")
|
|
19367
19375
|
]);
|
|
19368
19376
|
console.log("[Collections /:id] Editor plugins status:", {
|
|
19369
19377
|
tinymce: tinymceActive,
|
|
@@ -19430,8 +19438,8 @@ adminCollectionsRoutes.put("/:id", async (c) => {
|
|
|
19430
19438
|
</div>
|
|
19431
19439
|
`);
|
|
19432
19440
|
}
|
|
19433
|
-
const
|
|
19434
|
-
const updateStmt =
|
|
19441
|
+
const db = c.env.DB;
|
|
19442
|
+
const updateStmt = db.prepare(`
|
|
19435
19443
|
UPDATE collections
|
|
19436
19444
|
SET display_name = ?, description = ?, updated_at = ?
|
|
19437
19445
|
WHERE id = ?
|
|
@@ -19454,8 +19462,8 @@ adminCollectionsRoutes.put("/:id", async (c) => {
|
|
|
19454
19462
|
adminCollectionsRoutes.delete("/:id", async (c) => {
|
|
19455
19463
|
try {
|
|
19456
19464
|
const id = c.req.param("id");
|
|
19457
|
-
const
|
|
19458
|
-
const contentStmt =
|
|
19465
|
+
const db = c.env.DB;
|
|
19466
|
+
const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
|
|
19459
19467
|
const contentResult = await contentStmt.bind(id).first();
|
|
19460
19468
|
if (contentResult && contentResult.count > 0) {
|
|
19461
19469
|
return c.html(html.html`
|
|
@@ -19464,9 +19472,9 @@ adminCollectionsRoutes.delete("/:id", async (c) => {
|
|
|
19464
19472
|
</div>
|
|
19465
19473
|
`);
|
|
19466
19474
|
}
|
|
19467
|
-
const deleteFieldsStmt =
|
|
19475
|
+
const deleteFieldsStmt = db.prepare("DELETE FROM content_fields WHERE collection_id = ?");
|
|
19468
19476
|
await deleteFieldsStmt.bind(id).run();
|
|
19469
|
-
const deleteStmt =
|
|
19477
|
+
const deleteStmt = db.prepare("DELETE FROM collections WHERE id = ?");
|
|
19470
19478
|
await deleteStmt.bind(id).run();
|
|
19471
19479
|
return c.html(html.html`
|
|
19472
19480
|
<script>
|
|
@@ -19498,18 +19506,18 @@ adminCollectionsRoutes.post("/:id/fields", async (c) => {
|
|
|
19498
19506
|
if (!/^[a-z0-9_]+$/.test(fieldName)) {
|
|
19499
19507
|
return c.json({ success: false, error: "Field name must contain only lowercase letters, numbers, and underscores." });
|
|
19500
19508
|
}
|
|
19501
|
-
const
|
|
19502
|
-
const existingStmt =
|
|
19509
|
+
const db = c.env.DB;
|
|
19510
|
+
const existingStmt = db.prepare("SELECT id FROM content_fields WHERE collection_id = ? AND field_name = ?");
|
|
19503
19511
|
const existing = await existingStmt.bind(collectionId, fieldName).first();
|
|
19504
19512
|
if (existing) {
|
|
19505
19513
|
return c.json({ success: false, error: "A field with this name already exists." });
|
|
19506
19514
|
}
|
|
19507
|
-
const orderStmt =
|
|
19515
|
+
const orderStmt = db.prepare("SELECT MAX(field_order) as max_order FROM content_fields WHERE collection_id = ?");
|
|
19508
19516
|
const orderResult = await orderStmt.bind(collectionId).first();
|
|
19509
19517
|
const nextOrder = (orderResult?.max_order || 0) + 1;
|
|
19510
|
-
const fieldId =
|
|
19518
|
+
const fieldId = crypto.randomUUID();
|
|
19511
19519
|
const now = Date.now();
|
|
19512
|
-
const insertStmt =
|
|
19520
|
+
const insertStmt = db.prepare(`
|
|
19513
19521
|
INSERT INTO content_fields (
|
|
19514
19522
|
id, collection_id, field_name, field_type, field_label,
|
|
19515
19523
|
field_options, field_order, is_required, is_searchable,
|
|
@@ -19558,11 +19566,11 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19558
19566
|
if (!fieldLabel) {
|
|
19559
19567
|
return c.json({ success: false, error: "Field label is required." });
|
|
19560
19568
|
}
|
|
19561
|
-
const
|
|
19569
|
+
const db = c.env.DB;
|
|
19562
19570
|
if (fieldId.startsWith("schema-")) {
|
|
19563
19571
|
const fieldName = fieldId.replace("schema-", "");
|
|
19564
19572
|
console.log("[Field Update] Updating schema field:", fieldName);
|
|
19565
|
-
const getCollectionStmt =
|
|
19573
|
+
const getCollectionStmt = db.prepare("SELECT * FROM collections WHERE id = ?");
|
|
19566
19574
|
const collection = await getCollectionStmt.bind(collectionId).first();
|
|
19567
19575
|
if (!collection) {
|
|
19568
19576
|
return c.json({ success: false, error: "Collection not found." });
|
|
@@ -19607,7 +19615,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19607
19615
|
console.log("[Field Update] Final required array:", schema.required);
|
|
19608
19616
|
console.log("[Field Update] Final field config:", schema.properties[fieldName]);
|
|
19609
19617
|
}
|
|
19610
|
-
const updateCollectionStmt =
|
|
19618
|
+
const updateCollectionStmt = db.prepare(`
|
|
19611
19619
|
UPDATE collections
|
|
19612
19620
|
SET schema = ?, updated_at = ?
|
|
19613
19621
|
WHERE id = ?
|
|
@@ -19619,7 +19627,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19619
19627
|
});
|
|
19620
19628
|
return c.json({ success: true });
|
|
19621
19629
|
}
|
|
19622
|
-
const updateStmt =
|
|
19630
|
+
const updateStmt = db.prepare(`
|
|
19623
19631
|
UPDATE content_fields
|
|
19624
19632
|
SET field_label = ?, field_type = ?, field_options = ?, is_required = ?, is_searchable = ?, updated_at = ?
|
|
19625
19633
|
WHERE id = ?
|
|
@@ -19631,7 +19639,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19631
19639
|
changes: result.meta?.changes,
|
|
19632
19640
|
last_row_id: result.meta?.last_row_id
|
|
19633
19641
|
});
|
|
19634
|
-
const verifyStmt =
|
|
19642
|
+
const verifyStmt = db.prepare("SELECT * FROM content_fields WHERE id = ?");
|
|
19635
19643
|
const verifyResult = await verifyStmt.bind(fieldId).first();
|
|
19636
19644
|
console.log("[Field Update] Verification - field after update:", verifyResult);
|
|
19637
19645
|
console.log("[Field Update] Successfully updated field with type:", fieldType);
|
|
@@ -19644,8 +19652,8 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19644
19652
|
adminCollectionsRoutes.delete("/:collectionId/fields/:fieldId", async (c) => {
|
|
19645
19653
|
try {
|
|
19646
19654
|
const fieldId = c.req.param("fieldId");
|
|
19647
|
-
const
|
|
19648
|
-
const deleteStmt =
|
|
19655
|
+
const db = c.env.DB;
|
|
19656
|
+
const deleteStmt = db.prepare("DELETE FROM content_fields WHERE id = ?");
|
|
19649
19657
|
await deleteStmt.bind(fieldId).run();
|
|
19650
19658
|
return c.json({ success: true });
|
|
19651
19659
|
} catch (error) {
|
|
@@ -19660,9 +19668,9 @@ adminCollectionsRoutes.post("/:collectionId/fields/reorder", async (c) => {
|
|
|
19660
19668
|
if (!Array.isArray(fieldIds)) {
|
|
19661
19669
|
return c.json({ success: false, error: "Invalid field order data." });
|
|
19662
19670
|
}
|
|
19663
|
-
const
|
|
19671
|
+
const db = c.env.DB;
|
|
19664
19672
|
for (let i = 0; i < fieldIds.length; i++) {
|
|
19665
|
-
const updateStmt =
|
|
19673
|
+
const updateStmt = db.prepare("UPDATE content_fields SET field_order = ?, updated_at = ? WHERE id = ?");
|
|
19666
19674
|
await updateStmt.bind(i + 1, Date.now(), fieldIds[i]).run();
|
|
19667
19675
|
}
|
|
19668
19676
|
return c.json({ success: true });
|
|
@@ -21121,7 +21129,7 @@ function renderDatabaseToolsSettings(settings) {
|
|
|
21121
21129
|
|
|
21122
21130
|
// src/routes/admin-settings.ts
|
|
21123
21131
|
var adminSettingsRoutes = new hono.Hono();
|
|
21124
|
-
adminSettingsRoutes.use("*",
|
|
21132
|
+
adminSettingsRoutes.use("*", chunk5UUYHAZT_cjs.requireAuth());
|
|
21125
21133
|
function getMockSettings(user) {
|
|
21126
21134
|
return {
|
|
21127
21135
|
general: {
|
|
@@ -21185,8 +21193,8 @@ adminSettingsRoutes.get("/", (c) => {
|
|
|
21185
21193
|
});
|
|
21186
21194
|
adminSettingsRoutes.get("/general", async (c) => {
|
|
21187
21195
|
const user = c.get("user");
|
|
21188
|
-
const
|
|
21189
|
-
const settingsService = new
|
|
21196
|
+
const db = c.env.DB;
|
|
21197
|
+
const settingsService = new chunkES3BRZQJ_cjs.SettingsService(db);
|
|
21190
21198
|
const generalSettings = await settingsService.getGeneralSettings(user?.email);
|
|
21191
21199
|
const mockSettings = getMockSettings(user);
|
|
21192
21200
|
mockSettings.general = generalSettings;
|
|
@@ -21288,8 +21296,8 @@ adminSettingsRoutes.get("/database-tools", (c) => {
|
|
|
21288
21296
|
});
|
|
21289
21297
|
adminSettingsRoutes.get("/api/migrations/status", async (c) => {
|
|
21290
21298
|
try {
|
|
21291
|
-
const
|
|
21292
|
-
const migrationService = new
|
|
21299
|
+
const db = c.env.DB;
|
|
21300
|
+
const migrationService = new chunk23VPL6VI_cjs.MigrationService(db);
|
|
21293
21301
|
const status = await migrationService.getMigrationStatus();
|
|
21294
21302
|
return c.json({
|
|
21295
21303
|
success: true,
|
|
@@ -21312,8 +21320,8 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
21312
21320
|
error: "Unauthorized. Admin access required."
|
|
21313
21321
|
}, 403);
|
|
21314
21322
|
}
|
|
21315
|
-
const
|
|
21316
|
-
const migrationService = new
|
|
21323
|
+
const db = c.env.DB;
|
|
21324
|
+
const migrationService = new chunk23VPL6VI_cjs.MigrationService(db);
|
|
21317
21325
|
const result = await migrationService.runPendingMigrations();
|
|
21318
21326
|
return c.json({
|
|
21319
21327
|
success: result.success,
|
|
@@ -21330,8 +21338,8 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
21330
21338
|
});
|
|
21331
21339
|
adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
21332
21340
|
try {
|
|
21333
|
-
const
|
|
21334
|
-
const migrationService = new
|
|
21341
|
+
const db = c.env.DB;
|
|
21342
|
+
const migrationService = new chunk23VPL6VI_cjs.MigrationService(db);
|
|
21335
21343
|
const validation = await migrationService.validateSchema();
|
|
21336
21344
|
return c.json({
|
|
21337
21345
|
success: true,
|
|
@@ -21347,8 +21355,8 @@ adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
|
21347
21355
|
});
|
|
21348
21356
|
adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
|
|
21349
21357
|
try {
|
|
21350
|
-
const
|
|
21351
|
-
const tablesQuery = await
|
|
21358
|
+
const db = c.env.DB;
|
|
21359
|
+
const tablesQuery = await db.prepare(`
|
|
21352
21360
|
SELECT name FROM sqlite_master
|
|
21353
21361
|
WHERE type='table'
|
|
21354
21362
|
AND name NOT LIKE 'sqlite_%'
|
|
@@ -21360,7 +21368,7 @@ adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
|
|
|
21360
21368
|
const tableStats = await Promise.all(
|
|
21361
21369
|
tables.map(async (table) => {
|
|
21362
21370
|
try {
|
|
21363
|
-
const countResult = await
|
|
21371
|
+
const countResult = await db.prepare(`SELECT COUNT(*) as count FROM ${table.name}`).first();
|
|
21364
21372
|
const rowCount = countResult?.count || 0;
|
|
21365
21373
|
totalRows += rowCount;
|
|
21366
21374
|
return {
|
|
@@ -21397,8 +21405,8 @@ adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
|
|
|
21397
21405
|
});
|
|
21398
21406
|
adminSettingsRoutes.get("/api/database-tools/validate", async (c) => {
|
|
21399
21407
|
try {
|
|
21400
|
-
const
|
|
21401
|
-
const integrityResult = await
|
|
21408
|
+
const db = c.env.DB;
|
|
21409
|
+
const integrityResult = await db.prepare("PRAGMA integrity_check").first();
|
|
21402
21410
|
const isValid = integrityResult?.integrity_check === "ok";
|
|
21403
21411
|
return c.json({
|
|
21404
21412
|
success: true,
|
|
@@ -21453,11 +21461,11 @@ adminSettingsRoutes.post("/api/database-tools/truncate", async (c) => {
|
|
|
21453
21461
|
error: "No tables specified for truncation"
|
|
21454
21462
|
}, 400);
|
|
21455
21463
|
}
|
|
21456
|
-
const
|
|
21464
|
+
const db = c.env.DB;
|
|
21457
21465
|
const results = [];
|
|
21458
21466
|
for (const tableName of tablesToTruncate) {
|
|
21459
21467
|
try {
|
|
21460
|
-
await
|
|
21468
|
+
await db.prepare(`DELETE FROM ${tableName}`).run();
|
|
21461
21469
|
results.push({ table: tableName, success: true });
|
|
21462
21470
|
} catch (error) {
|
|
21463
21471
|
console.error(`Error truncating ${tableName}:`, error);
|
|
@@ -21487,8 +21495,8 @@ adminSettingsRoutes.post("/general", async (c) => {
|
|
|
21487
21495
|
}, 403);
|
|
21488
21496
|
}
|
|
21489
21497
|
const formData = await c.req.formData();
|
|
21490
|
-
const
|
|
21491
|
-
const settingsService = new
|
|
21498
|
+
const db = c.env.DB;
|
|
21499
|
+
const settingsService = new chunkES3BRZQJ_cjs.SettingsService(db);
|
|
21492
21500
|
const settings = {
|
|
21493
21501
|
siteName: formData.get("siteName"),
|
|
21494
21502
|
siteDescription: formData.get("siteDescription"),
|
|
@@ -21576,5 +21584,5 @@ exports.auth_default = auth_default;
|
|
|
21576
21584
|
exports.router = router;
|
|
21577
21585
|
exports.test_cleanup_default = test_cleanup_default;
|
|
21578
21586
|
exports.userRoutes = userRoutes;
|
|
21579
|
-
//# sourceMappingURL=chunk-
|
|
21580
|
-
//# sourceMappingURL=chunk-
|
|
21587
|
+
//# sourceMappingURL=chunk-5QJX2VMP.cjs.map
|
|
21588
|
+
//# sourceMappingURL=chunk-5QJX2VMP.cjs.map
|