@sonicjs-cms/core 2.0.11 → 2.0.12
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/{chunk-AMSTLQFI.cjs → chunk-22EFGHAX.cjs} +4 -4
- package/dist/chunk-22EFGHAX.cjs.map +1 -0
- package/dist/{chunk-NNXPAPUD.cjs → chunk-2HRF65VF.cjs} +7 -4
- package/dist/chunk-2HRF65VF.cjs.map +1 -0
- package/dist/{chunk-DOR2IU73.cjs → chunk-3F4LF7LW.cjs} +249 -2
- package/dist/chunk-3F4LF7LW.cjs.map +1 -0
- package/dist/chunk-3OKKNBPD.cjs +70 -0
- package/dist/chunk-3OKKNBPD.cjs.map +1 -0
- package/dist/{chunk-CLLJFZ5U.js → chunk-6B4ENDQM.js} +805 -466
- package/dist/chunk-6B4ENDQM.js.map +1 -0
- package/dist/chunk-AUVW4I3D.js +1550 -0
- package/dist/chunk-AUVW4I3D.js.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-DU7JJZN7.js → chunk-DSDHGJ4F.js} +7 -4
- package/dist/chunk-DSDHGJ4F.js.map +1 -0
- 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-X2VADBA4.cjs → chunk-F4IGVB2V.cjs} +7 -7
- package/dist/{chunk-X2VADBA4.cjs.map → chunk-F4IGVB2V.cjs.map} +1 -1
- package/dist/{chunk-IM2LGCYD.cjs → chunk-K5WUGEXH.cjs} +905 -565
- package/dist/chunk-K5WUGEXH.cjs.map +1 -0
- package/dist/{chunk-FYWJMETG.js → chunk-LBSKQKYL.js} +4 -4
- package/dist/{chunk-FYWJMETG.js.map → chunk-LBSKQKYL.js.map} +1 -1
- package/dist/{chunk-I5ZPYKNX.js → chunk-LWMMMW43.js} +4 -4
- package/dist/chunk-LWMMMW43.js.map +1 -0
- package/dist/{chunk-6FR25MPC.js → chunk-M2YDOOBC.js} +246 -3
- package/dist/chunk-M2YDOOBC.js.map +1 -0
- package/dist/chunk-RDJ2QLA2.cjs +1552 -0
- package/dist/chunk-RDJ2QLA2.cjs.map +1 -0
- package/dist/chunk-RKNHW6QU.js +61 -0
- package/dist/chunk-RKNHW6QU.js.map +1 -0
- package/dist/index.cjs +139 -137
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -11
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +24 -24
- package/dist/middleware.js +3 -3
- package/dist/migrations-DURR3GZX.js +4 -0
- package/dist/{migrations-IHERIQVD.js.map → migrations-DURR3GZX.js.map} +1 -1
- package/dist/migrations-P5BD7WQK.cjs +13 -0
- package/dist/{migrations-POFD5KNG.cjs.map → migrations-P5BD7WQK.cjs.map} +1 -1
- package/dist/plugins.cjs +7 -7
- package/dist/plugins.js +1 -1
- package/dist/routes.cjs +30 -25
- package/dist/routes.js +7 -6
- package/dist/services.cjs +41 -24
- package/dist/services.js +4 -3
- package/dist/utils.cjs +44 -11
- package/dist/utils.js +2 -1
- package/migrations/001_initial_schema.sql +1 -1
- package/migrations/{023_add_mdxeditor_plugin.sql → 023_add_easy_mdx_plugin.sql} +7 -7
- package/migrations/025_rename_mdxeditor_to_easy_mdx.sql +22 -0
- package/package.json +5 -2
- package/dist/chunk-6FR25MPC.js.map +0 -1
- package/dist/chunk-AMSTLQFI.cjs.map +0 -1
- package/dist/chunk-CLLJFZ5U.js.map +0 -1
- package/dist/chunk-DOR2IU73.cjs.map +0 -1
- package/dist/chunk-DU7JJZN7.js.map +0 -1
- package/dist/chunk-I5ZPYKNX.js.map +0 -1
- package/dist/chunk-IM2LGCYD.cjs.map +0 -1
- package/dist/chunk-NNXPAPUD.cjs.map +0 -1
- package/dist/chunk-T7IYBGGO.cjs +0 -746
- package/dist/chunk-T7IYBGGO.cjs.map +0 -1
- package/dist/chunk-ZPMFT2JW.js +0 -744
- package/dist/chunk-ZPMFT2JW.js.map +0 -1
- package/dist/migrations-IHERIQVD.js +0 -4
- package/dist/migrations-POFD5KNG.cjs +0 -13
- package/migrations/013_code_examples_plugin.sql +0 -177
- package/migrations/025_add_easymde_plugin.sql +0 -25
- /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 chunk3F4LF7LW_cjs = require('./chunk-3F4LF7LW.cjs');
|
|
4
|
+
var chunkF4IGVB2V_cjs = require('./chunk-F4IGVB2V.cjs');
|
|
5
|
+
var chunk22EFGHAX_cjs = require('./chunk-22EFGHAX.cjs');
|
|
6
|
+
var chunkRDJ2QLA2_cjs = require('./chunk-RDJ2QLA2.cjs');
|
|
7
7
|
var chunkYU6QFFI4_cjs = require('./chunk-YU6QFFI4.cjs');
|
|
8
|
-
var
|
|
8
|
+
var chunk2HRF65VF_cjs = require('./chunk-2HRF65VF.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 db2 = c.env.DB;
|
|
23
|
+
const stmt = db2.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("/", chunkF4IGVB2V_cjs.requireAuth(), async (c) => {
|
|
48
48
|
try {
|
|
49
|
-
const
|
|
49
|
+
const db2 = 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("/", chunkX2VADBA4_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 = db2.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("/", chunkX2VADBA4_cjs.requireAuth(), async (c) => {
|
|
|
67
67
|
}
|
|
68
68
|
const contentId = crypto.randomUUID();
|
|
69
69
|
const now = Date.now();
|
|
70
|
-
const insertStmt =
|
|
70
|
+
const insertStmt = db2.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("/", chunkX2VADBA4_cjs.requireAuth(), async (c) => {
|
|
|
85
85
|
now,
|
|
86
86
|
now
|
|
87
87
|
).run();
|
|
88
|
-
const cache =
|
|
88
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_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 = db2.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("/", chunkX2VADBA4_cjs.requireAuth(), async (c) => {
|
|
|
110
110
|
}, 500);
|
|
111
111
|
}
|
|
112
112
|
});
|
|
113
|
-
apiContentCrudRoutes.put("/:id",
|
|
113
|
+
apiContentCrudRoutes.put("/:id", chunkF4IGVB2V_cjs.requireAuth(), async (c) => {
|
|
114
114
|
try {
|
|
115
115
|
const id = c.req.param("id");
|
|
116
|
-
const
|
|
116
|
+
const db2 = c.env.DB;
|
|
117
117
|
const body = await c.req.json();
|
|
118
|
-
const existingStmt =
|
|
118
|
+
const existingStmt = db2.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", chunkX2VADBA4_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 = db2.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 = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_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 = db2.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", chunkX2VADBA4_cjs.requireAuth(), async (c) => {
|
|
|
174
174
|
}, 500);
|
|
175
175
|
}
|
|
176
176
|
});
|
|
177
|
-
apiContentCrudRoutes.delete("/:id",
|
|
177
|
+
apiContentCrudRoutes.delete("/:id", chunkF4IGVB2V_cjs.requireAuth(), async (c) => {
|
|
178
178
|
try {
|
|
179
179
|
const id = c.req.param("id");
|
|
180
|
-
const
|
|
181
|
-
const existingStmt =
|
|
180
|
+
const db2 = c.env.DB;
|
|
181
|
+
const existingStmt = db2.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 = db2.prepare("DELETE FROM content WHERE id = ?");
|
|
187
187
|
await deleteStmt.bind(id).run();
|
|
188
|
-
const cache =
|
|
188
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_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 chunkF4IGVB2V_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 db2 = c.env.DB;
|
|
260
260
|
const cacheEnabled = c.get("cacheEnabled");
|
|
261
|
-
const cache =
|
|
261
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_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 = db2.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 db2 = 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 = db2.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 = chunk2HRF65VF_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 chunk2HRF65VF_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 = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_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 = db2.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 db2 = c.env.DB;
|
|
424
424
|
const queryParams = c.req.query();
|
|
425
|
-
const collectionStmt =
|
|
425
|
+
const collectionStmt = db2.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 = chunk2HRF65VF_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 chunk2HRF65VF_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 = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_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 = db2.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("*", chunkF4IGVB2V_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 db2 = c.env.DB;
|
|
1246
|
+
const contentStats = await db2.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 db2.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 db2.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("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
1316
|
+
adminApiRoutes.use("*", chunkF4IGVB2V_cjs.requireRole(["admin", "editor"]));
|
|
1317
1317
|
adminApiRoutes.get("/stats", async (c) => {
|
|
1318
1318
|
try {
|
|
1319
|
-
const
|
|
1319
|
+
const db2 = c.env.DB;
|
|
1320
1320
|
let collectionsCount = 0;
|
|
1321
1321
|
try {
|
|
1322
|
-
const collectionsStmt =
|
|
1322
|
+
const collectionsStmt = db2.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 = db2.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 = db2.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 = db2.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 db2 = c.env.DB;
|
|
1370
1370
|
let databaseSize = 0;
|
|
1371
1371
|
try {
|
|
1372
|
-
const result = await
|
|
1372
|
+
const result = await db2.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 = db2.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 db2 = c.env.DB;
|
|
1399
1399
|
const limit = parseInt(c.req.query("limit") || "10");
|
|
1400
|
-
const activityStmt =
|
|
1400
|
+
const activityStmt = db2.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 db2 = 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 = db2.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 = db2.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 = db2.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 db2 = c.env.DB;
|
|
1516
|
+
const stmt = db2.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 = db2.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 db2 = 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 = db2.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 = db2.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 db2 = c.env.DB;
|
|
1648
|
+
const checkStmt = db2.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 = db2.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 db2 = c.env.DB;
|
|
1695
|
+
const collectionStmt = db2.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 = db2.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 = db2.prepare("DELETE FROM content_fields WHERE collection_id = ?");
|
|
1708
1708
|
await deleteFieldsStmt.bind(id).run();
|
|
1709
|
-
const deleteStmt =
|
|
1709
|
+
const deleteStmt = db2.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-P5BD7WQK.cjs');
|
|
1726
|
+
const db2 = c.env.DB;
|
|
1727
|
+
const migrationService = new MigrationService2(db2);
|
|
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-P5BD7WQK.cjs');
|
|
1751
|
+
const db2 = c.env.DB;
|
|
1752
|
+
const migrationService = new MigrationService2(db2);
|
|
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-P5BD7WQK.cjs');
|
|
1770
|
+
const db2 = c.env.DB;
|
|
1771
|
+
const migrationService = new MigrationService2(db2);
|
|
1772
1772
|
const validation = await migrationService.validateSchema();
|
|
1773
1773
|
return c.json({
|
|
1774
1774
|
success: true,
|
|
@@ -2160,10 +2160,10 @@ authRoutes.get("/login", async (c) => {
|
|
|
2160
2160
|
message: message || void 0,
|
|
2161
2161
|
version: c.get("appVersion")
|
|
2162
2162
|
};
|
|
2163
|
-
const
|
|
2163
|
+
const db2 = c.env.DB;
|
|
2164
2164
|
let demoLoginActive = false;
|
|
2165
2165
|
try {
|
|
2166
|
-
const plugin = await
|
|
2166
|
+
const plugin = await db2.prepare("SELECT * FROM plugins WHERE id = ? AND status = ?").bind("demo-login-prefill", "active").first();
|
|
2167
2167
|
demoLoginActive = !!plugin;
|
|
2168
2168
|
} catch (error2) {
|
|
2169
2169
|
}
|
|
@@ -2184,21 +2184,21 @@ authRoutes.post(
|
|
|
2184
2184
|
"/register",
|
|
2185
2185
|
async (c) => {
|
|
2186
2186
|
try {
|
|
2187
|
-
const
|
|
2187
|
+
const db2 = c.env.DB;
|
|
2188
2188
|
let requestData;
|
|
2189
2189
|
try {
|
|
2190
2190
|
requestData = await c.req.json();
|
|
2191
2191
|
} catch (parseError) {
|
|
2192
2192
|
return c.json({ error: "Invalid JSON in request body" }, 400);
|
|
2193
2193
|
}
|
|
2194
|
-
const validationSchema = await authValidationService.buildRegistrationSchema(
|
|
2194
|
+
const validationSchema = await authValidationService.buildRegistrationSchema(db2);
|
|
2195
2195
|
let validatedData;
|
|
2196
2196
|
try {
|
|
2197
2197
|
validatedData = await validationSchema.parseAsync(requestData);
|
|
2198
2198
|
} catch (validationError) {
|
|
2199
2199
|
return c.json({
|
|
2200
2200
|
error: "Validation failed",
|
|
2201
|
-
details: validationError.
|
|
2201
|
+
details: validationError.issues?.map((e) => e.message) || [validationError.message || "Invalid request data"]
|
|
2202
2202
|
}, 400);
|
|
2203
2203
|
}
|
|
2204
2204
|
const email = validatedData.email;
|
|
@@ -2207,14 +2207,14 @@ authRoutes.post(
|
|
|
2207
2207
|
const firstName = validatedData.firstName || authValidationService.generateDefaultValue("firstName", validatedData);
|
|
2208
2208
|
const lastName = validatedData.lastName || authValidationService.generateDefaultValue("lastName", validatedData);
|
|
2209
2209
|
const normalizedEmail = email.toLowerCase();
|
|
2210
|
-
const existingUser = await
|
|
2210
|
+
const existingUser = await db2.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind(normalizedEmail, username).first();
|
|
2211
2211
|
if (existingUser) {
|
|
2212
2212
|
return c.json({ error: "User with this email or username already exists" }, 400);
|
|
2213
2213
|
}
|
|
2214
|
-
const passwordHash = await
|
|
2214
|
+
const passwordHash = await chunkF4IGVB2V_cjs.AuthManager.hashPassword(password);
|
|
2215
2215
|
const userId = crypto.randomUUID();
|
|
2216
2216
|
const now = /* @__PURE__ */ new Date();
|
|
2217
|
-
await
|
|
2217
|
+
await db2.prepare(`
|
|
2218
2218
|
INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
|
|
2219
2219
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2220
2220
|
`).bind(
|
|
@@ -2231,7 +2231,7 @@ authRoutes.post(
|
|
|
2231
2231
|
now.getTime(),
|
|
2232
2232
|
now.getTime()
|
|
2233
2233
|
).run();
|
|
2234
|
-
const token = await
|
|
2234
|
+
const token = await chunkF4IGVB2V_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer");
|
|
2235
2235
|
cookie.setCookie(c, "auth_token", token, {
|
|
2236
2236
|
httpOnly: true,
|
|
2237
2237
|
secure: true,
|
|
@@ -2267,15 +2267,15 @@ authRoutes.post("/login", async (c) => {
|
|
|
2267
2267
|
const body = await c.req.json();
|
|
2268
2268
|
const validation = loginSchema.safeParse(body);
|
|
2269
2269
|
if (!validation.success) {
|
|
2270
|
-
return c.json({ error: "Validation failed", details: validation.error.
|
|
2270
|
+
return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
|
|
2271
2271
|
}
|
|
2272
2272
|
const { email, password } = validation.data;
|
|
2273
|
-
const
|
|
2273
|
+
const db2 = c.env.DB;
|
|
2274
2274
|
const normalizedEmail = email.toLowerCase();
|
|
2275
|
-
const cache =
|
|
2275
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_cjs.CACHE_CONFIGS.user);
|
|
2276
2276
|
let user = await cache.get(cache.generateKey("user", `email:${normalizedEmail}`));
|
|
2277
2277
|
if (!user) {
|
|
2278
|
-
user = await
|
|
2278
|
+
user = await db2.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
|
|
2279
2279
|
if (user) {
|
|
2280
2280
|
await cache.set(cache.generateKey("user", `email:${normalizedEmail}`), user);
|
|
2281
2281
|
await cache.set(cache.generateKey("user", user.id), user);
|
|
@@ -2284,11 +2284,11 @@ authRoutes.post("/login", async (c) => {
|
|
|
2284
2284
|
if (!user) {
|
|
2285
2285
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2286
2286
|
}
|
|
2287
|
-
const isValidPassword = await
|
|
2287
|
+
const isValidPassword = await chunkF4IGVB2V_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2288
2288
|
if (!isValidPassword) {
|
|
2289
2289
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2290
2290
|
}
|
|
2291
|
-
const token = await
|
|
2291
|
+
const token = await chunkF4IGVB2V_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2292
2292
|
cookie.setCookie(c, "auth_token", token, {
|
|
2293
2293
|
httpOnly: true,
|
|
2294
2294
|
secure: true,
|
|
@@ -2296,7 +2296,7 @@ authRoutes.post("/login", async (c) => {
|
|
|
2296
2296
|
maxAge: 60 * 60 * 24
|
|
2297
2297
|
// 24 hours
|
|
2298
2298
|
});
|
|
2299
|
-
await
|
|
2299
|
+
await db2.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
|
|
2300
2300
|
await cache.delete(cache.generateKey("user", user.id));
|
|
2301
2301
|
await cache.delete(cache.generateKey("user", `email:${normalizedEmail}`));
|
|
2302
2302
|
return c.json({
|
|
@@ -2337,14 +2337,14 @@ authRoutes.get("/logout", (c) => {
|
|
|
2337
2337
|
});
|
|
2338
2338
|
return c.redirect("/auth/login?message=You have been logged out successfully");
|
|
2339
2339
|
});
|
|
2340
|
-
authRoutes.get("/me",
|
|
2340
|
+
authRoutes.get("/me", chunkF4IGVB2V_cjs.requireAuth(), async (c) => {
|
|
2341
2341
|
try {
|
|
2342
2342
|
const user = c.get("user");
|
|
2343
2343
|
if (!user) {
|
|
2344
2344
|
return c.json({ error: "Not authenticated" }, 401);
|
|
2345
2345
|
}
|
|
2346
|
-
const
|
|
2347
|
-
const userData = await
|
|
2346
|
+
const db2 = c.env.DB;
|
|
2347
|
+
const userData = await db2.prepare("SELECT id, email, username, first_name, last_name, role, created_at FROM users WHERE id = ?").bind(user.userId).first();
|
|
2348
2348
|
if (!userData) {
|
|
2349
2349
|
return c.json({ error: "User not found" }, 404);
|
|
2350
2350
|
}
|
|
@@ -2354,13 +2354,13 @@ authRoutes.get("/me", chunkX2VADBA4_cjs.requireAuth(), async (c) => {
|
|
|
2354
2354
|
return c.json({ error: "Failed to get user" }, 500);
|
|
2355
2355
|
}
|
|
2356
2356
|
});
|
|
2357
|
-
authRoutes.post("/refresh",
|
|
2357
|
+
authRoutes.post("/refresh", chunkF4IGVB2V_cjs.requireAuth(), async (c) => {
|
|
2358
2358
|
try {
|
|
2359
2359
|
const user = c.get("user");
|
|
2360
2360
|
if (!user) {
|
|
2361
2361
|
return c.json({ error: "Not authenticated" }, 401);
|
|
2362
2362
|
}
|
|
2363
|
-
const token = await
|
|
2363
|
+
const token = await chunkF4IGVB2V_cjs.AuthManager.generateToken(user.userId, user.email, user.role);
|
|
2364
2364
|
cookie.setCookie(c, "auth_token", token, {
|
|
2365
2365
|
httpOnly: true,
|
|
2366
2366
|
secure: true,
|
|
@@ -2376,7 +2376,7 @@ authRoutes.post("/refresh", chunkX2VADBA4_cjs.requireAuth(), async (c) => {
|
|
|
2376
2376
|
});
|
|
2377
2377
|
authRoutes.post("/register/form", async (c) => {
|
|
2378
2378
|
try {
|
|
2379
|
-
const
|
|
2379
|
+
const db2 = c.env.DB;
|
|
2380
2380
|
const formData = await c.req.formData();
|
|
2381
2381
|
const requestData = {
|
|
2382
2382
|
email: formData.get("email"),
|
|
@@ -2387,12 +2387,12 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2387
2387
|
};
|
|
2388
2388
|
const normalizedEmail = requestData.email?.toLowerCase();
|
|
2389
2389
|
requestData.email = normalizedEmail;
|
|
2390
|
-
const validationSchema = await authValidationService.buildRegistrationSchema(
|
|
2390
|
+
const validationSchema = await authValidationService.buildRegistrationSchema(db2);
|
|
2391
2391
|
const validation = await validationSchema.safeParseAsync(requestData);
|
|
2392
2392
|
if (!validation.success) {
|
|
2393
2393
|
return c.html(html.html`
|
|
2394
2394
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
2395
|
-
${validation.error.
|
|
2395
|
+
${validation.error.issues.map((err) => err.message).join(", ")}
|
|
2396
2396
|
</div>
|
|
2397
2397
|
`);
|
|
2398
2398
|
}
|
|
@@ -2401,7 +2401,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2401
2401
|
const username = validatedData.username || authValidationService.generateDefaultValue("username", validatedData);
|
|
2402
2402
|
const firstName = validatedData.firstName || authValidationService.generateDefaultValue("firstName", validatedData);
|
|
2403
2403
|
const lastName = validatedData.lastName || authValidationService.generateDefaultValue("lastName", validatedData);
|
|
2404
|
-
const existingUser = await
|
|
2404
|
+
const existingUser = await db2.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind(normalizedEmail, username).first();
|
|
2405
2405
|
if (existingUser) {
|
|
2406
2406
|
return c.html(html.html`
|
|
2407
2407
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2409,10 +2409,10 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2409
2409
|
</div>
|
|
2410
2410
|
`);
|
|
2411
2411
|
}
|
|
2412
|
-
const passwordHash = await
|
|
2412
|
+
const passwordHash = await chunkF4IGVB2V_cjs.AuthManager.hashPassword(password);
|
|
2413
2413
|
const userId = crypto.randomUUID();
|
|
2414
2414
|
const now = /* @__PURE__ */ new Date();
|
|
2415
|
-
await
|
|
2415
|
+
await db2.prepare(`
|
|
2416
2416
|
INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
|
|
2417
2417
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2418
2418
|
`).bind(
|
|
@@ -2429,7 +2429,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2429
2429
|
now.getTime(),
|
|
2430
2430
|
now.getTime()
|
|
2431
2431
|
).run();
|
|
2432
|
-
const token = await
|
|
2432
|
+
const token = await chunkF4IGVB2V_cjs.AuthManager.generateToken(userId, normalizedEmail, "admin");
|
|
2433
2433
|
cookie.setCookie(c, "auth_token", token, {
|
|
2434
2434
|
httpOnly: true,
|
|
2435
2435
|
secure: false,
|
|
@@ -2467,12 +2467,12 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2467
2467
|
if (!validation.success) {
|
|
2468
2468
|
return c.html(html.html`
|
|
2469
2469
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
2470
|
-
${validation.error.
|
|
2470
|
+
${validation.error.issues.map((err) => err.message).join(", ")}
|
|
2471
2471
|
</div>
|
|
2472
2472
|
`);
|
|
2473
2473
|
}
|
|
2474
|
-
const
|
|
2475
|
-
const user = await
|
|
2474
|
+
const db2 = c.env.DB;
|
|
2475
|
+
const user = await db2.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
|
|
2476
2476
|
if (!user) {
|
|
2477
2477
|
return c.html(html.html`
|
|
2478
2478
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2480,7 +2480,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2480
2480
|
</div>
|
|
2481
2481
|
`);
|
|
2482
2482
|
}
|
|
2483
|
-
const isValidPassword = await
|
|
2483
|
+
const isValidPassword = await chunkF4IGVB2V_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2484
2484
|
if (!isValidPassword) {
|
|
2485
2485
|
return c.html(html.html`
|
|
2486
2486
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2488,7 +2488,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2488
2488
|
</div>
|
|
2489
2489
|
`);
|
|
2490
2490
|
}
|
|
2491
|
-
const token = await
|
|
2491
|
+
const token = await chunkF4IGVB2V_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2492
2492
|
cookie.setCookie(c, "auth_token", token, {
|
|
2493
2493
|
httpOnly: true,
|
|
2494
2494
|
secure: false,
|
|
@@ -2497,7 +2497,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2497
2497
|
maxAge: 60 * 60 * 24
|
|
2498
2498
|
// 24 hours
|
|
2499
2499
|
});
|
|
2500
|
-
await
|
|
2500
|
+
await db2.prepare("UPDATE users SET last_login_at = ? WHERE id = ?").bind((/* @__PURE__ */ new Date()).getTime(), user.id).run();
|
|
2501
2501
|
return c.html(html.html`
|
|
2502
2502
|
<div id="form-response">
|
|
2503
2503
|
<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 +2528,8 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2528
2528
|
});
|
|
2529
2529
|
authRoutes.post("/seed-admin", async (c) => {
|
|
2530
2530
|
try {
|
|
2531
|
-
const
|
|
2532
|
-
await
|
|
2531
|
+
const db2 = c.env.DB;
|
|
2532
|
+
await db2.prepare(`
|
|
2533
2533
|
CREATE TABLE IF NOT EXISTS users (
|
|
2534
2534
|
id TEXT PRIMARY KEY,
|
|
2535
2535
|
email TEXT NOT NULL UNIQUE,
|
|
@@ -2545,10 +2545,10 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2545
2545
|
updated_at INTEGER NOT NULL
|
|
2546
2546
|
)
|
|
2547
2547
|
`).run();
|
|
2548
|
-
const existingAdmin = await
|
|
2548
|
+
const existingAdmin = await db2.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind("admin@sonicjs.com", "admin").first();
|
|
2549
2549
|
if (existingAdmin) {
|
|
2550
|
-
const passwordHash2 = await
|
|
2551
|
-
await
|
|
2550
|
+
const passwordHash2 = await chunkF4IGVB2V_cjs.AuthManager.hashPassword("sonicjs!");
|
|
2551
|
+
await db2.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?").bind(passwordHash2, Date.now(), existingAdmin.id).run();
|
|
2552
2552
|
return c.json({
|
|
2553
2553
|
message: "Admin user already exists (password updated)",
|
|
2554
2554
|
user: {
|
|
@@ -2559,11 +2559,11 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2559
2559
|
}
|
|
2560
2560
|
});
|
|
2561
2561
|
}
|
|
2562
|
-
const passwordHash = await
|
|
2562
|
+
const passwordHash = await chunkF4IGVB2V_cjs.AuthManager.hashPassword("sonicjs!");
|
|
2563
2563
|
const userId = "admin-user-id";
|
|
2564
2564
|
const now = Date.now();
|
|
2565
2565
|
const adminEmail = "admin@sonicjs.com".toLowerCase();
|
|
2566
|
-
await
|
|
2566
|
+
await db2.prepare(`
|
|
2567
2567
|
INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)
|
|
2568
2568
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2569
2569
|
`).bind(
|
|
@@ -2610,8 +2610,8 @@ authRoutes.get("/accept-invitation", async (c) => {
|
|
|
2610
2610
|
</html>
|
|
2611
2611
|
`);
|
|
2612
2612
|
}
|
|
2613
|
-
const
|
|
2614
|
-
const userStmt =
|
|
2613
|
+
const db2 = c.env.DB;
|
|
2614
|
+
const userStmt = db2.prepare(`
|
|
2615
2615
|
SELECT id, email, first_name, last_name, role, invited_at
|
|
2616
2616
|
FROM users
|
|
2617
2617
|
WHERE invitation_token = ? AND is_active = 0
|
|
@@ -2757,8 +2757,8 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2757
2757
|
if (password.length < 8) {
|
|
2758
2758
|
return c.json({ error: "Password must be at least 8 characters long" }, 400);
|
|
2759
2759
|
}
|
|
2760
|
-
const
|
|
2761
|
-
const userStmt =
|
|
2760
|
+
const db2 = c.env.DB;
|
|
2761
|
+
const userStmt = db2.prepare(`
|
|
2762
2762
|
SELECT id, email, first_name, last_name, role, invited_at
|
|
2763
2763
|
FROM users
|
|
2764
2764
|
WHERE invitation_token = ? AND is_active = 0
|
|
@@ -2772,15 +2772,15 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2772
2772
|
if (invitationAge > maxAge) {
|
|
2773
2773
|
return c.json({ error: "Invitation has expired" }, 400);
|
|
2774
2774
|
}
|
|
2775
|
-
const existingUsernameStmt =
|
|
2775
|
+
const existingUsernameStmt = db2.prepare(`
|
|
2776
2776
|
SELECT id FROM users WHERE username = ? AND id != ?
|
|
2777
2777
|
`);
|
|
2778
2778
|
const existingUsername = await existingUsernameStmt.bind(username, invitedUser.id).first();
|
|
2779
2779
|
if (existingUsername) {
|
|
2780
2780
|
return c.json({ error: "Username is already taken" }, 400);
|
|
2781
2781
|
}
|
|
2782
|
-
const passwordHash = await
|
|
2783
|
-
const updateStmt =
|
|
2782
|
+
const passwordHash = await chunkF4IGVB2V_cjs.AuthManager.hashPassword(password);
|
|
2783
|
+
const updateStmt = db2.prepare(`
|
|
2784
2784
|
UPDATE users SET
|
|
2785
2785
|
username = ?,
|
|
2786
2786
|
password_hash = ?,
|
|
@@ -2798,7 +2798,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2798
2798
|
Date.now(),
|
|
2799
2799
|
invitedUser.id
|
|
2800
2800
|
).run();
|
|
2801
|
-
const authToken = await
|
|
2801
|
+
const authToken = await chunkF4IGVB2V_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role);
|
|
2802
2802
|
cookie.setCookie(c, "auth_token", authToken, {
|
|
2803
2803
|
httpOnly: true,
|
|
2804
2804
|
secure: true,
|
|
@@ -2823,8 +2823,8 @@ authRoutes.post("/request-password-reset", async (c) => {
|
|
|
2823
2823
|
if (!emailRegex.test(email)) {
|
|
2824
2824
|
return c.json({ error: "Please enter a valid email address" }, 400);
|
|
2825
2825
|
}
|
|
2826
|
-
const
|
|
2827
|
-
const userStmt =
|
|
2826
|
+
const db2 = c.env.DB;
|
|
2827
|
+
const userStmt = db2.prepare(`
|
|
2828
2828
|
SELECT id, email, first_name, last_name FROM users
|
|
2829
2829
|
WHERE email = ? AND is_active = 1
|
|
2830
2830
|
`);
|
|
@@ -2837,7 +2837,7 @@ authRoutes.post("/request-password-reset", async (c) => {
|
|
|
2837
2837
|
}
|
|
2838
2838
|
const resetToken = crypto.randomUUID();
|
|
2839
2839
|
const resetExpires = Date.now() + 60 * 60 * 1e3;
|
|
2840
|
-
const updateStmt =
|
|
2840
|
+
const updateStmt = db2.prepare(`
|
|
2841
2841
|
UPDATE users SET
|
|
2842
2842
|
password_reset_token = ?,
|
|
2843
2843
|
password_reset_expires = ?,
|
|
@@ -2877,8 +2877,8 @@ authRoutes.get("/reset-password", async (c) => {
|
|
|
2877
2877
|
</html>
|
|
2878
2878
|
`);
|
|
2879
2879
|
}
|
|
2880
|
-
const
|
|
2881
|
-
const userStmt =
|
|
2880
|
+
const db2 = c.env.DB;
|
|
2881
|
+
const userStmt = db2.prepare(`
|
|
2882
2882
|
SELECT id, email, first_name, last_name, password_reset_expires
|
|
2883
2883
|
FROM users
|
|
2884
2884
|
WHERE password_reset_token = ? AND is_active = 1
|
|
@@ -3015,8 +3015,8 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3015
3015
|
if (password.length < 8) {
|
|
3016
3016
|
return c.json({ error: "Password must be at least 8 characters long" }, 400);
|
|
3017
3017
|
}
|
|
3018
|
-
const
|
|
3019
|
-
const userStmt =
|
|
3018
|
+
const db2 = c.env.DB;
|
|
3019
|
+
const userStmt = db2.prepare(`
|
|
3020
3020
|
SELECT id, email, password_hash, password_reset_expires
|
|
3021
3021
|
FROM users
|
|
3022
3022
|
WHERE password_reset_token = ? AND is_active = 1
|
|
@@ -3028,9 +3028,9 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3028
3028
|
if (Date.now() > user.password_reset_expires) {
|
|
3029
3029
|
return c.json({ error: "Reset token has expired" }, 400);
|
|
3030
3030
|
}
|
|
3031
|
-
const newPasswordHash = await
|
|
3031
|
+
const newPasswordHash = await chunkF4IGVB2V_cjs.AuthManager.hashPassword(password);
|
|
3032
3032
|
try {
|
|
3033
|
-
const historyStmt =
|
|
3033
|
+
const historyStmt = db2.prepare(`
|
|
3034
3034
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
3035
3035
|
VALUES (?, ?, ?, ?)
|
|
3036
3036
|
`);
|
|
@@ -3043,7 +3043,7 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3043
3043
|
} catch (historyError) {
|
|
3044
3044
|
console.warn("Could not store password history:", historyError);
|
|
3045
3045
|
}
|
|
3046
|
-
const updateStmt =
|
|
3046
|
+
const updateStmt = db2.prepare(`
|
|
3047
3047
|
UPDATE users SET
|
|
3048
3048
|
password_hash = ?,
|
|
3049
3049
|
password_reset_token = NULL,
|
|
@@ -3063,19 +3063,269 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3063
3063
|
}
|
|
3064
3064
|
});
|
|
3065
3065
|
var auth_default = authRoutes;
|
|
3066
|
+
var app = new hono.Hono();
|
|
3067
|
+
app.post("/test-cleanup", async (c) => {
|
|
3068
|
+
const db2 = c.env.DB;
|
|
3069
|
+
if (c.env.ENVIRONMENT === "production") {
|
|
3070
|
+
return c.json({ error: "Cleanup endpoint not available in production" }, 403);
|
|
3071
|
+
}
|
|
3072
|
+
try {
|
|
3073
|
+
let deletedCount = 0;
|
|
3074
|
+
await db2.prepare(`
|
|
3075
|
+
DELETE FROM content_versions
|
|
3076
|
+
WHERE content_id IN (
|
|
3077
|
+
SELECT id FROM content
|
|
3078
|
+
WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
|
|
3079
|
+
)
|
|
3080
|
+
`).run();
|
|
3081
|
+
await db2.prepare(`
|
|
3082
|
+
DELETE FROM workflow_history
|
|
3083
|
+
WHERE content_id IN (
|
|
3084
|
+
SELECT id FROM content
|
|
3085
|
+
WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
|
|
3086
|
+
)
|
|
3087
|
+
`).run();
|
|
3088
|
+
try {
|
|
3089
|
+
await db2.prepare(`
|
|
3090
|
+
DELETE FROM content_data
|
|
3091
|
+
WHERE content_id IN (
|
|
3092
|
+
SELECT id FROM content
|
|
3093
|
+
WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
|
|
3094
|
+
)
|
|
3095
|
+
`).run();
|
|
3096
|
+
} catch (e) {
|
|
3097
|
+
}
|
|
3098
|
+
const contentResult = await db2.prepare(`
|
|
3099
|
+
DELETE FROM content
|
|
3100
|
+
WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'
|
|
3101
|
+
`).run();
|
|
3102
|
+
deletedCount += contentResult.meta?.changes || 0;
|
|
3103
|
+
await db2.prepare(`
|
|
3104
|
+
DELETE FROM api_tokens
|
|
3105
|
+
WHERE user_id IN (
|
|
3106
|
+
SELECT id FROM users
|
|
3107
|
+
WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
|
|
3108
|
+
)
|
|
3109
|
+
`).run();
|
|
3110
|
+
await db2.prepare(`
|
|
3111
|
+
DELETE FROM media
|
|
3112
|
+
WHERE uploaded_by IN (
|
|
3113
|
+
SELECT id FROM users
|
|
3114
|
+
WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
|
|
3115
|
+
)
|
|
3116
|
+
`).run();
|
|
3117
|
+
const usersResult = await db2.prepare(`
|
|
3118
|
+
DELETE FROM users
|
|
3119
|
+
WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')
|
|
3120
|
+
`).run();
|
|
3121
|
+
deletedCount += usersResult.meta?.changes || 0;
|
|
3122
|
+
try {
|
|
3123
|
+
await db2.prepare(`
|
|
3124
|
+
DELETE FROM collection_fields
|
|
3125
|
+
WHERE collection_id IN (
|
|
3126
|
+
SELECT id FROM collections
|
|
3127
|
+
WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
|
|
3128
|
+
)
|
|
3129
|
+
`).run();
|
|
3130
|
+
} catch (e) {
|
|
3131
|
+
}
|
|
3132
|
+
await db2.prepare(`
|
|
3133
|
+
DELETE FROM content
|
|
3134
|
+
WHERE collection_id IN (
|
|
3135
|
+
SELECT id FROM collections
|
|
3136
|
+
WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
|
|
3137
|
+
)
|
|
3138
|
+
`).run();
|
|
3139
|
+
const collectionsResult = await db2.prepare(`
|
|
3140
|
+
DELETE FROM collections
|
|
3141
|
+
WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
|
|
3142
|
+
`).run();
|
|
3143
|
+
deletedCount += collectionsResult.meta?.changes || 0;
|
|
3144
|
+
try {
|
|
3145
|
+
await db2.prepare(`
|
|
3146
|
+
DELETE FROM content_data WHERE content_id NOT IN (SELECT id FROM content)
|
|
3147
|
+
`).run();
|
|
3148
|
+
} catch (e) {
|
|
3149
|
+
}
|
|
3150
|
+
try {
|
|
3151
|
+
await db2.prepare(`
|
|
3152
|
+
DELETE FROM collection_fields WHERE collection_id NOT IN (SELECT id FROM collections)
|
|
3153
|
+
`).run();
|
|
3154
|
+
} catch (e) {
|
|
3155
|
+
}
|
|
3156
|
+
try {
|
|
3157
|
+
await db2.prepare(`
|
|
3158
|
+
DELETE FROM content_versions WHERE content_id NOT IN (SELECT id FROM content)
|
|
3159
|
+
`).run();
|
|
3160
|
+
} catch (e) {
|
|
3161
|
+
}
|
|
3162
|
+
try {
|
|
3163
|
+
await db2.prepare(`
|
|
3164
|
+
DELETE FROM workflow_history WHERE content_id NOT IN (SELECT id FROM content)
|
|
3165
|
+
`).run();
|
|
3166
|
+
} catch (e) {
|
|
3167
|
+
}
|
|
3168
|
+
await db2.prepare(`
|
|
3169
|
+
DELETE FROM activity_logs
|
|
3170
|
+
WHERE id NOT IN (
|
|
3171
|
+
SELECT id FROM activity_logs
|
|
3172
|
+
ORDER BY created_at DESC
|
|
3173
|
+
LIMIT 100
|
|
3174
|
+
)
|
|
3175
|
+
`).run();
|
|
3176
|
+
return c.json({
|
|
3177
|
+
success: true,
|
|
3178
|
+
deletedCount,
|
|
3179
|
+
message: "Test data cleaned up successfully"
|
|
3180
|
+
});
|
|
3181
|
+
} catch (error) {
|
|
3182
|
+
console.error("Test cleanup error:", error);
|
|
3183
|
+
return c.json({
|
|
3184
|
+
success: false,
|
|
3185
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
3186
|
+
}, 500);
|
|
3187
|
+
}
|
|
3188
|
+
});
|
|
3189
|
+
app.post("/test-cleanup/users", async (c) => {
|
|
3190
|
+
const db2 = c.env.DB;
|
|
3191
|
+
if (c.env.ENVIRONMENT === "production") {
|
|
3192
|
+
return c.json({ error: "Cleanup endpoint not available in production" }, 403);
|
|
3193
|
+
}
|
|
3194
|
+
try {
|
|
3195
|
+
const result = await db2.prepare(`
|
|
3196
|
+
DELETE FROM users
|
|
3197
|
+
WHERE email != 'admin@sonicjs.com'
|
|
3198
|
+
AND (
|
|
3199
|
+
email LIKE '%test%'
|
|
3200
|
+
OR email LIKE '%example.com%'
|
|
3201
|
+
OR first_name = 'Test'
|
|
3202
|
+
)
|
|
3203
|
+
`).run();
|
|
3204
|
+
return c.json({
|
|
3205
|
+
success: true,
|
|
3206
|
+
deletedCount: result.meta?.changes || 0,
|
|
3207
|
+
message: "Test users cleaned up successfully"
|
|
3208
|
+
});
|
|
3209
|
+
} catch (error) {
|
|
3210
|
+
console.error("User cleanup error:", error);
|
|
3211
|
+
return c.json({
|
|
3212
|
+
success: false,
|
|
3213
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
3214
|
+
}, 500);
|
|
3215
|
+
}
|
|
3216
|
+
});
|
|
3217
|
+
app.post("/test-cleanup/collections", async (c) => {
|
|
3218
|
+
const db2 = c.env.DB;
|
|
3219
|
+
if (c.env.ENVIRONMENT === "production") {
|
|
3220
|
+
return c.json({ error: "Cleanup endpoint not available in production" }, 403);
|
|
3221
|
+
}
|
|
3222
|
+
try {
|
|
3223
|
+
let deletedCount = 0;
|
|
3224
|
+
const collections = await db2.prepare(`
|
|
3225
|
+
SELECT id FROM collections
|
|
3226
|
+
WHERE name LIKE 'test_%'
|
|
3227
|
+
OR name IN ('blog_posts', 'test_collection', 'products', 'articles')
|
|
3228
|
+
`).all();
|
|
3229
|
+
if (collections.results && collections.results.length > 0) {
|
|
3230
|
+
const collectionIds = collections.results.map((c2) => c2.id);
|
|
3231
|
+
for (const id of collectionIds) {
|
|
3232
|
+
await db2.prepare("DELETE FROM collection_fields WHERE collection_id = ?").bind(id).run();
|
|
3233
|
+
}
|
|
3234
|
+
for (const id of collectionIds) {
|
|
3235
|
+
await db2.prepare("DELETE FROM content WHERE collection_id = ?").bind(id).run();
|
|
3236
|
+
}
|
|
3237
|
+
const result = await db2.prepare(`
|
|
3238
|
+
DELETE FROM collections
|
|
3239
|
+
WHERE id IN (${collectionIds.map(() => "?").join(",")})
|
|
3240
|
+
`).bind(...collectionIds).run();
|
|
3241
|
+
deletedCount = result.meta?.changes || 0;
|
|
3242
|
+
}
|
|
3243
|
+
return c.json({
|
|
3244
|
+
success: true,
|
|
3245
|
+
deletedCount,
|
|
3246
|
+
message: "Test collections cleaned up successfully"
|
|
3247
|
+
});
|
|
3248
|
+
} catch (error) {
|
|
3249
|
+
console.error("Collection cleanup error:", error);
|
|
3250
|
+
return c.json({
|
|
3251
|
+
success: false,
|
|
3252
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
3253
|
+
}, 500);
|
|
3254
|
+
}
|
|
3255
|
+
});
|
|
3256
|
+
app.post("/test-cleanup/content", async (c) => {
|
|
3257
|
+
const db2 = c.env.DB;
|
|
3258
|
+
if (c.env.ENVIRONMENT === "production") {
|
|
3259
|
+
return c.json({ error: "Cleanup endpoint not available in production" }, 403);
|
|
3260
|
+
}
|
|
3261
|
+
try {
|
|
3262
|
+
const result = await db2.prepare(`
|
|
3263
|
+
DELETE FROM content
|
|
3264
|
+
WHERE title LIKE 'Test %'
|
|
3265
|
+
OR title LIKE '%E2E%'
|
|
3266
|
+
OR title LIKE '%Playwright%'
|
|
3267
|
+
OR title LIKE '%Sample%'
|
|
3268
|
+
`).run();
|
|
3269
|
+
await db2.prepare(`
|
|
3270
|
+
DELETE FROM content_data
|
|
3271
|
+
WHERE content_id NOT IN (SELECT id FROM content)
|
|
3272
|
+
`).run();
|
|
3273
|
+
return c.json({
|
|
3274
|
+
success: true,
|
|
3275
|
+
deletedCount: result.meta?.changes || 0,
|
|
3276
|
+
message: "Test content cleaned up successfully"
|
|
3277
|
+
});
|
|
3278
|
+
} catch (error) {
|
|
3279
|
+
console.error("Content cleanup error:", error);
|
|
3280
|
+
return c.json({
|
|
3281
|
+
success: false,
|
|
3282
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
3283
|
+
}, 500);
|
|
3284
|
+
}
|
|
3285
|
+
});
|
|
3286
|
+
var test_cleanup_default = app;
|
|
3066
3287
|
|
|
3067
3288
|
// src/templates/pages/admin-content-form.template.ts
|
|
3068
3289
|
chunkYU6QFFI4_cjs.init_admin_layout_catalyst_template();
|
|
3069
3290
|
|
|
3070
3291
|
// src/templates/components/dynamic-field.template.ts
|
|
3071
3292
|
function renderDynamicField(field, options = {}) {
|
|
3072
|
-
const { value = "", errors = [], disabled = false, className = "" } = options;
|
|
3293
|
+
const { value = "", errors = [], disabled = false, className = "", pluginStatuses = {} } = options;
|
|
3073
3294
|
const opts = field.field_options || {};
|
|
3074
3295
|
const required = field.is_required ? "required" : "";
|
|
3075
3296
|
const baseClasses = `w-full rounded-lg px-3 py-2 text-sm text-zinc-950 dark:text-white bg-white dark:bg-zinc-800 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 ${className}`;
|
|
3076
3297
|
const errorClasses = errors.length > 0 ? "ring-pink-600 dark:ring-pink-500 focus:ring-pink-600 dark:focus:ring-pink-500" : "";
|
|
3077
3298
|
const fieldId = `field-${field.field_name}`;
|
|
3078
3299
|
const fieldName = field.field_name;
|
|
3300
|
+
let fallbackToTextarea = false;
|
|
3301
|
+
let fallbackWarning = "";
|
|
3302
|
+
if (field.field_type === "quill" && !pluginStatuses.quillEnabled) {
|
|
3303
|
+
fallbackToTextarea = true;
|
|
3304
|
+
fallbackWarning = "\u26A0\uFE0F Quill Editor plugin is inactive. Using textarea fallback.";
|
|
3305
|
+
} else if (field.field_type === "mdxeditor" && !pluginStatuses.mdxeditorEnabled) {
|
|
3306
|
+
fallbackToTextarea = true;
|
|
3307
|
+
fallbackWarning = "\u26A0\uFE0F MDXEditor plugin is inactive. Using textarea fallback.";
|
|
3308
|
+
} else if (field.field_type === "tinymce" && !pluginStatuses.tinymceEnabled) {
|
|
3309
|
+
fallbackToTextarea = true;
|
|
3310
|
+
fallbackWarning = "\u26A0\uFE0F TinyMCE plugin is inactive. Using textarea fallback.";
|
|
3311
|
+
}
|
|
3312
|
+
if (fallbackToTextarea) {
|
|
3313
|
+
return `
|
|
3314
|
+
<div>
|
|
3315
|
+
${fallbackWarning ? `<div class="mb-2 px-3 py-2 bg-amber-50 dark:bg-amber-900/20 text-amber-900 dark:text-amber-200 text-xs rounded-lg border border-amber-200 dark:border-amber-800">${fallbackWarning}</div>` : ""}
|
|
3316
|
+
<textarea
|
|
3317
|
+
id="${fieldId}"
|
|
3318
|
+
name="${fieldName}"
|
|
3319
|
+
rows="${opts.rows || opts.height ? Math.floor(opts.height / 25) : 10}"
|
|
3320
|
+
placeholder="${opts.placeholder || ""}"
|
|
3321
|
+
maxlength="${opts.maxLength || ""}"
|
|
3322
|
+
class="${baseClasses} ${errorClasses} resize-y"
|
|
3323
|
+
${required}
|
|
3324
|
+
${disabled ? "disabled" : ""}
|
|
3325
|
+
>${escapeHtml2(value)}</textarea>
|
|
3326
|
+
</div>
|
|
3327
|
+
`;
|
|
3328
|
+
}
|
|
3079
3329
|
let fieldHTML = "";
|
|
3080
3330
|
switch (field.field_type) {
|
|
3081
3331
|
case "text":
|
|
@@ -3998,9 +4248,9 @@ function createQuillEditorPlugin() {
|
|
|
3998
4248
|
}
|
|
3999
4249
|
createQuillEditorPlugin();
|
|
4000
4250
|
|
|
4001
|
-
// src/plugins/available/
|
|
4251
|
+
// src/plugins/available/easy-mdx/index.ts
|
|
4002
4252
|
var builder2 = PluginBuilder.create({
|
|
4003
|
-
name: "
|
|
4253
|
+
name: "easy-mdx",
|
|
4004
4254
|
version: "1.0.0",
|
|
4005
4255
|
description: "Lightweight markdown editor with live preview"
|
|
4006
4256
|
});
|
|
@@ -4216,17 +4466,25 @@ function renderContentFormPage(data) {
|
|
|
4216
4466
|
if (fieldName === "slug") return data.slug || data.data?.[fieldName] || "";
|
|
4217
4467
|
return data.data?.[fieldName] || "";
|
|
4218
4468
|
};
|
|
4469
|
+
const pluginStatuses = {
|
|
4470
|
+
quillEnabled: data.quillEnabled || false,
|
|
4471
|
+
mdxeditorEnabled: data.mdxeditorEnabled || false,
|
|
4472
|
+
tinymceEnabled: data.tinymceEnabled || false
|
|
4473
|
+
};
|
|
4219
4474
|
const coreFieldsHTML = coreFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
|
|
4220
4475
|
value: getFieldValue(field.field_name),
|
|
4221
|
-
errors: data.validationErrors?.[field.field_name] || []
|
|
4476
|
+
errors: data.validationErrors?.[field.field_name] || [],
|
|
4477
|
+
pluginStatuses
|
|
4222
4478
|
}));
|
|
4223
4479
|
const contentFieldsHTML = contentFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
|
|
4224
4480
|
value: getFieldValue(field.field_name),
|
|
4225
|
-
errors: data.validationErrors?.[field.field_name] || []
|
|
4481
|
+
errors: data.validationErrors?.[field.field_name] || [],
|
|
4482
|
+
pluginStatuses
|
|
4226
4483
|
}));
|
|
4227
4484
|
const metaFieldsHTML = metaFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
|
|
4228
4485
|
value: getFieldValue(field.field_name),
|
|
4229
|
-
errors: data.validationErrors?.[field.field_name] || []
|
|
4486
|
+
errors: data.validationErrors?.[field.field_name] || [],
|
|
4487
|
+
pluginStatuses
|
|
4230
4488
|
}));
|
|
4231
4489
|
const pageContent = `
|
|
4232
4490
|
<div class="space-y-6">
|
|
@@ -5655,9 +5913,9 @@ function escapeHtml3(text) {
|
|
|
5655
5913
|
}
|
|
5656
5914
|
|
|
5657
5915
|
// src/middleware/plugin-middleware.ts
|
|
5658
|
-
async function isPluginActive2(
|
|
5916
|
+
async function isPluginActive2(db2, pluginId) {
|
|
5659
5917
|
try {
|
|
5660
|
-
const result = await
|
|
5918
|
+
const result = await db2.prepare("SELECT status FROM plugins WHERE id = ?").bind(pluginId).first();
|
|
5661
5919
|
return result?.status === "active";
|
|
5662
5920
|
} catch (error) {
|
|
5663
5921
|
console.error(`[isPluginActive] Error checking plugin status for ${pluginId}:`, error);
|
|
@@ -5667,13 +5925,13 @@ async function isPluginActive2(db, pluginId) {
|
|
|
5667
5925
|
|
|
5668
5926
|
// src/routes/admin-content.ts
|
|
5669
5927
|
var adminContentRoutes = new hono.Hono();
|
|
5670
|
-
adminContentRoutes.use("*",
|
|
5671
|
-
async function getCollectionFields(
|
|
5672
|
-
const cache =
|
|
5928
|
+
adminContentRoutes.use("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
5929
|
+
async function getCollectionFields(db2, collectionId) {
|
|
5930
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_cjs.CACHE_CONFIGS.collection);
|
|
5673
5931
|
return cache.getOrSet(
|
|
5674
5932
|
cache.generateKey("fields", collectionId),
|
|
5675
5933
|
async () => {
|
|
5676
|
-
const collectionStmt =
|
|
5934
|
+
const collectionStmt = db2.prepare("SELECT schema FROM collections WHERE id = ?");
|
|
5677
5935
|
const collectionRow = await collectionStmt.bind(collectionId).first();
|
|
5678
5936
|
if (collectionRow && collectionRow.schema) {
|
|
5679
5937
|
try {
|
|
@@ -5704,7 +5962,7 @@ async function getCollectionFields(db, collectionId) {
|
|
|
5704
5962
|
console.error("Error parsing collection schema:", e);
|
|
5705
5963
|
}
|
|
5706
5964
|
}
|
|
5707
|
-
const stmt =
|
|
5965
|
+
const stmt = db2.prepare(`
|
|
5708
5966
|
SELECT * FROM content_fields
|
|
5709
5967
|
WHERE collection_id = ?
|
|
5710
5968
|
ORDER BY field_order ASC
|
|
@@ -5723,12 +5981,12 @@ async function getCollectionFields(db, collectionId) {
|
|
|
5723
5981
|
}
|
|
5724
5982
|
);
|
|
5725
5983
|
}
|
|
5726
|
-
async function getCollection(
|
|
5727
|
-
const cache =
|
|
5984
|
+
async function getCollection(db2, collectionId) {
|
|
5985
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_cjs.CACHE_CONFIGS.collection);
|
|
5728
5986
|
return cache.getOrSet(
|
|
5729
5987
|
cache.generateKey("collection", collectionId),
|
|
5730
5988
|
async () => {
|
|
5731
|
-
const stmt =
|
|
5989
|
+
const stmt = db2.prepare("SELECT * FROM collections WHERE id = ? AND is_active = 1");
|
|
5732
5990
|
const collection = await stmt.bind(collectionId).first();
|
|
5733
5991
|
if (!collection) return null;
|
|
5734
5992
|
return {
|
|
@@ -5745,14 +6003,14 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
5745
6003
|
try {
|
|
5746
6004
|
const user = c.get("user");
|
|
5747
6005
|
const url = new URL(c.req.url);
|
|
5748
|
-
const
|
|
6006
|
+
const db2 = c.env.DB;
|
|
5749
6007
|
const page = parseInt(url.searchParams.get("page") || "1");
|
|
5750
6008
|
const limit = parseInt(url.searchParams.get("limit") || "20");
|
|
5751
6009
|
const modelName = url.searchParams.get("model") || "all";
|
|
5752
6010
|
const status = url.searchParams.get("status") || "all";
|
|
5753
6011
|
const search = url.searchParams.get("search") || "";
|
|
5754
6012
|
const offset = (page - 1) * limit;
|
|
5755
|
-
const collectionsStmt =
|
|
6013
|
+
const collectionsStmt = db2.prepare("SELECT id, name, display_name FROM collections WHERE is_active = 1 ORDER BY display_name");
|
|
5756
6014
|
const { results: collectionsResults } = await collectionsStmt.all();
|
|
5757
6015
|
const models = (collectionsResults || []).map((row) => ({
|
|
5758
6016
|
name: row.name,
|
|
@@ -5778,7 +6036,7 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
5778
6036
|
conditions.push("c.status = 'deleted'");
|
|
5779
6037
|
}
|
|
5780
6038
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
5781
|
-
const countStmt =
|
|
6039
|
+
const countStmt = db2.prepare(`
|
|
5782
6040
|
SELECT COUNT(*) as count
|
|
5783
6041
|
FROM content c
|
|
5784
6042
|
JOIN collections col ON c.collection_id = col.id
|
|
@@ -5786,7 +6044,7 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
5786
6044
|
`);
|
|
5787
6045
|
const countResult = await countStmt.bind(...params).first();
|
|
5788
6046
|
const totalItems = countResult?.count || 0;
|
|
5789
|
-
const contentStmt =
|
|
6047
|
+
const contentStmt = db2.prepare(`
|
|
5790
6048
|
SELECT c.id, c.title, c.slug, c.status, c.created_at, c.updated_at,
|
|
5791
6049
|
col.name as collection_name, col.display_name as collection_display_name,
|
|
5792
6050
|
u.first_name, u.last_name, u.email as author_email
|
|
@@ -5887,8 +6145,8 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
5887
6145
|
const url = new URL(c.req.url);
|
|
5888
6146
|
const collectionId = url.searchParams.get("collection");
|
|
5889
6147
|
if (!collectionId) {
|
|
5890
|
-
const
|
|
5891
|
-
const collectionsStmt =
|
|
6148
|
+
const db3 = c.env.DB;
|
|
6149
|
+
const collectionsStmt = db3.prepare("SELECT id, name, display_name, description FROM collections WHERE is_active = 1 ORDER BY display_name");
|
|
5892
6150
|
const { results } = await collectionsStmt.all();
|
|
5893
6151
|
const collections = (results || []).map((row) => ({
|
|
5894
6152
|
id: row.id,
|
|
@@ -5929,8 +6187,8 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
5929
6187
|
`;
|
|
5930
6188
|
return c.html(selectionHTML);
|
|
5931
6189
|
}
|
|
5932
|
-
const
|
|
5933
|
-
const collection = await getCollection(
|
|
6190
|
+
const db2 = c.env.DB;
|
|
6191
|
+
const collection = await getCollection(db2, collectionId);
|
|
5934
6192
|
if (!collection) {
|
|
5935
6193
|
const formData2 = {
|
|
5936
6194
|
collection: { id: "", name: "", display_name: "Unknown", schema: {} },
|
|
@@ -5944,28 +6202,28 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
5944
6202
|
};
|
|
5945
6203
|
return c.html(renderContentFormPage(formData2));
|
|
5946
6204
|
}
|
|
5947
|
-
const fields = await getCollectionFields(
|
|
5948
|
-
const workflowEnabled = await isPluginActive2(
|
|
5949
|
-
const tinymceEnabled = await isPluginActive2(
|
|
6205
|
+
const fields = await getCollectionFields(db2, collectionId);
|
|
6206
|
+
const workflowEnabled = await isPluginActive2(db2, "workflow");
|
|
6207
|
+
const tinymceEnabled = await isPluginActive2(db2, "tinymce-plugin");
|
|
5950
6208
|
let tinymceSettings;
|
|
5951
6209
|
if (tinymceEnabled) {
|
|
5952
|
-
const pluginService = new
|
|
6210
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
5953
6211
|
const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
|
|
5954
6212
|
tinymceSettings = tinymcePlugin2?.settings;
|
|
5955
6213
|
}
|
|
5956
|
-
const quillEnabled = await isPluginActive2(
|
|
6214
|
+
const quillEnabled = await isPluginActive2(db2, "quill-editor");
|
|
5957
6215
|
let quillSettings;
|
|
5958
6216
|
if (quillEnabled) {
|
|
5959
|
-
const pluginService = new
|
|
6217
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
5960
6218
|
const quillPlugin = await pluginService.getPlugin("quill-editor");
|
|
5961
6219
|
quillSettings = quillPlugin?.settings;
|
|
5962
6220
|
}
|
|
5963
|
-
const mdxeditorEnabled = await isPluginActive2(
|
|
6221
|
+
const mdxeditorEnabled = await isPluginActive2(db2, "easy-mdx");
|
|
5964
6222
|
let mdxeditorSettings;
|
|
5965
6223
|
if (mdxeditorEnabled) {
|
|
5966
|
-
const pluginService = new
|
|
5967
|
-
const
|
|
5968
|
-
mdxeditorSettings =
|
|
6224
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
6225
|
+
const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
|
|
6226
|
+
mdxeditorSettings = mdxeditorPlugin?.settings;
|
|
5969
6227
|
}
|
|
5970
6228
|
console.log("[Content Form /new] Editor plugins status:", {
|
|
5971
6229
|
tinymce: tinymceEnabled,
|
|
@@ -6010,14 +6268,14 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
6010
6268
|
try {
|
|
6011
6269
|
const id = c.req.param("id");
|
|
6012
6270
|
const user = c.get("user");
|
|
6013
|
-
const
|
|
6271
|
+
const db2 = c.env.DB;
|
|
6014
6272
|
const url = new URL(c.req.url);
|
|
6015
6273
|
const referrerParams = url.searchParams.get("ref") || "";
|
|
6016
|
-
const cache =
|
|
6274
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_cjs.CACHE_CONFIGS.content);
|
|
6017
6275
|
const content = await cache.getOrSet(
|
|
6018
6276
|
cache.generateKey("content", id),
|
|
6019
6277
|
async () => {
|
|
6020
|
-
const contentStmt =
|
|
6278
|
+
const contentStmt = db2.prepare(`
|
|
6021
6279
|
SELECT c.*, col.id as collection_id, col.name as collection_name,
|
|
6022
6280
|
col.display_name as collection_display_name, col.description as collection_description,
|
|
6023
6281
|
col.schema as collection_schema
|
|
@@ -6048,29 +6306,29 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
6048
6306
|
description: content.collection_description,
|
|
6049
6307
|
schema: content.collection_schema ? JSON.parse(content.collection_schema) : {}
|
|
6050
6308
|
};
|
|
6051
|
-
const fields = await getCollectionFields(
|
|
6309
|
+
const fields = await getCollectionFields(db2, content.collection_id);
|
|
6052
6310
|
const contentData = content.data ? JSON.parse(content.data) : {};
|
|
6053
|
-
const workflowEnabled = await isPluginActive2(
|
|
6054
|
-
const tinymceEnabled = await isPluginActive2(
|
|
6311
|
+
const workflowEnabled = await isPluginActive2(db2, "workflow");
|
|
6312
|
+
const tinymceEnabled = await isPluginActive2(db2, "tinymce-plugin");
|
|
6055
6313
|
let tinymceSettings;
|
|
6056
6314
|
if (tinymceEnabled) {
|
|
6057
|
-
const pluginService = new
|
|
6315
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
6058
6316
|
const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
|
|
6059
6317
|
tinymceSettings = tinymcePlugin2?.settings;
|
|
6060
6318
|
}
|
|
6061
|
-
const quillEnabled = await isPluginActive2(
|
|
6319
|
+
const quillEnabled = await isPluginActive2(db2, "quill-editor");
|
|
6062
6320
|
let quillSettings;
|
|
6063
6321
|
if (quillEnabled) {
|
|
6064
|
-
const pluginService = new
|
|
6322
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
6065
6323
|
const quillPlugin = await pluginService.getPlugin("quill-editor");
|
|
6066
6324
|
quillSettings = quillPlugin?.settings;
|
|
6067
6325
|
}
|
|
6068
|
-
const mdxeditorEnabled = await isPluginActive2(
|
|
6326
|
+
const mdxeditorEnabled = await isPluginActive2(db2, "easy-mdx");
|
|
6069
6327
|
let mdxeditorSettings;
|
|
6070
6328
|
if (mdxeditorEnabled) {
|
|
6071
|
-
const pluginService = new
|
|
6072
|
-
const
|
|
6073
|
-
mdxeditorSettings =
|
|
6329
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
6330
|
+
const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
|
|
6331
|
+
mdxeditorSettings = mdxeditorPlugin?.settings;
|
|
6074
6332
|
}
|
|
6075
6333
|
const formData = {
|
|
6076
6334
|
id: content.id,
|
|
@@ -6130,8 +6388,8 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6130
6388
|
</div>
|
|
6131
6389
|
`);
|
|
6132
6390
|
}
|
|
6133
|
-
const
|
|
6134
|
-
const collection = await getCollection(
|
|
6391
|
+
const db2 = c.env.DB;
|
|
6392
|
+
const collection = await getCollection(db2, collectionId);
|
|
6135
6393
|
if (!collection) {
|
|
6136
6394
|
return c.html(html.html`
|
|
6137
6395
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -6139,7 +6397,7 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6139
6397
|
</div>
|
|
6140
6398
|
`);
|
|
6141
6399
|
}
|
|
6142
|
-
const fields = await getCollectionFields(
|
|
6400
|
+
const fields = await getCollectionFields(db2, collectionId);
|
|
6143
6401
|
const data = {};
|
|
6144
6402
|
const errors = {};
|
|
6145
6403
|
for (const field of fields) {
|
|
@@ -6197,13 +6455,13 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6197
6455
|
const scheduledUnpublishAt = formData.get("scheduled_unpublish_at");
|
|
6198
6456
|
const contentId = crypto.randomUUID();
|
|
6199
6457
|
const now = Date.now();
|
|
6200
|
-
const insertStmt =
|
|
6458
|
+
const insertStmt = db2.prepare(`
|
|
6201
6459
|
INSERT INTO content (
|
|
6202
6460
|
id, collection_id, slug, title, data, status,
|
|
6203
6461
|
scheduled_publish_at, scheduled_unpublish_at,
|
|
6204
|
-
meta_title, meta_description, author_id, created_at, updated_at
|
|
6462
|
+
meta_title, meta_description, author_id, created_by, created_at, updated_at
|
|
6205
6463
|
)
|
|
6206
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
6464
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
6207
6465
|
`);
|
|
6208
6466
|
await insertStmt.bind(
|
|
6209
6467
|
contentId,
|
|
@@ -6217,12 +6475,13 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6217
6475
|
data.meta_title || null,
|
|
6218
6476
|
data.meta_description || null,
|
|
6219
6477
|
user?.userId || "unknown",
|
|
6478
|
+
user?.userId || "unknown",
|
|
6220
6479
|
now,
|
|
6221
6480
|
now
|
|
6222
6481
|
).run();
|
|
6223
|
-
const cache =
|
|
6482
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_cjs.CACHE_CONFIGS.content);
|
|
6224
6483
|
await cache.invalidate(`content:list:${collectionId}:*`);
|
|
6225
|
-
const versionStmt =
|
|
6484
|
+
const versionStmt = db2.prepare(`
|
|
6226
6485
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
6227
6486
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
6228
6487
|
`);
|
|
@@ -6234,7 +6493,7 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6234
6493
|
user?.userId || "unknown",
|
|
6235
6494
|
now
|
|
6236
6495
|
).run();
|
|
6237
|
-
const workflowStmt =
|
|
6496
|
+
const workflowStmt = db2.prepare(`
|
|
6238
6497
|
INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, created_at)
|
|
6239
6498
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
6240
6499
|
`);
|
|
@@ -6272,8 +6531,8 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6272
6531
|
const user = c.get("user");
|
|
6273
6532
|
const formData = await c.req.formData();
|
|
6274
6533
|
const action = formData.get("action");
|
|
6275
|
-
const
|
|
6276
|
-
const contentStmt =
|
|
6534
|
+
const db2 = c.env.DB;
|
|
6535
|
+
const contentStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
|
|
6277
6536
|
const existingContent = await contentStmt.bind(id).first();
|
|
6278
6537
|
if (!existingContent) {
|
|
6279
6538
|
return c.html(html.html`
|
|
@@ -6282,7 +6541,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6282
6541
|
</div>
|
|
6283
6542
|
`);
|
|
6284
6543
|
}
|
|
6285
|
-
const collection = await getCollection(
|
|
6544
|
+
const collection = await getCollection(db2, existingContent.collection_id);
|
|
6286
6545
|
if (!collection) {
|
|
6287
6546
|
return c.html(html.html`
|
|
6288
6547
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -6290,7 +6549,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6290
6549
|
</div>
|
|
6291
6550
|
`);
|
|
6292
6551
|
}
|
|
6293
|
-
const fields = await getCollectionFields(
|
|
6552
|
+
const fields = await getCollectionFields(db2, existingContent.collection_id);
|
|
6294
6553
|
const data = {};
|
|
6295
6554
|
const errors = {};
|
|
6296
6555
|
for (const field of fields) {
|
|
@@ -6349,7 +6608,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6349
6608
|
const scheduledPublishAt = formData.get("scheduled_publish_at");
|
|
6350
6609
|
const scheduledUnpublishAt = formData.get("scheduled_unpublish_at");
|
|
6351
6610
|
const now = Date.now();
|
|
6352
|
-
const updateStmt =
|
|
6611
|
+
const updateStmt = db2.prepare(`
|
|
6353
6612
|
UPDATE content SET
|
|
6354
6613
|
slug = ?, title = ?, data = ?, status = ?,
|
|
6355
6614
|
scheduled_publish_at = ?, scheduled_unpublish_at = ?,
|
|
@@ -6368,15 +6627,15 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6368
6627
|
now,
|
|
6369
6628
|
id
|
|
6370
6629
|
).run();
|
|
6371
|
-
const cache =
|
|
6630
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_cjs.CACHE_CONFIGS.content);
|
|
6372
6631
|
await cache.delete(cache.generateKey("content", id));
|
|
6373
6632
|
await cache.invalidate(`content:list:${existingContent.collection_id}:*`);
|
|
6374
6633
|
const existingData = JSON.parse(existingContent.data || "{}");
|
|
6375
6634
|
if (JSON.stringify(existingData) !== JSON.stringify(data)) {
|
|
6376
|
-
const versionCountStmt =
|
|
6635
|
+
const versionCountStmt = db2.prepare("SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?");
|
|
6377
6636
|
const versionResult = await versionCountStmt.bind(id).first();
|
|
6378
6637
|
const nextVersion = (versionResult?.max_version || 0) + 1;
|
|
6379
|
-
const versionStmt =
|
|
6638
|
+
const versionStmt = db2.prepare(`
|
|
6380
6639
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
6381
6640
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
6382
6641
|
`);
|
|
@@ -6390,7 +6649,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6390
6649
|
).run();
|
|
6391
6650
|
}
|
|
6392
6651
|
if (status !== existingContent.status) {
|
|
6393
|
-
const workflowStmt =
|
|
6652
|
+
const workflowStmt = db2.prepare(`
|
|
6394
6653
|
INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, created_at)
|
|
6395
6654
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
6396
6655
|
`);
|
|
@@ -6427,12 +6686,12 @@ adminContentRoutes.post("/preview", async (c) => {
|
|
|
6427
6686
|
try {
|
|
6428
6687
|
const formData = await c.req.formData();
|
|
6429
6688
|
const collectionId = formData.get("collection_id");
|
|
6430
|
-
const
|
|
6431
|
-
const collection = await getCollection(
|
|
6689
|
+
const db2 = c.env.DB;
|
|
6690
|
+
const collection = await getCollection(db2, collectionId);
|
|
6432
6691
|
if (!collection) {
|
|
6433
6692
|
return c.html("<p>Collection not found</p>");
|
|
6434
6693
|
}
|
|
6435
|
-
const fields = await getCollectionFields(
|
|
6694
|
+
const fields = await getCollectionFields(db2, collectionId);
|
|
6436
6695
|
const data = {};
|
|
6437
6696
|
for (const field of fields) {
|
|
6438
6697
|
const value = formData.get(field.field_name);
|
|
@@ -6506,8 +6765,8 @@ adminContentRoutes.post("/duplicate", async (c) => {
|
|
|
6506
6765
|
if (!originalId) {
|
|
6507
6766
|
return c.json({ success: false, error: "Content ID required" });
|
|
6508
6767
|
}
|
|
6509
|
-
const
|
|
6510
|
-
const contentStmt =
|
|
6768
|
+
const db2 = c.env.DB;
|
|
6769
|
+
const contentStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
|
|
6511
6770
|
const original = await contentStmt.bind(originalId).first();
|
|
6512
6771
|
if (!original) {
|
|
6513
6772
|
return c.json({ success: false, error: "Content not found" });
|
|
@@ -6516,7 +6775,7 @@ adminContentRoutes.post("/duplicate", async (c) => {
|
|
|
6516
6775
|
const now = Date.now();
|
|
6517
6776
|
const originalData = JSON.parse(original.data || "{}");
|
|
6518
6777
|
originalData.title = `${originalData.title || "Untitled"} (Copy)`;
|
|
6519
|
-
const insertStmt =
|
|
6778
|
+
const insertStmt = db2.prepare(`
|
|
6520
6779
|
INSERT INTO content (
|
|
6521
6780
|
id, collection_id, slug, title, data, status,
|
|
6522
6781
|
author_id, created_at, updated_at
|
|
@@ -6639,11 +6898,11 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
6639
6898
|
if (!action || !ids || ids.length === 0) {
|
|
6640
6899
|
return c.json({ success: false, error: "Action and IDs required" });
|
|
6641
6900
|
}
|
|
6642
|
-
const
|
|
6901
|
+
const db2 = c.env.DB;
|
|
6643
6902
|
const now = Date.now();
|
|
6644
6903
|
if (action === "delete") {
|
|
6645
6904
|
const placeholders = ids.map(() => "?").join(",");
|
|
6646
|
-
const stmt =
|
|
6905
|
+
const stmt = db2.prepare(`
|
|
6647
6906
|
UPDATE content
|
|
6648
6907
|
SET status = 'deleted', updated_at = ?
|
|
6649
6908
|
WHERE id IN (${placeholders})
|
|
@@ -6652,7 +6911,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
6652
6911
|
} else if (action === "publish" || action === "draft") {
|
|
6653
6912
|
const placeholders = ids.map(() => "?").join(",");
|
|
6654
6913
|
const publishedAt = action === "publish" ? now : null;
|
|
6655
|
-
const stmt =
|
|
6914
|
+
const stmt = db2.prepare(`
|
|
6656
6915
|
UPDATE content
|
|
6657
6916
|
SET status = ?, published_at = ?, updated_at = ?
|
|
6658
6917
|
WHERE id IN (${placeholders})
|
|
@@ -6661,7 +6920,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
6661
6920
|
} else {
|
|
6662
6921
|
return c.json({ success: false, error: "Invalid action" });
|
|
6663
6922
|
}
|
|
6664
|
-
const cache =
|
|
6923
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_cjs.CACHE_CONFIGS.content);
|
|
6665
6924
|
for (const contentId of ids) {
|
|
6666
6925
|
await cache.delete(cache.generateKey("content", contentId));
|
|
6667
6926
|
}
|
|
@@ -6675,21 +6934,21 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
6675
6934
|
adminContentRoutes.delete("/:id", async (c) => {
|
|
6676
6935
|
try {
|
|
6677
6936
|
const id = c.req.param("id");
|
|
6678
|
-
const
|
|
6937
|
+
const db2 = c.env.DB;
|
|
6679
6938
|
const user = c.get("user");
|
|
6680
|
-
const contentStmt =
|
|
6939
|
+
const contentStmt = db2.prepare("SELECT id, title FROM content WHERE id = ?");
|
|
6681
6940
|
const content = await contentStmt.bind(id).first();
|
|
6682
6941
|
if (!content) {
|
|
6683
6942
|
return c.json({ success: false, error: "Content not found" }, 404);
|
|
6684
6943
|
}
|
|
6685
6944
|
const now = Date.now();
|
|
6686
|
-
const deleteStmt =
|
|
6945
|
+
const deleteStmt = db2.prepare(`
|
|
6687
6946
|
UPDATE content
|
|
6688
6947
|
SET status = 'deleted', updated_at = ?
|
|
6689
6948
|
WHERE id = ?
|
|
6690
6949
|
`);
|
|
6691
6950
|
await deleteStmt.bind(now, id).run();
|
|
6692
|
-
const cache =
|
|
6951
|
+
const cache = chunk3F4LF7LW_cjs.getCacheService(chunk3F4LF7LW_cjs.CACHE_CONFIGS.content);
|
|
6693
6952
|
await cache.delete(cache.generateKey("content", id));
|
|
6694
6953
|
await cache.invalidate("content:list:*");
|
|
6695
6954
|
return c.html(`
|
|
@@ -6712,13 +6971,13 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
6712
6971
|
adminContentRoutes.get("/:id/versions", async (c) => {
|
|
6713
6972
|
try {
|
|
6714
6973
|
const id = c.req.param("id");
|
|
6715
|
-
const
|
|
6716
|
-
const contentStmt =
|
|
6974
|
+
const db2 = c.env.DB;
|
|
6975
|
+
const contentStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
|
|
6717
6976
|
const content = await contentStmt.bind(id).first();
|
|
6718
6977
|
if (!content) {
|
|
6719
6978
|
return c.html("<p>Content not found</p>");
|
|
6720
6979
|
}
|
|
6721
|
-
const versionsStmt =
|
|
6980
|
+
const versionsStmt = db2.prepare(`
|
|
6722
6981
|
SELECT cv.*, u.first_name, u.last_name, u.email
|
|
6723
6982
|
FROM content_versions cv
|
|
6724
6983
|
LEFT JOIN users u ON cv.author_id = u.id
|
|
@@ -6755,8 +7014,8 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
|
|
|
6755
7014
|
const id = c.req.param("id");
|
|
6756
7015
|
const version = parseInt(c.req.param("version"));
|
|
6757
7016
|
const user = c.get("user");
|
|
6758
|
-
const
|
|
6759
|
-
const versionStmt =
|
|
7017
|
+
const db2 = c.env.DB;
|
|
7018
|
+
const versionStmt = db2.prepare(`
|
|
6760
7019
|
SELECT * FROM content_versions
|
|
6761
7020
|
WHERE content_id = ? AND version = ?
|
|
6762
7021
|
`);
|
|
@@ -6764,14 +7023,14 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
|
|
|
6764
7023
|
if (!versionData) {
|
|
6765
7024
|
return c.json({ success: false, error: "Version not found" });
|
|
6766
7025
|
}
|
|
6767
|
-
const contentStmt =
|
|
7026
|
+
const contentStmt = db2.prepare("SELECT * FROM content WHERE id = ?");
|
|
6768
7027
|
const currentContent = await contentStmt.bind(id).first();
|
|
6769
7028
|
if (!currentContent) {
|
|
6770
7029
|
return c.json({ success: false, error: "Content not found" });
|
|
6771
7030
|
}
|
|
6772
7031
|
const restoredData = JSON.parse(versionData.data);
|
|
6773
7032
|
const now = Date.now();
|
|
6774
|
-
const updateStmt =
|
|
7033
|
+
const updateStmt = db2.prepare(`
|
|
6775
7034
|
UPDATE content SET
|
|
6776
7035
|
title = ?, data = ?, updated_at = ?
|
|
6777
7036
|
WHERE id = ?
|
|
@@ -6782,10 +7041,10 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
|
|
|
6782
7041
|
now,
|
|
6783
7042
|
id
|
|
6784
7043
|
).run();
|
|
6785
|
-
const nextVersionStmt =
|
|
7044
|
+
const nextVersionStmt = db2.prepare("SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?");
|
|
6786
7045
|
const nextVersionResult = await nextVersionStmt.bind(id).first();
|
|
6787
7046
|
const nextVersion = (nextVersionResult?.max_version || 0) + 1;
|
|
6788
|
-
const newVersionStmt =
|
|
7047
|
+
const newVersionStmt = db2.prepare(`
|
|
6789
7048
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
6790
7049
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
6791
7050
|
`);
|
|
@@ -6797,7 +7056,7 @@ adminContentRoutes.post("/:id/restore/:version", async (c) => {
|
|
|
6797
7056
|
user?.userId || "unknown",
|
|
6798
7057
|
now
|
|
6799
7058
|
).run();
|
|
6800
|
-
const workflowStmt =
|
|
7059
|
+
const workflowStmt = db2.prepare(`
|
|
6801
7060
|
INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, comment, created_at)
|
|
6802
7061
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
6803
7062
|
`);
|
|
@@ -6821,8 +7080,8 @@ adminContentRoutes.get("/:id/version/:version/preview", async (c) => {
|
|
|
6821
7080
|
try {
|
|
6822
7081
|
const id = c.req.param("id");
|
|
6823
7082
|
const version = parseInt(c.req.param("version"));
|
|
6824
|
-
const
|
|
6825
|
-
const versionStmt =
|
|
7083
|
+
const db2 = c.env.DB;
|
|
7084
|
+
const versionStmt = db2.prepare(`
|
|
6826
7085
|
SELECT cv.*, c.collection_id, col.display_name as collection_name
|
|
6827
7086
|
FROM content_versions cv
|
|
6828
7087
|
JOIN content c ON cv.content_id = c.id
|
|
@@ -7733,7 +7992,7 @@ function renderUserEditPage(data) {
|
|
|
7733
7992
|
<input
|
|
7734
7993
|
type="text"
|
|
7735
7994
|
name="first_name"
|
|
7736
|
-
value="${
|
|
7995
|
+
value="${chunk2HRF65VF_cjs.escapeHtml(data.userToEdit.firstName || "")}"
|
|
7737
7996
|
required
|
|
7738
7997
|
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"
|
|
7739
7998
|
/>
|
|
@@ -7744,7 +8003,7 @@ function renderUserEditPage(data) {
|
|
|
7744
8003
|
<input
|
|
7745
8004
|
type="text"
|
|
7746
8005
|
name="last_name"
|
|
7747
|
-
value="${
|
|
8006
|
+
value="${chunk2HRF65VF_cjs.escapeHtml(data.userToEdit.lastName || "")}"
|
|
7748
8007
|
required
|
|
7749
8008
|
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"
|
|
7750
8009
|
/>
|
|
@@ -7755,7 +8014,7 @@ function renderUserEditPage(data) {
|
|
|
7755
8014
|
<input
|
|
7756
8015
|
type="text"
|
|
7757
8016
|
name="username"
|
|
7758
|
-
value="${
|
|
8017
|
+
value="${chunk2HRF65VF_cjs.escapeHtml(data.userToEdit.username || "")}"
|
|
7759
8018
|
required
|
|
7760
8019
|
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"
|
|
7761
8020
|
/>
|
|
@@ -7766,7 +8025,7 @@ function renderUserEditPage(data) {
|
|
|
7766
8025
|
<input
|
|
7767
8026
|
type="email"
|
|
7768
8027
|
name="email"
|
|
7769
|
-
value="${
|
|
8028
|
+
value="${chunk2HRF65VF_cjs.escapeHtml(data.userToEdit.email || "")}"
|
|
7770
8029
|
required
|
|
7771
8030
|
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"
|
|
7772
8031
|
/>
|
|
@@ -7777,7 +8036,7 @@ function renderUserEditPage(data) {
|
|
|
7777
8036
|
<input
|
|
7778
8037
|
type="tel"
|
|
7779
8038
|
name="phone"
|
|
7780
|
-
value="${
|
|
8039
|
+
value="${chunk2HRF65VF_cjs.escapeHtml(data.userToEdit.phone || "")}"
|
|
7781
8040
|
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"
|
|
7782
8041
|
/>
|
|
7783
8042
|
</div>
|
|
@@ -7791,7 +8050,7 @@ function renderUserEditPage(data) {
|
|
|
7791
8050
|
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"
|
|
7792
8051
|
>
|
|
7793
8052
|
${data.roles.map((role) => `
|
|
7794
|
-
<option value="${
|
|
8053
|
+
<option value="${chunk2HRF65VF_cjs.escapeHtml(role.value)}" ${data.userToEdit.role === role.value ? "selected" : ""}>${chunk2HRF65VF_cjs.escapeHtml(role.label)}</option>
|
|
7795
8054
|
`).join("")}
|
|
7796
8055
|
</select>
|
|
7797
8056
|
<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">
|
|
@@ -7807,7 +8066,7 @@ function renderUserEditPage(data) {
|
|
|
7807
8066
|
name="bio"
|
|
7808
8067
|
rows="3"
|
|
7809
8068
|
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"
|
|
7810
|
-
>${
|
|
8069
|
+
>${chunk2HRF65VF_cjs.escapeHtml(data.userToEdit.bio || "")}</textarea>
|
|
7811
8070
|
</div>
|
|
7812
8071
|
</div>
|
|
7813
8072
|
|
|
@@ -8707,7 +8966,7 @@ function renderUsersListPage(data) {
|
|
|
8707
8966
|
|
|
8708
8967
|
// src/routes/admin-users.ts
|
|
8709
8968
|
var userRoutes = new hono.Hono();
|
|
8710
|
-
userRoutes.use("*",
|
|
8969
|
+
userRoutes.use("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
8711
8970
|
userRoutes.get("/", (c) => {
|
|
8712
8971
|
return c.redirect("/admin/dashboard");
|
|
8713
8972
|
});
|
|
@@ -8743,9 +9002,9 @@ var ROLES = [
|
|
|
8743
9002
|
];
|
|
8744
9003
|
userRoutes.get("/profile", async (c) => {
|
|
8745
9004
|
const user = c.get("user");
|
|
8746
|
-
const
|
|
9005
|
+
const db2 = c.env.DB;
|
|
8747
9006
|
try {
|
|
8748
|
-
const userStmt =
|
|
9007
|
+
const userStmt = db2.prepare(`
|
|
8749
9008
|
SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
|
|
8750
9009
|
timezone, language, theme, email_notifications, two_factor_enabled,
|
|
8751
9010
|
role, created_at, last_login_at
|
|
@@ -8803,15 +9062,15 @@ userRoutes.get("/profile", async (c) => {
|
|
|
8803
9062
|
});
|
|
8804
9063
|
userRoutes.put("/profile", async (c) => {
|
|
8805
9064
|
const user = c.get("user");
|
|
8806
|
-
const
|
|
9065
|
+
const db2 = c.env.DB;
|
|
8807
9066
|
try {
|
|
8808
9067
|
const formData = await c.req.formData();
|
|
8809
|
-
const firstName =
|
|
8810
|
-
const lastName =
|
|
8811
|
-
const username =
|
|
9068
|
+
const firstName = chunk2HRF65VF_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9069
|
+
const lastName = chunk2HRF65VF_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9070
|
+
const username = chunk2HRF65VF_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
8812
9071
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
8813
|
-
const phone =
|
|
8814
|
-
const bio =
|
|
9072
|
+
const phone = chunk2HRF65VF_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9073
|
+
const bio = chunk2HRF65VF_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
8815
9074
|
const timezone = formData.get("timezone")?.toString() || "UTC";
|
|
8816
9075
|
const language = formData.get("language")?.toString() || "en";
|
|
8817
9076
|
const emailNotifications = formData.get("email_notifications") === "1";
|
|
@@ -8830,7 +9089,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
8830
9089
|
dismissible: true
|
|
8831
9090
|
}));
|
|
8832
9091
|
}
|
|
8833
|
-
const checkStmt =
|
|
9092
|
+
const checkStmt = db2.prepare(`
|
|
8834
9093
|
SELECT id FROM users
|
|
8835
9094
|
WHERE (username = ? OR email = ?) AND id != ? AND is_active = 1
|
|
8836
9095
|
`);
|
|
@@ -8842,7 +9101,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
8842
9101
|
dismissible: true
|
|
8843
9102
|
}));
|
|
8844
9103
|
}
|
|
8845
|
-
const updateStmt =
|
|
9104
|
+
const updateStmt = db2.prepare(`
|
|
8846
9105
|
UPDATE users SET
|
|
8847
9106
|
first_name = ?, last_name = ?, username = ?, email = ?,
|
|
8848
9107
|
phone = ?, bio = ?, timezone = ?, language = ?,
|
|
@@ -8862,8 +9121,8 @@ userRoutes.put("/profile", async (c) => {
|
|
|
8862
9121
|
Date.now(),
|
|
8863
9122
|
user.userId
|
|
8864
9123
|
).run();
|
|
8865
|
-
await
|
|
8866
|
-
|
|
9124
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9125
|
+
db2,
|
|
8867
9126
|
user.userId,
|
|
8868
9127
|
"profile.update",
|
|
8869
9128
|
"users",
|
|
@@ -8888,7 +9147,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
8888
9147
|
});
|
|
8889
9148
|
userRoutes.post("/profile/avatar", async (c) => {
|
|
8890
9149
|
const user = c.get("user");
|
|
8891
|
-
const
|
|
9150
|
+
const db2 = c.env.DB;
|
|
8892
9151
|
try {
|
|
8893
9152
|
const formData = await c.req.formData();
|
|
8894
9153
|
const avatarFile = formData.get("avatar");
|
|
@@ -8916,17 +9175,17 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
8916
9175
|
}));
|
|
8917
9176
|
}
|
|
8918
9177
|
const avatarUrl = `/uploads/avatars/${user.userId}-${Date.now()}.${avatarFile.type.split("/")[1]}`;
|
|
8919
|
-
const updateStmt =
|
|
9178
|
+
const updateStmt = db2.prepare(`
|
|
8920
9179
|
UPDATE users SET avatar_url = ?, updated_at = ?
|
|
8921
9180
|
WHERE id = ?
|
|
8922
9181
|
`);
|
|
8923
9182
|
await updateStmt.bind(avatarUrl, Date.now(), user.userId).run();
|
|
8924
|
-
const userStmt =
|
|
9183
|
+
const userStmt = db2.prepare(`
|
|
8925
9184
|
SELECT first_name, last_name FROM users WHERE id = ?
|
|
8926
9185
|
`);
|
|
8927
9186
|
const userData = await userStmt.bind(user.userId).first();
|
|
8928
|
-
await
|
|
8929
|
-
|
|
9187
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9188
|
+
db2,
|
|
8930
9189
|
user.userId,
|
|
8931
9190
|
"profile.avatar_update",
|
|
8932
9191
|
"users",
|
|
@@ -8958,7 +9217,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
8958
9217
|
});
|
|
8959
9218
|
userRoutes.post("/profile/password", async (c) => {
|
|
8960
9219
|
const user = c.get("user");
|
|
8961
|
-
const
|
|
9220
|
+
const db2 = c.env.DB;
|
|
8962
9221
|
try {
|
|
8963
9222
|
const formData = await c.req.formData();
|
|
8964
9223
|
const currentPassword = formData.get("current_password")?.toString() || "";
|
|
@@ -8985,7 +9244,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
8985
9244
|
dismissible: true
|
|
8986
9245
|
}));
|
|
8987
9246
|
}
|
|
8988
|
-
const userStmt =
|
|
9247
|
+
const userStmt = db2.prepare(`
|
|
8989
9248
|
SELECT password_hash FROM users WHERE id = ? AND is_active = 1
|
|
8990
9249
|
`);
|
|
8991
9250
|
const userData = await userStmt.bind(user.userId).first();
|
|
@@ -8996,7 +9255,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
8996
9255
|
dismissible: true
|
|
8997
9256
|
}));
|
|
8998
9257
|
}
|
|
8999
|
-
const validPassword = await
|
|
9258
|
+
const validPassword = await chunkF4IGVB2V_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
|
|
9000
9259
|
if (!validPassword) {
|
|
9001
9260
|
return c.html(renderAlert2({
|
|
9002
9261
|
type: "error",
|
|
@@ -9004,8 +9263,8 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9004
9263
|
dismissible: true
|
|
9005
9264
|
}));
|
|
9006
9265
|
}
|
|
9007
|
-
const newPasswordHash = await
|
|
9008
|
-
const historyStmt =
|
|
9266
|
+
const newPasswordHash = await chunkF4IGVB2V_cjs.AuthManager.hashPassword(newPassword);
|
|
9267
|
+
const historyStmt = db2.prepare(`
|
|
9009
9268
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
9010
9269
|
VALUES (?, ?, ?, ?)
|
|
9011
9270
|
`);
|
|
@@ -9015,13 +9274,13 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9015
9274
|
userData.password_hash,
|
|
9016
9275
|
Date.now()
|
|
9017
9276
|
).run();
|
|
9018
|
-
const updateStmt =
|
|
9277
|
+
const updateStmt = db2.prepare(`
|
|
9019
9278
|
UPDATE users SET password_hash = ?, updated_at = ?
|
|
9020
9279
|
WHERE id = ?
|
|
9021
9280
|
`);
|
|
9022
9281
|
await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
|
|
9023
|
-
await
|
|
9024
|
-
|
|
9282
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9283
|
+
db2,
|
|
9025
9284
|
user.userId,
|
|
9026
9285
|
"profile.password_change",
|
|
9027
9286
|
"users",
|
|
@@ -9045,7 +9304,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9045
9304
|
}
|
|
9046
9305
|
});
|
|
9047
9306
|
userRoutes.get("/users", async (c) => {
|
|
9048
|
-
const
|
|
9307
|
+
const db2 = c.env.DB;
|
|
9049
9308
|
const user = c.get("user");
|
|
9050
9309
|
try {
|
|
9051
9310
|
const page = parseInt(c.req.query("page") || "1");
|
|
@@ -9072,7 +9331,7 @@ userRoutes.get("/users", async (c) => {
|
|
|
9072
9331
|
whereClause += " AND u.role = ?";
|
|
9073
9332
|
params.push(roleFilter);
|
|
9074
9333
|
}
|
|
9075
|
-
const usersStmt =
|
|
9334
|
+
const usersStmt = db2.prepare(`
|
|
9076
9335
|
SELECT u.id, u.email, u.username, u.first_name, u.last_name,
|
|
9077
9336
|
u.role, u.avatar_url, u.created_at, u.last_login_at, u.updated_at,
|
|
9078
9337
|
u.email_verified, u.two_factor_enabled, u.is_active
|
|
@@ -9082,13 +9341,13 @@ userRoutes.get("/users", async (c) => {
|
|
|
9082
9341
|
LIMIT ? OFFSET ?
|
|
9083
9342
|
`);
|
|
9084
9343
|
const { results: usersData } = await usersStmt.bind(...params, limit, offset).all();
|
|
9085
|
-
const countStmt =
|
|
9344
|
+
const countStmt = db2.prepare(`
|
|
9086
9345
|
SELECT COUNT(*) as total FROM users u ${whereClause}
|
|
9087
9346
|
`);
|
|
9088
9347
|
const countResult = await countStmt.bind(...params).first();
|
|
9089
9348
|
const totalUsers = countResult?.total || 0;
|
|
9090
|
-
await
|
|
9091
|
-
|
|
9349
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9350
|
+
db2,
|
|
9092
9351
|
user.userId,
|
|
9093
9352
|
"users.list_view",
|
|
9094
9353
|
"users",
|
|
@@ -9185,16 +9444,16 @@ userRoutes.get("/users/new", async (c) => {
|
|
|
9185
9444
|
}
|
|
9186
9445
|
});
|
|
9187
9446
|
userRoutes.post("/users/new", async (c) => {
|
|
9188
|
-
const
|
|
9447
|
+
const db2 = c.env.DB;
|
|
9189
9448
|
const user = c.get("user");
|
|
9190
9449
|
try {
|
|
9191
9450
|
const formData = await c.req.formData();
|
|
9192
|
-
const firstName =
|
|
9193
|
-
const lastName =
|
|
9194
|
-
const username =
|
|
9451
|
+
const firstName = chunk2HRF65VF_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9452
|
+
const lastName = chunk2HRF65VF_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9453
|
+
const username = chunk2HRF65VF_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
9195
9454
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9196
|
-
const phone =
|
|
9197
|
-
const bio =
|
|
9455
|
+
const phone = chunk2HRF65VF_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9456
|
+
const bio = chunk2HRF65VF_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
9198
9457
|
const role = formData.get("role")?.toString() || "viewer";
|
|
9199
9458
|
const password = formData.get("password")?.toString() || "";
|
|
9200
9459
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
@@ -9229,7 +9488,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9229
9488
|
dismissible: true
|
|
9230
9489
|
}));
|
|
9231
9490
|
}
|
|
9232
|
-
const checkStmt =
|
|
9491
|
+
const checkStmt = db2.prepare(`
|
|
9233
9492
|
SELECT id FROM users
|
|
9234
9493
|
WHERE username = ? OR email = ?
|
|
9235
9494
|
`);
|
|
@@ -9241,9 +9500,9 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9241
9500
|
dismissible: true
|
|
9242
9501
|
}));
|
|
9243
9502
|
}
|
|
9244
|
-
const passwordHash = await
|
|
9503
|
+
const passwordHash = await chunkF4IGVB2V_cjs.AuthManager.hashPassword(password);
|
|
9245
9504
|
const userId = crypto.randomUUID();
|
|
9246
|
-
const createStmt =
|
|
9505
|
+
const createStmt = db2.prepare(`
|
|
9247
9506
|
INSERT INTO users (
|
|
9248
9507
|
id, email, username, first_name, last_name, phone, bio,
|
|
9249
9508
|
password_hash, role, is_active, email_verified, created_at, updated_at
|
|
@@ -9264,8 +9523,8 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9264
9523
|
Date.now(),
|
|
9265
9524
|
Date.now()
|
|
9266
9525
|
).run();
|
|
9267
|
-
await
|
|
9268
|
-
|
|
9526
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9527
|
+
db2,
|
|
9269
9528
|
user.userId,
|
|
9270
9529
|
"user!.create",
|
|
9271
9530
|
"users",
|
|
@@ -9288,11 +9547,11 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
9288
9547
|
if (c.req.path.endsWith("/edit")) {
|
|
9289
9548
|
return c.notFound();
|
|
9290
9549
|
}
|
|
9291
|
-
const
|
|
9550
|
+
const db2 = c.env.DB;
|
|
9292
9551
|
const user = c.get("user");
|
|
9293
9552
|
const userId = c.req.param("id");
|
|
9294
9553
|
try {
|
|
9295
|
-
const userStmt =
|
|
9554
|
+
const userStmt = db2.prepare(`
|
|
9296
9555
|
SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
|
|
9297
9556
|
role, is_active, email_verified, two_factor_enabled, created_at, last_login_at
|
|
9298
9557
|
FROM users
|
|
@@ -9302,8 +9561,8 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
9302
9561
|
if (!userRecord) {
|
|
9303
9562
|
return c.json({ error: "User not found" }, 404);
|
|
9304
9563
|
}
|
|
9305
|
-
await
|
|
9306
|
-
|
|
9564
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9565
|
+
db2,
|
|
9307
9566
|
user.userId,
|
|
9308
9567
|
"user!.view",
|
|
9309
9568
|
"users",
|
|
@@ -9336,11 +9595,11 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
9336
9595
|
}
|
|
9337
9596
|
});
|
|
9338
9597
|
userRoutes.get("/users/:id/edit", async (c) => {
|
|
9339
|
-
const
|
|
9598
|
+
const db2 = c.env.DB;
|
|
9340
9599
|
const user = c.get("user");
|
|
9341
9600
|
const userId = c.req.param("id");
|
|
9342
9601
|
try {
|
|
9343
|
-
const userStmt =
|
|
9602
|
+
const userStmt = db2.prepare(`
|
|
9344
9603
|
SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,
|
|
9345
9604
|
role, is_active, email_verified, two_factor_enabled, created_at, last_login_at
|
|
9346
9605
|
FROM users
|
|
@@ -9390,17 +9649,17 @@ userRoutes.get("/users/:id/edit", async (c) => {
|
|
|
9390
9649
|
}
|
|
9391
9650
|
});
|
|
9392
9651
|
userRoutes.put("/users/:id", async (c) => {
|
|
9393
|
-
const
|
|
9652
|
+
const db2 = c.env.DB;
|
|
9394
9653
|
const user = c.get("user");
|
|
9395
9654
|
const userId = c.req.param("id");
|
|
9396
9655
|
try {
|
|
9397
9656
|
const formData = await c.req.formData();
|
|
9398
|
-
const firstName =
|
|
9399
|
-
const lastName =
|
|
9400
|
-
const username =
|
|
9657
|
+
const firstName = chunk2HRF65VF_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9658
|
+
const lastName = chunk2HRF65VF_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9659
|
+
const username = chunk2HRF65VF_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
9401
9660
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9402
|
-
const phone =
|
|
9403
|
-
const bio =
|
|
9661
|
+
const phone = chunk2HRF65VF_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9662
|
+
const bio = chunk2HRF65VF_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
9404
9663
|
const role = formData.get("role")?.toString() || "viewer";
|
|
9405
9664
|
const isActive = formData.get("is_active") === "1";
|
|
9406
9665
|
const emailVerified = formData.get("email_verified") === "1";
|
|
@@ -9419,7 +9678,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9419
9678
|
dismissible: true
|
|
9420
9679
|
}));
|
|
9421
9680
|
}
|
|
9422
|
-
const checkStmt =
|
|
9681
|
+
const checkStmt = db2.prepare(`
|
|
9423
9682
|
SELECT id FROM users
|
|
9424
9683
|
WHERE (username = ? OR email = ?) AND id != ?
|
|
9425
9684
|
`);
|
|
@@ -9431,7 +9690,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9431
9690
|
dismissible: true
|
|
9432
9691
|
}));
|
|
9433
9692
|
}
|
|
9434
|
-
const updateStmt =
|
|
9693
|
+
const updateStmt = db2.prepare(`
|
|
9435
9694
|
UPDATE users SET
|
|
9436
9695
|
first_name = ?, last_name = ?, username = ?, email = ?,
|
|
9437
9696
|
phone = ?, bio = ?, role = ?, is_active = ?, email_verified = ?,
|
|
@@ -9451,8 +9710,8 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9451
9710
|
Date.now(),
|
|
9452
9711
|
userId
|
|
9453
9712
|
).run();
|
|
9454
|
-
await
|
|
9455
|
-
|
|
9713
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9714
|
+
db2,
|
|
9456
9715
|
user.userId,
|
|
9457
9716
|
"user!.update",
|
|
9458
9717
|
"users",
|
|
@@ -9476,7 +9735,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9476
9735
|
}
|
|
9477
9736
|
});
|
|
9478
9737
|
userRoutes.post("/users/:id/toggle", async (c) => {
|
|
9479
|
-
const
|
|
9738
|
+
const db2 = c.env.DB;
|
|
9480
9739
|
const user = c.get("user");
|
|
9481
9740
|
const userId = c.req.param("id");
|
|
9482
9741
|
try {
|
|
@@ -9485,19 +9744,19 @@ userRoutes.post("/users/:id/toggle", async (c) => {
|
|
|
9485
9744
|
if (userId === user.userId && !active) {
|
|
9486
9745
|
return c.json({ error: "You cannot deactivate your own account" }, 400);
|
|
9487
9746
|
}
|
|
9488
|
-
const userStmt =
|
|
9747
|
+
const userStmt = db2.prepare(`
|
|
9489
9748
|
SELECT id, email FROM users WHERE id = ?
|
|
9490
9749
|
`);
|
|
9491
9750
|
const userToToggle = await userStmt.bind(userId).first();
|
|
9492
9751
|
if (!userToToggle) {
|
|
9493
9752
|
return c.json({ error: "User not found" }, 404);
|
|
9494
9753
|
}
|
|
9495
|
-
const toggleStmt =
|
|
9754
|
+
const toggleStmt = db2.prepare(`
|
|
9496
9755
|
UPDATE users SET is_active = ?, updated_at = ? WHERE id = ?
|
|
9497
9756
|
`);
|
|
9498
9757
|
await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run();
|
|
9499
|
-
await
|
|
9500
|
-
|
|
9758
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9759
|
+
db2,
|
|
9501
9760
|
user.userId,
|
|
9502
9761
|
active ? "user.activate" : "user.deactivate",
|
|
9503
9762
|
"users",
|
|
@@ -9516,7 +9775,7 @@ userRoutes.post("/users/:id/toggle", async (c) => {
|
|
|
9516
9775
|
}
|
|
9517
9776
|
});
|
|
9518
9777
|
userRoutes.delete("/users/:id", async (c) => {
|
|
9519
|
-
const
|
|
9778
|
+
const db2 = c.env.DB;
|
|
9520
9779
|
const user = c.get("user");
|
|
9521
9780
|
const userId = c.req.param("id");
|
|
9522
9781
|
try {
|
|
@@ -9525,7 +9784,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9525
9784
|
if (userId === user.userId) {
|
|
9526
9785
|
return c.json({ error: "You cannot delete your own account" }, 400);
|
|
9527
9786
|
}
|
|
9528
|
-
const userStmt =
|
|
9787
|
+
const userStmt = db2.prepare(`
|
|
9529
9788
|
SELECT id, email FROM users WHERE id = ?
|
|
9530
9789
|
`);
|
|
9531
9790
|
const userToDelete = await userStmt.bind(userId).first();
|
|
@@ -9533,12 +9792,12 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9533
9792
|
return c.json({ error: "User not found" }, 404);
|
|
9534
9793
|
}
|
|
9535
9794
|
if (hardDelete) {
|
|
9536
|
-
const deleteStmt =
|
|
9795
|
+
const deleteStmt = db2.prepare(`
|
|
9537
9796
|
DELETE FROM users WHERE id = ?
|
|
9538
9797
|
`);
|
|
9539
9798
|
await deleteStmt.bind(userId).run();
|
|
9540
|
-
await
|
|
9541
|
-
|
|
9799
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9800
|
+
db2,
|
|
9542
9801
|
user.userId,
|
|
9543
9802
|
"user!.hard_delete",
|
|
9544
9803
|
"users",
|
|
@@ -9552,12 +9811,12 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9552
9811
|
message: "User permanently deleted"
|
|
9553
9812
|
});
|
|
9554
9813
|
} else {
|
|
9555
|
-
const deleteStmt =
|
|
9814
|
+
const deleteStmt = db2.prepare(`
|
|
9556
9815
|
UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?
|
|
9557
9816
|
`);
|
|
9558
9817
|
await deleteStmt.bind(Date.now(), userId).run();
|
|
9559
|
-
await
|
|
9560
|
-
|
|
9818
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9819
|
+
db2,
|
|
9561
9820
|
user.userId,
|
|
9562
9821
|
"user!.soft_delete",
|
|
9563
9822
|
"users",
|
|
@@ -9577,14 +9836,14 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9577
9836
|
}
|
|
9578
9837
|
});
|
|
9579
9838
|
userRoutes.post("/invite-user", async (c) => {
|
|
9580
|
-
const
|
|
9839
|
+
const db2 = c.env.DB;
|
|
9581
9840
|
const user = c.get("user");
|
|
9582
9841
|
try {
|
|
9583
9842
|
const formData = await c.req.formData();
|
|
9584
9843
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9585
9844
|
const role = formData.get("role")?.toString()?.trim() || "viewer";
|
|
9586
|
-
const firstName =
|
|
9587
|
-
const lastName =
|
|
9845
|
+
const firstName = chunk2HRF65VF_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9846
|
+
const lastName = chunk2HRF65VF_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9588
9847
|
if (!email || !firstName || !lastName) {
|
|
9589
9848
|
return c.json({ error: "Email, first name, and last name are required" }, 400);
|
|
9590
9849
|
}
|
|
@@ -9592,7 +9851,7 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9592
9851
|
if (!emailRegex.test(email)) {
|
|
9593
9852
|
return c.json({ error: "Please enter a valid email address" }, 400);
|
|
9594
9853
|
}
|
|
9595
|
-
const existingUserStmt =
|
|
9854
|
+
const existingUserStmt = db2.prepare(`
|
|
9596
9855
|
SELECT id FROM users WHERE email = ?
|
|
9597
9856
|
`);
|
|
9598
9857
|
const existingUser = await existingUserStmt.bind(email).first();
|
|
@@ -9601,7 +9860,7 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9601
9860
|
}
|
|
9602
9861
|
const invitationToken = crypto.randomUUID();
|
|
9603
9862
|
const userId = crypto.randomUUID();
|
|
9604
|
-
const createUserStmt =
|
|
9863
|
+
const createUserStmt = db2.prepare(`
|
|
9605
9864
|
INSERT INTO users (
|
|
9606
9865
|
id, email, first_name, last_name, role,
|
|
9607
9866
|
invitation_token, invited_by, invited_at,
|
|
@@ -9622,8 +9881,8 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9622
9881
|
Date.now(),
|
|
9623
9882
|
Date.now()
|
|
9624
9883
|
).run();
|
|
9625
|
-
await
|
|
9626
|
-
|
|
9884
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9885
|
+
db2,
|
|
9627
9886
|
user.userId,
|
|
9628
9887
|
"user!.invite_sent",
|
|
9629
9888
|
"users",
|
|
@@ -9652,11 +9911,11 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9652
9911
|
}
|
|
9653
9912
|
});
|
|
9654
9913
|
userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
9655
|
-
const
|
|
9914
|
+
const db2 = c.env.DB;
|
|
9656
9915
|
const user = c.get("user");
|
|
9657
9916
|
const userId = c.req.param("id");
|
|
9658
9917
|
try {
|
|
9659
|
-
const userStmt =
|
|
9918
|
+
const userStmt = db2.prepare(`
|
|
9660
9919
|
SELECT id, email, first_name, last_name, role, invitation_token
|
|
9661
9920
|
FROM users
|
|
9662
9921
|
WHERE id = ? AND is_active = 0 AND invitation_token IS NOT NULL
|
|
@@ -9666,7 +9925,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
9666
9925
|
return c.json({ error: "User not found or invitation not valid" }, 404);
|
|
9667
9926
|
}
|
|
9668
9927
|
const newInvitationToken = crypto.randomUUID();
|
|
9669
|
-
const updateStmt =
|
|
9928
|
+
const updateStmt = db2.prepare(`
|
|
9670
9929
|
UPDATE users SET
|
|
9671
9930
|
invitation_token = ?,
|
|
9672
9931
|
invited_at = ?,
|
|
@@ -9679,8 +9938,8 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
9679
9938
|
Date.now(),
|
|
9680
9939
|
userId
|
|
9681
9940
|
).run();
|
|
9682
|
-
await
|
|
9683
|
-
|
|
9941
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9942
|
+
db2,
|
|
9684
9943
|
user.userId,
|
|
9685
9944
|
"user!.invitation_resent",
|
|
9686
9945
|
"users",
|
|
@@ -9701,11 +9960,11 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
9701
9960
|
}
|
|
9702
9961
|
});
|
|
9703
9962
|
userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
9704
|
-
const
|
|
9963
|
+
const db2 = c.env.DB;
|
|
9705
9964
|
const user = c.get("user");
|
|
9706
9965
|
const userId = c.req.param("id");
|
|
9707
9966
|
try {
|
|
9708
|
-
const userStmt =
|
|
9967
|
+
const userStmt = db2.prepare(`
|
|
9709
9968
|
SELECT id, email FROM users
|
|
9710
9969
|
WHERE id = ? AND is_active = 0 AND invitation_token IS NOT NULL
|
|
9711
9970
|
`);
|
|
@@ -9713,10 +9972,10 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
|
9713
9972
|
if (!invitedUser) {
|
|
9714
9973
|
return c.json({ error: "User not found or invitation not valid" }, 404);
|
|
9715
9974
|
}
|
|
9716
|
-
const deleteStmt =
|
|
9975
|
+
const deleteStmt = db2.prepare(`DELETE FROM users WHERE id = ?`);
|
|
9717
9976
|
await deleteStmt.bind(userId).run();
|
|
9718
|
-
await
|
|
9719
|
-
|
|
9977
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
9978
|
+
db2,
|
|
9720
9979
|
user.userId,
|
|
9721
9980
|
"user!.invitation_cancelled",
|
|
9722
9981
|
"users",
|
|
@@ -9735,7 +9994,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
|
9735
9994
|
}
|
|
9736
9995
|
});
|
|
9737
9996
|
userRoutes.get("/activity-logs", async (c) => {
|
|
9738
|
-
const
|
|
9997
|
+
const db2 = c.env.DB;
|
|
9739
9998
|
const user = c.get("user");
|
|
9740
9999
|
try {
|
|
9741
10000
|
const page = parseInt(c.req.query("page") || "1");
|
|
@@ -9773,7 +10032,7 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
9773
10032
|
params.push(toTimestamp);
|
|
9774
10033
|
}
|
|
9775
10034
|
const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
|
|
9776
|
-
const logsStmt =
|
|
10035
|
+
const logsStmt = db2.prepare(`
|
|
9777
10036
|
SELECT
|
|
9778
10037
|
al.id, al.user_id, al.action, al.resource_type, al.resource_id,
|
|
9779
10038
|
al.details, al.ip_address, al.user_agent, al.created_at,
|
|
@@ -9786,7 +10045,7 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
9786
10045
|
LIMIT ? OFFSET ?
|
|
9787
10046
|
`);
|
|
9788
10047
|
const { results: logs } = await logsStmt.bind(...params, limit, offset).all();
|
|
9789
|
-
const countStmt =
|
|
10048
|
+
const countStmt = db2.prepare(`
|
|
9790
10049
|
SELECT COUNT(*) as total
|
|
9791
10050
|
FROM activity_logs al
|
|
9792
10051
|
LEFT JOIN users u ON al.user_id = u.id
|
|
@@ -9798,8 +10057,8 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
9798
10057
|
...log,
|
|
9799
10058
|
details: log.details ? JSON.parse(log.details) : null
|
|
9800
10059
|
}));
|
|
9801
|
-
await
|
|
9802
|
-
|
|
10060
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
10061
|
+
db2,
|
|
9803
10062
|
user.userId,
|
|
9804
10063
|
"activity.logs_viewed",
|
|
9805
10064
|
void 0,
|
|
@@ -9841,7 +10100,7 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
9841
10100
|
}
|
|
9842
10101
|
});
|
|
9843
10102
|
userRoutes.get("/activity-logs/export", async (c) => {
|
|
9844
|
-
const
|
|
10103
|
+
const db2 = c.env.DB;
|
|
9845
10104
|
const user = c.get("user");
|
|
9846
10105
|
try {
|
|
9847
10106
|
const filters = {
|
|
@@ -9876,7 +10135,7 @@ userRoutes.get("/activity-logs/export", async (c) => {
|
|
|
9876
10135
|
params.push(toTimestamp);
|
|
9877
10136
|
}
|
|
9878
10137
|
const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
|
|
9879
|
-
const logsStmt =
|
|
10138
|
+
const logsStmt = db2.prepare(`
|
|
9880
10139
|
SELECT
|
|
9881
10140
|
al.id, al.user_id, al.action, al.resource_type, al.resource_id,
|
|
9882
10141
|
al.details, al.ip_address, al.user_agent, al.created_at,
|
|
@@ -9905,8 +10164,8 @@ userRoutes.get("/activity-logs/export", async (c) => {
|
|
|
9905
10164
|
csvRows.push(row.join(","));
|
|
9906
10165
|
}
|
|
9907
10166
|
const csvContent = csvRows.join("\n");
|
|
9908
|
-
await
|
|
9909
|
-
|
|
10167
|
+
await chunkF4IGVB2V_cjs.logActivity(
|
|
10168
|
+
db2,
|
|
9910
10169
|
user.userId,
|
|
9911
10170
|
"activity.logs_exported",
|
|
9912
10171
|
void 0,
|
|
@@ -11244,7 +11503,7 @@ var fileValidationSchema2 = zod.z.object({
|
|
|
11244
11503
|
// 50MB max
|
|
11245
11504
|
});
|
|
11246
11505
|
var adminMediaRoutes = new hono.Hono();
|
|
11247
|
-
adminMediaRoutes.use("*",
|
|
11506
|
+
adminMediaRoutes.use("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
11248
11507
|
adminMediaRoutes.get("/", async (c) => {
|
|
11249
11508
|
try {
|
|
11250
11509
|
const user = c.get("user");
|
|
@@ -11256,7 +11515,7 @@ adminMediaRoutes.get("/", async (c) => {
|
|
|
11256
11515
|
const ____cacheBust = searchParams.get("t");
|
|
11257
11516
|
const limit = 24;
|
|
11258
11517
|
const offset = (page - 1) * limit;
|
|
11259
|
-
const
|
|
11518
|
+
const db2 = c.env.DB;
|
|
11260
11519
|
let query = "SELECT * FROM media";
|
|
11261
11520
|
const params = [];
|
|
11262
11521
|
const conditions = ["deleted_at IS NULL"];
|
|
@@ -11284,9 +11543,9 @@ adminMediaRoutes.get("/", async (c) => {
|
|
|
11284
11543
|
query += ` WHERE ${conditions.join(" AND ")}`;
|
|
11285
11544
|
}
|
|
11286
11545
|
query += ` ORDER BY uploaded_at DESC LIMIT ${limit} OFFSET ${offset}`;
|
|
11287
|
-
const stmt =
|
|
11546
|
+
const stmt = db2.prepare(query);
|
|
11288
11547
|
const { results } = await stmt.bind(...params).all();
|
|
11289
|
-
const foldersStmt =
|
|
11548
|
+
const foldersStmt = db2.prepare(`
|
|
11290
11549
|
SELECT folder, COUNT(*) as count, SUM(size) as totalSize
|
|
11291
11550
|
FROM media
|
|
11292
11551
|
WHERE deleted_at IS NULL
|
|
@@ -11294,7 +11553,7 @@ adminMediaRoutes.get("/", async (c) => {
|
|
|
11294
11553
|
ORDER BY folder
|
|
11295
11554
|
`);
|
|
11296
11555
|
const { results: folders } = await foldersStmt.all();
|
|
11297
|
-
const typesStmt =
|
|
11556
|
+
const typesStmt = db2.prepare(`
|
|
11298
11557
|
SELECT
|
|
11299
11558
|
CASE
|
|
11300
11559
|
WHEN mime_type LIKE 'image/%' THEN 'images'
|
|
@@ -11360,7 +11619,7 @@ adminMediaRoutes.get("/selector", async (c) => {
|
|
|
11360
11619
|
try {
|
|
11361
11620
|
const { searchParams } = new URL(c.req.url);
|
|
11362
11621
|
const search = searchParams.get("search") || "";
|
|
11363
|
-
const
|
|
11622
|
+
const db2 = c.env.DB;
|
|
11364
11623
|
let query = "SELECT * FROM media WHERE deleted_at IS NULL";
|
|
11365
11624
|
const params = [];
|
|
11366
11625
|
if (search.trim()) {
|
|
@@ -11369,7 +11628,7 @@ adminMediaRoutes.get("/selector", async (c) => {
|
|
|
11369
11628
|
params.push(searchTerm, searchTerm, searchTerm);
|
|
11370
11629
|
}
|
|
11371
11630
|
query += " ORDER BY uploaded_at DESC LIMIT 24";
|
|
11372
|
-
const stmt =
|
|
11631
|
+
const stmt = db2.prepare(query);
|
|
11373
11632
|
const { results } = await stmt.bind(...params).all();
|
|
11374
11633
|
const mediaFiles = results.map((row) => ({
|
|
11375
11634
|
id: row.id,
|
|
@@ -11476,7 +11735,7 @@ adminMediaRoutes.get("/search", async (c) => {
|
|
|
11476
11735
|
const search = searchParams.get("search") || "";
|
|
11477
11736
|
const folder = searchParams.get("folder") || "all";
|
|
11478
11737
|
const type = searchParams.get("type") || "all";
|
|
11479
|
-
const
|
|
11738
|
+
const db2 = c.env.DB;
|
|
11480
11739
|
let query = "SELECT * FROM media";
|
|
11481
11740
|
const params = [];
|
|
11482
11741
|
const conditions = [];
|
|
@@ -11509,7 +11768,7 @@ adminMediaRoutes.get("/search", async (c) => {
|
|
|
11509
11768
|
query += ` WHERE ${conditions.join(" AND ")}`;
|
|
11510
11769
|
}
|
|
11511
11770
|
query += ` ORDER BY uploaded_at DESC LIMIT 24`;
|
|
11512
|
-
const stmt =
|
|
11771
|
+
const stmt = db2.prepare(query);
|
|
11513
11772
|
const { results } = await stmt.bind(...params).all();
|
|
11514
11773
|
const mediaFiles = results.map((row) => ({
|
|
11515
11774
|
...row,
|
|
@@ -11532,8 +11791,8 @@ adminMediaRoutes.get("/search", async (c) => {
|
|
|
11532
11791
|
adminMediaRoutes.get("/:id/details", async (c) => {
|
|
11533
11792
|
try {
|
|
11534
11793
|
const id = c.req.param("id");
|
|
11535
|
-
const
|
|
11536
|
-
const stmt =
|
|
11794
|
+
const db2 = c.env.DB;
|
|
11795
|
+
const stmt = db2.prepare("SELECT * FROM media WHERE id = ?");
|
|
11537
11796
|
const result = await stmt.bind(id).first();
|
|
11538
11797
|
if (!result) {
|
|
11539
11798
|
return c.html('<div class="text-red-500">File not found</div>');
|
|
@@ -11606,7 +11865,7 @@ adminMediaRoutes.post("/upload", async (c) => {
|
|
|
11606
11865
|
});
|
|
11607
11866
|
continue;
|
|
11608
11867
|
}
|
|
11609
|
-
const fileId =
|
|
11868
|
+
const fileId = crypto.randomUUID();
|
|
11610
11869
|
const fileExtension = file.name.split(".").pop() || "";
|
|
11611
11870
|
const filename = `${fileId}.${fileExtension}`;
|
|
11612
11871
|
const folder = formData.get("folder") || "uploads";
|
|
@@ -11823,12 +12082,12 @@ adminMediaRoutes.put("/:id", async (c) => {
|
|
|
11823
12082
|
`);
|
|
11824
12083
|
}
|
|
11825
12084
|
});
|
|
11826
|
-
adminMediaRoutes.delete("/cleanup",
|
|
12085
|
+
adminMediaRoutes.delete("/cleanup", chunkF4IGVB2V_cjs.requireRole("admin"), async (c) => {
|
|
11827
12086
|
try {
|
|
11828
|
-
const
|
|
11829
|
-
const allMediaStmt =
|
|
12087
|
+
const db2 = c.env.DB;
|
|
12088
|
+
const allMediaStmt = db2.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
|
|
11830
12089
|
const { results: allMedia } = await allMediaStmt.all();
|
|
11831
|
-
const contentStmt =
|
|
12090
|
+
const contentStmt = db2.prepare("SELECT data FROM content");
|
|
11832
12091
|
const { results: contentRecords } = await contentStmt.all();
|
|
11833
12092
|
const referencedUrls = /* @__PURE__ */ new Set();
|
|
11834
12093
|
for (const record of contentRecords) {
|
|
@@ -11858,7 +12117,7 @@ adminMediaRoutes.delete("/cleanup", chunkX2VADBA4_cjs.requireRole("admin"), asyn
|
|
|
11858
12117
|
for (const file of unusedFiles) {
|
|
11859
12118
|
try {
|
|
11860
12119
|
await c.env.MEDIA_BUCKET.delete(file.r2_key);
|
|
11861
|
-
const deleteStmt =
|
|
12120
|
+
const deleteStmt = db2.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
|
|
11862
12121
|
await deleteStmt.bind(Math.floor(Date.now() / 1e3), file.id).run();
|
|
11863
12122
|
deletedCount++;
|
|
11864
12123
|
} catch (error) {
|
|
@@ -12082,44 +12341,6 @@ function renderPluginsListPage(data) {
|
|
|
12082
12341
|
<h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">Plugins</h1>
|
|
12083
12342
|
<p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">Manage and extend functionality with plugins</p>
|
|
12084
12343
|
</div>
|
|
12085
|
-
<div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none">
|
|
12086
|
-
<div class="relative inline-block text-left">
|
|
12087
|
-
<button onclick="toggleDropdown()" class="inline-flex items-center justify-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm">
|
|
12088
|
-
<svg class="-ml-0.5 mr-1.5 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
12089
|
-
<path d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z" />
|
|
12090
|
-
</svg>
|
|
12091
|
-
Install Plugin
|
|
12092
|
-
<svg class="-mr-1 ml-2 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
12093
|
-
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
|
12094
|
-
</svg>
|
|
12095
|
-
</button>
|
|
12096
|
-
<div id="plugin-dropdown" class="hidden absolute right-0 z-10 mt-2 w-56 origin-top-right rounded-xl bg-white dark:bg-zinc-900 shadow-xl ring-1 ring-zinc-950/5 dark:ring-white/10 focus:outline-none">
|
|
12097
|
-
<div class="py-1">
|
|
12098
|
-
<button onclick="installPlugin('faq-plugin')" class="block w-full text-left px-4 py-2 text-sm text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors first:rounded-t-xl">
|
|
12099
|
-
<div class="flex items-center">
|
|
12100
|
-
<span class="text-lg mr-2">\u2753</span>
|
|
12101
|
-
<div>
|
|
12102
|
-
<div class="font-medium">FAQ System</div>
|
|
12103
|
-
<div class="text-xs text-zinc-500 dark:text-zinc-400">Community FAQ management plugin</div>
|
|
12104
|
-
</div>
|
|
12105
|
-
</div>
|
|
12106
|
-
</button>
|
|
12107
|
-
<div class="border-t border-zinc-950/5 dark:border-white/10 my-1"></div>
|
|
12108
|
-
<button onclick="showNotification('Plugin marketplace coming soon!', 'info')" class="block w-full text-left px-4 py-2 text-sm text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors last:rounded-b-xl">
|
|
12109
|
-
<div class="flex items-center">
|
|
12110
|
-
<svg class="w-5 h-5 mr-2 text-zinc-500 dark:text-zinc-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
12111
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
|
|
12112
|
-
</svg>
|
|
12113
|
-
<div>
|
|
12114
|
-
<div class="font-medium">Browse Marketplace</div>
|
|
12115
|
-
<div class="text-xs text-zinc-500 dark:text-zinc-400">Discover more plugins</div>
|
|
12116
|
-
</div>
|
|
12117
|
-
</div>
|
|
12118
|
-
</button>
|
|
12119
|
-
</div>
|
|
12120
|
-
</div>
|
|
12121
|
-
</div>
|
|
12122
|
-
</div>
|
|
12123
12344
|
</div>
|
|
12124
12345
|
|
|
12125
12346
|
<!-- Experimental Notice -->
|
|
@@ -12450,16 +12671,11 @@ function renderPluginsListPage(data) {
|
|
|
12450
12671
|
notification.className = \`fixed top-4 right-4 px-4 py-2 rounded-lg text-white z-50 \${bgColor}\`;
|
|
12451
12672
|
notification.textContent = message;
|
|
12452
12673
|
document.body.appendChild(notification);
|
|
12453
|
-
|
|
12674
|
+
|
|
12454
12675
|
setTimeout(() => {
|
|
12455
12676
|
notification.remove();
|
|
12456
12677
|
}, 3000);
|
|
12457
12678
|
}
|
|
12458
|
-
|
|
12459
|
-
function toggleDropdown() {
|
|
12460
|
-
const dropdown = document.getElementById('plugin-dropdown');
|
|
12461
|
-
dropdown.classList.toggle('hidden');
|
|
12462
|
-
}
|
|
12463
12679
|
|
|
12464
12680
|
function filterPlugins() {
|
|
12465
12681
|
const categoryFilter = document.getElementById('category-filter').value.toLowerCase();
|
|
@@ -12526,16 +12742,6 @@ function renderPluginsListPage(data) {
|
|
|
12526
12742
|
noResultsMsg.style.display = 'none';
|
|
12527
12743
|
}
|
|
12528
12744
|
}
|
|
12529
|
-
|
|
12530
|
-
// Close dropdown when clicking outside
|
|
12531
|
-
document.addEventListener('click', (event) => {
|
|
12532
|
-
const dropdown = document.getElementById('plugin-dropdown');
|
|
12533
|
-
const button = event.target.closest('button[onclick="toggleDropdown()"]');
|
|
12534
|
-
|
|
12535
|
-
if (!button && !dropdown.contains(event.target)) {
|
|
12536
|
-
dropdown.classList.add('hidden');
|
|
12537
|
-
}
|
|
12538
|
-
});
|
|
12539
12745
|
</script>
|
|
12540
12746
|
|
|
12541
12747
|
<!-- Confirmation Dialogs -->
|
|
@@ -13480,7 +13686,7 @@ function formatTimestamp(timestamp) {
|
|
|
13480
13686
|
|
|
13481
13687
|
// src/routes/admin-plugins.ts
|
|
13482
13688
|
var adminPluginRoutes = new hono.Hono();
|
|
13483
|
-
adminPluginRoutes.use("*",
|
|
13689
|
+
adminPluginRoutes.use("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
13484
13690
|
var AVAILABLE_PLUGINS = [
|
|
13485
13691
|
{
|
|
13486
13692
|
id: "third-party-faq",
|
|
@@ -13559,16 +13765,29 @@ var AVAILABLE_PLUGINS = [
|
|
|
13559
13765
|
permissions: [],
|
|
13560
13766
|
dependencies: [],
|
|
13561
13767
|
is_core: false
|
|
13768
|
+
},
|
|
13769
|
+
{
|
|
13770
|
+
id: "easy-mdx",
|
|
13771
|
+
name: "easy-mdx",
|
|
13772
|
+
display_name: "EasyMDE Markdown Editor",
|
|
13773
|
+
description: "Lightweight markdown editor with live preview. Provides a simple and efficient editor with markdown support for richtext fields.",
|
|
13774
|
+
version: "1.0.0",
|
|
13775
|
+
author: "SonicJS Team",
|
|
13776
|
+
category: "editor",
|
|
13777
|
+
icon: "\u{1F4DD}",
|
|
13778
|
+
permissions: [],
|
|
13779
|
+
dependencies: [],
|
|
13780
|
+
is_core: false
|
|
13562
13781
|
}
|
|
13563
13782
|
];
|
|
13564
13783
|
adminPluginRoutes.get("/", async (c) => {
|
|
13565
13784
|
try {
|
|
13566
13785
|
const user = c.get("user");
|
|
13567
|
-
const
|
|
13786
|
+
const db2 = c.env.DB;
|
|
13568
13787
|
if (user?.role !== "admin") {
|
|
13569
13788
|
return c.text("Access denied", 403);
|
|
13570
13789
|
}
|
|
13571
|
-
const pluginService = new
|
|
13790
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
13572
13791
|
let installedPlugins = [];
|
|
13573
13792
|
let stats = { total: 0, active: 0, inactive: 0, errors: 0, uninstalled: 0 };
|
|
13574
13793
|
try {
|
|
@@ -13635,12 +13854,12 @@ adminPluginRoutes.get("/", async (c) => {
|
|
|
13635
13854
|
adminPluginRoutes.get("/:id", async (c) => {
|
|
13636
13855
|
try {
|
|
13637
13856
|
const user = c.get("user");
|
|
13638
|
-
const
|
|
13857
|
+
const db2 = c.env.DB;
|
|
13639
13858
|
const pluginId = c.req.param("id");
|
|
13640
13859
|
if (user?.role !== "admin") {
|
|
13641
13860
|
return c.redirect("/admin/plugins");
|
|
13642
13861
|
}
|
|
13643
|
-
const pluginService = new
|
|
13862
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
13644
13863
|
const plugin = await pluginService.getPlugin(pluginId);
|
|
13645
13864
|
if (!plugin) {
|
|
13646
13865
|
return c.text("Plugin not found", 404);
|
|
@@ -13689,12 +13908,12 @@ adminPluginRoutes.get("/:id", async (c) => {
|
|
|
13689
13908
|
adminPluginRoutes.post("/:id/activate", async (c) => {
|
|
13690
13909
|
try {
|
|
13691
13910
|
const user = c.get("user");
|
|
13692
|
-
const
|
|
13911
|
+
const db2 = c.env.DB;
|
|
13693
13912
|
const pluginId = c.req.param("id");
|
|
13694
13913
|
if (user?.role !== "admin") {
|
|
13695
13914
|
return c.json({ error: "Access denied" }, 403);
|
|
13696
13915
|
}
|
|
13697
|
-
const pluginService = new
|
|
13916
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
13698
13917
|
await pluginService.activatePlugin(pluginId);
|
|
13699
13918
|
return c.json({ success: true });
|
|
13700
13919
|
} catch (error) {
|
|
@@ -13706,12 +13925,12 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
|
|
|
13706
13925
|
adminPluginRoutes.post("/:id/deactivate", async (c) => {
|
|
13707
13926
|
try {
|
|
13708
13927
|
const user = c.get("user");
|
|
13709
|
-
const
|
|
13928
|
+
const db2 = c.env.DB;
|
|
13710
13929
|
const pluginId = c.req.param("id");
|
|
13711
13930
|
if (user?.role !== "admin") {
|
|
13712
13931
|
return c.json({ error: "Access denied" }, 403);
|
|
13713
13932
|
}
|
|
13714
|
-
const pluginService = new
|
|
13933
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
13715
13934
|
await pluginService.deactivatePlugin(pluginId);
|
|
13716
13935
|
return c.json({ success: true });
|
|
13717
13936
|
} catch (error) {
|
|
@@ -13723,12 +13942,12 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
|
|
|
13723
13942
|
adminPluginRoutes.post("/install", async (c) => {
|
|
13724
13943
|
try {
|
|
13725
13944
|
const user = c.get("user");
|
|
13726
|
-
const
|
|
13945
|
+
const db2 = c.env.DB;
|
|
13727
13946
|
if (user?.role !== "admin") {
|
|
13728
13947
|
return c.json({ error: "Access denied" }, 403);
|
|
13729
13948
|
}
|
|
13730
13949
|
const body = await c.req.json();
|
|
13731
|
-
const pluginService = new
|
|
13950
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
13732
13951
|
if (body.name === "faq-plugin") {
|
|
13733
13952
|
const faqPlugin = await pluginService.installPlugin({
|
|
13734
13953
|
id: "third-party-faq",
|
|
@@ -13907,6 +14126,28 @@ adminPluginRoutes.post("/install", async (c) => {
|
|
|
13907
14126
|
});
|
|
13908
14127
|
return c.json({ success: true, plugin: tinymcePlugin2 });
|
|
13909
14128
|
}
|
|
14129
|
+
if (body.name === "easy-mdx") {
|
|
14130
|
+
const easyMdxPlugin2 = await pluginService.installPlugin({
|
|
14131
|
+
id: "easy-mdx",
|
|
14132
|
+
name: "easy-mdx",
|
|
14133
|
+
display_name: "EasyMDE Markdown Editor",
|
|
14134
|
+
description: "Lightweight markdown editor with live preview. Provides a simple and efficient editor with markdown support for richtext fields.",
|
|
14135
|
+
version: "1.0.0",
|
|
14136
|
+
author: "SonicJS Team",
|
|
14137
|
+
category: "editor",
|
|
14138
|
+
icon: "\u{1F4DD}",
|
|
14139
|
+
permissions: [],
|
|
14140
|
+
dependencies: [],
|
|
14141
|
+
is_core: false,
|
|
14142
|
+
settings: {
|
|
14143
|
+
defaultHeight: 400,
|
|
14144
|
+
theme: "dark",
|
|
14145
|
+
toolbar: "full",
|
|
14146
|
+
placeholder: "Start writing your content..."
|
|
14147
|
+
}
|
|
14148
|
+
});
|
|
14149
|
+
return c.json({ success: true, plugin: easyMdxPlugin2 });
|
|
14150
|
+
}
|
|
13910
14151
|
return c.json({ error: "Plugin not found in registry" }, 404);
|
|
13911
14152
|
} catch (error) {
|
|
13912
14153
|
console.error("Error installing plugin:", error);
|
|
@@ -13917,12 +14158,12 @@ adminPluginRoutes.post("/install", async (c) => {
|
|
|
13917
14158
|
adminPluginRoutes.post("/:id/uninstall", async (c) => {
|
|
13918
14159
|
try {
|
|
13919
14160
|
const user = c.get("user");
|
|
13920
|
-
const
|
|
14161
|
+
const db2 = c.env.DB;
|
|
13921
14162
|
const pluginId = c.req.param("id");
|
|
13922
14163
|
if (user?.role !== "admin") {
|
|
13923
14164
|
return c.json({ error: "Access denied" }, 403);
|
|
13924
14165
|
}
|
|
13925
|
-
const pluginService = new
|
|
14166
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
13926
14167
|
await pluginService.uninstallPlugin(pluginId);
|
|
13927
14168
|
return c.json({ success: true });
|
|
13928
14169
|
} catch (error) {
|
|
@@ -13934,13 +14175,13 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
|
|
|
13934
14175
|
adminPluginRoutes.post("/:id/settings", async (c) => {
|
|
13935
14176
|
try {
|
|
13936
14177
|
const user = c.get("user");
|
|
13937
|
-
const
|
|
14178
|
+
const db2 = c.env.DB;
|
|
13938
14179
|
const pluginId = c.req.param("id");
|
|
13939
14180
|
if (user?.role !== "admin") {
|
|
13940
14181
|
return c.json({ error: "Access denied" }, 403);
|
|
13941
14182
|
}
|
|
13942
14183
|
const settings = await c.req.json();
|
|
13943
|
-
const pluginService = new
|
|
14184
|
+
const pluginService = new chunk22EFGHAX_cjs.PluginService(db2);
|
|
13944
14185
|
await pluginService.updatePluginSettings(pluginId, settings);
|
|
13945
14186
|
return c.json({ success: true });
|
|
13946
14187
|
} catch (error) {
|
|
@@ -14736,11 +14977,11 @@ function renderLogConfigPage(data) {
|
|
|
14736
14977
|
|
|
14737
14978
|
// src/routes/admin-logs.ts
|
|
14738
14979
|
var adminLogsRoutes = new hono.Hono();
|
|
14739
|
-
adminLogsRoutes.use("*",
|
|
14980
|
+
adminLogsRoutes.use("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
14740
14981
|
adminLogsRoutes.get("/", async (c) => {
|
|
14741
14982
|
try {
|
|
14742
14983
|
const user = c.get("user");
|
|
14743
|
-
const logger =
|
|
14984
|
+
const logger = chunk3F4LF7LW_cjs.getLogger(c.env.DB);
|
|
14744
14985
|
const query = c.req.query();
|
|
14745
14986
|
const page = parseInt(query.page || "1");
|
|
14746
14987
|
const limit = parseInt(query.limit || "50");
|
|
@@ -14820,7 +15061,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
14820
15061
|
try {
|
|
14821
15062
|
const id = c.req.param("id");
|
|
14822
15063
|
const user = c.get("user");
|
|
14823
|
-
const logger =
|
|
15064
|
+
const logger = chunk3F4LF7LW_cjs.getLogger(c.env.DB);
|
|
14824
15065
|
const { logs } = await logger.getLogs({
|
|
14825
15066
|
limit: 1,
|
|
14826
15067
|
offset: 0,
|
|
@@ -14857,7 +15098,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
14857
15098
|
adminLogsRoutes.get("/config", async (c) => {
|
|
14858
15099
|
try {
|
|
14859
15100
|
const user = c.get("user");
|
|
14860
|
-
const logger =
|
|
15101
|
+
const logger = chunk3F4LF7LW_cjs.getLogger(c.env.DB);
|
|
14861
15102
|
const configs = await logger.getAllConfigs();
|
|
14862
15103
|
const pageData = {
|
|
14863
15104
|
configs,
|
|
@@ -14881,7 +15122,7 @@ adminLogsRoutes.post("/config/:category", async (c) => {
|
|
|
14881
15122
|
const level = formData.get("level");
|
|
14882
15123
|
const retention = parseInt(formData.get("retention"));
|
|
14883
15124
|
const maxSize = parseInt(formData.get("max_size"));
|
|
14884
|
-
const logger =
|
|
15125
|
+
const logger = chunk3F4LF7LW_cjs.getLogger(c.env.DB);
|
|
14885
15126
|
await logger.updateConfig(category, {
|
|
14886
15127
|
enabled,
|
|
14887
15128
|
level,
|
|
@@ -14910,7 +15151,7 @@ adminLogsRoutes.get("/export", async (c) => {
|
|
|
14910
15151
|
const category = query.category;
|
|
14911
15152
|
const startDate = query.start_date;
|
|
14912
15153
|
const endDate = query.end_date;
|
|
14913
|
-
const logger =
|
|
15154
|
+
const logger = chunk3F4LF7LW_cjs.getLogger(c.env.DB);
|
|
14914
15155
|
const filter = {
|
|
14915
15156
|
limit: 1e4,
|
|
14916
15157
|
// Export up to 10k logs
|
|
@@ -14991,7 +15232,7 @@ adminLogsRoutes.post("/cleanup", async (c) => {
|
|
|
14991
15232
|
error: "Unauthorized. Admin access required."
|
|
14992
15233
|
}, 403);
|
|
14993
15234
|
}
|
|
14994
|
-
const logger =
|
|
15235
|
+
const logger = chunk3F4LF7LW_cjs.getLogger(c.env.DB);
|
|
14995
15236
|
await logger.cleanupByRetention();
|
|
14996
15237
|
return c.html(html.html`
|
|
14997
15238
|
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded">
|
|
@@ -15013,7 +15254,7 @@ adminLogsRoutes.post("/search", async (c) => {
|
|
|
15013
15254
|
const search = formData.get("search");
|
|
15014
15255
|
const level = formData.get("level");
|
|
15015
15256
|
const category = formData.get("category");
|
|
15016
|
-
const logger =
|
|
15257
|
+
const logger = chunk3F4LF7LW_cjs.getLogger(c.env.DB);
|
|
15017
15258
|
const filter = {
|
|
15018
15259
|
limit: 20,
|
|
15019
15260
|
offset: 0,
|
|
@@ -15401,8 +15642,8 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
15401
15642
|
const currentPage = parseInt(page, 10) || 1;
|
|
15402
15643
|
const limit = 20;
|
|
15403
15644
|
const offset = (currentPage - 1) * limit;
|
|
15404
|
-
const
|
|
15405
|
-
if (!
|
|
15645
|
+
const db2 = c.env?.DB;
|
|
15646
|
+
if (!db2) {
|
|
15406
15647
|
return c.html(chunkYU6QFFI4_cjs.renderTestimonialsList({
|
|
15407
15648
|
testimonials: [],
|
|
15408
15649
|
totalCount: 0,
|
|
@@ -15433,7 +15674,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
15433
15674
|
params.push(searchTerm, searchTerm, searchTerm);
|
|
15434
15675
|
}
|
|
15435
15676
|
const countQuery = `SELECT COUNT(*) as count FROM testimonials ${whereClause}`;
|
|
15436
|
-
const { results: countResults } = await
|
|
15677
|
+
const { results: countResults } = await db2.prepare(countQuery).bind(...params).all();
|
|
15437
15678
|
const totalCount = countResults?.[0]?.count || 0;
|
|
15438
15679
|
const dataQuery = `
|
|
15439
15680
|
SELECT * FROM testimonials
|
|
@@ -15441,7 +15682,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
15441
15682
|
ORDER BY sortOrder ASC, created_at DESC
|
|
15442
15683
|
LIMIT ? OFFSET ?
|
|
15443
15684
|
`;
|
|
15444
|
-
const { results: testimonials } = await
|
|
15685
|
+
const { results: testimonials } = await db2.prepare(dataQuery).bind(...params, limit, offset).all();
|
|
15445
15686
|
const totalPages = Math.ceil(totalCount / limit);
|
|
15446
15687
|
return c.html(chunkYU6QFFI4_cjs.renderTestimonialsList({
|
|
15447
15688
|
testimonials: testimonials || [],
|
|
@@ -15489,8 +15730,8 @@ adminTestimonialsRoutes.post("/", async (c) => {
|
|
|
15489
15730
|
const data = Object.fromEntries(formData.entries());
|
|
15490
15731
|
const validatedData = testimonialSchema.parse(data);
|
|
15491
15732
|
const user = c.get("user");
|
|
15492
|
-
const
|
|
15493
|
-
if (!
|
|
15733
|
+
const db2 = c.env?.DB;
|
|
15734
|
+
if (!db2) {
|
|
15494
15735
|
return c.html(renderTestimonialsForm({
|
|
15495
15736
|
isEdit: false,
|
|
15496
15737
|
user: user ? {
|
|
@@ -15502,7 +15743,7 @@ adminTestimonialsRoutes.post("/", async (c) => {
|
|
|
15502
15743
|
messageType: "error"
|
|
15503
15744
|
}));
|
|
15504
15745
|
}
|
|
15505
|
-
const { results } = await
|
|
15746
|
+
const { results } = await db2.prepare(`
|
|
15506
15747
|
INSERT INTO testimonials (author_name, author_title, author_company, testimonial_text, rating, isPublished, sortOrder)
|
|
15507
15748
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
15508
15749
|
RETURNING *
|
|
@@ -15534,7 +15775,7 @@ adminTestimonialsRoutes.post("/", async (c) => {
|
|
|
15534
15775
|
const user = c.get("user");
|
|
15535
15776
|
if (error instanceof zod.z.ZodError) {
|
|
15536
15777
|
const errors = {};
|
|
15537
|
-
error.
|
|
15778
|
+
error.issues.forEach((err) => {
|
|
15538
15779
|
const field = err.path[0];
|
|
15539
15780
|
if (!errors[field]) errors[field] = [];
|
|
15540
15781
|
errors[field].push(err.message);
|
|
@@ -15567,8 +15808,8 @@ adminTestimonialsRoutes.get("/:id", async (c) => {
|
|
|
15567
15808
|
try {
|
|
15568
15809
|
const id = parseInt(c.req.param("id"));
|
|
15569
15810
|
const user = c.get("user");
|
|
15570
|
-
const
|
|
15571
|
-
if (!
|
|
15811
|
+
const db2 = c.env?.DB;
|
|
15812
|
+
if (!db2) {
|
|
15572
15813
|
return c.html(renderTestimonialsForm({
|
|
15573
15814
|
isEdit: true,
|
|
15574
15815
|
user: user ? {
|
|
@@ -15580,7 +15821,7 @@ adminTestimonialsRoutes.get("/:id", async (c) => {
|
|
|
15580
15821
|
messageType: "error"
|
|
15581
15822
|
}));
|
|
15582
15823
|
}
|
|
15583
|
-
const { results } = await
|
|
15824
|
+
const { results } = await db2.prepare("SELECT * FROM testimonials WHERE id = ?").bind(id).all();
|
|
15584
15825
|
if (!results || results.length === 0) {
|
|
15585
15826
|
return c.redirect("/admin/testimonials?message=Testimonial not found&type=error");
|
|
15586
15827
|
}
|
|
@@ -15625,8 +15866,8 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
|
|
|
15625
15866
|
const data = Object.fromEntries(formData.entries());
|
|
15626
15867
|
const validatedData = testimonialSchema.parse(data);
|
|
15627
15868
|
const user = c.get("user");
|
|
15628
|
-
const
|
|
15629
|
-
if (!
|
|
15869
|
+
const db2 = c.env?.DB;
|
|
15870
|
+
if (!db2) {
|
|
15630
15871
|
return c.html(renderTestimonialsForm({
|
|
15631
15872
|
isEdit: true,
|
|
15632
15873
|
user: user ? {
|
|
@@ -15638,7 +15879,7 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
|
|
|
15638
15879
|
messageType: "error"
|
|
15639
15880
|
}));
|
|
15640
15881
|
}
|
|
15641
|
-
const { results } = await
|
|
15882
|
+
const { results } = await db2.prepare(`
|
|
15642
15883
|
UPDATE testimonials
|
|
15643
15884
|
SET author_name = ?, author_title = ?, author_company = ?, testimonial_text = ?, rating = ?, isPublished = ?, sortOrder = ?
|
|
15644
15885
|
WHERE id = ?
|
|
@@ -15683,7 +15924,7 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
|
|
|
15683
15924
|
const id = parseInt(c.req.param("id"));
|
|
15684
15925
|
if (error instanceof zod.z.ZodError) {
|
|
15685
15926
|
const errors = {};
|
|
15686
|
-
error.
|
|
15927
|
+
error.issues.forEach((err) => {
|
|
15687
15928
|
const field = err.path[0];
|
|
15688
15929
|
if (!errors[field]) errors[field] = [];
|
|
15689
15930
|
errors[field].push(err.message);
|
|
@@ -15735,11 +15976,11 @@ adminTestimonialsRoutes.put("/:id", async (c) => {
|
|
|
15735
15976
|
adminTestimonialsRoutes.delete("/:id", async (c) => {
|
|
15736
15977
|
try {
|
|
15737
15978
|
const id = parseInt(c.req.param("id"));
|
|
15738
|
-
const
|
|
15739
|
-
if (!
|
|
15979
|
+
const db2 = c.env?.DB;
|
|
15980
|
+
if (!db2) {
|
|
15740
15981
|
return c.json({ error: "Database not available" }, 500);
|
|
15741
15982
|
}
|
|
15742
|
-
const { changes } = await
|
|
15983
|
+
const { changes } = await db2.prepare("DELETE FROM testimonials WHERE id = ?").bind(id).run();
|
|
15743
15984
|
if (changes === 0) {
|
|
15744
15985
|
return c.json({ error: "Testimonial not found" }, 404);
|
|
15745
15986
|
}
|
|
@@ -16071,8 +16312,8 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
16071
16312
|
const currentPage = parseInt(page, 10) || 1;
|
|
16072
16313
|
const limit = 20;
|
|
16073
16314
|
const offset = (currentPage - 1) * limit;
|
|
16074
|
-
const
|
|
16075
|
-
if (!
|
|
16315
|
+
const db2 = c.env?.DB;
|
|
16316
|
+
if (!db2) {
|
|
16076
16317
|
return c.html(chunkYU6QFFI4_cjs.renderCodeExamplesList({
|
|
16077
16318
|
codeExamples: [],
|
|
16078
16319
|
totalCount: 0,
|
|
@@ -16103,7 +16344,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
16103
16344
|
params.push(searchTerm, searchTerm, searchTerm, searchTerm);
|
|
16104
16345
|
}
|
|
16105
16346
|
const countQuery = `SELECT COUNT(*) as count FROM code_examples ${whereClause}`;
|
|
16106
|
-
const { results: countResults } = await
|
|
16347
|
+
const { results: countResults } = await db2.prepare(countQuery).bind(...params).all();
|
|
16107
16348
|
const totalCount = countResults?.[0]?.count || 0;
|
|
16108
16349
|
const dataQuery = `
|
|
16109
16350
|
SELECT * FROM code_examples
|
|
@@ -16111,7 +16352,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
16111
16352
|
ORDER BY sortOrder ASC, created_at DESC
|
|
16112
16353
|
LIMIT ? OFFSET ?
|
|
16113
16354
|
`;
|
|
16114
|
-
const { results: codeExamples } = await
|
|
16355
|
+
const { results: codeExamples } = await db2.prepare(dataQuery).bind(...params, limit, offset).all();
|
|
16115
16356
|
const totalPages = Math.ceil(totalCount / limit);
|
|
16116
16357
|
return c.html(chunkYU6QFFI4_cjs.renderCodeExamplesList({
|
|
16117
16358
|
codeExamples: codeExamples || [],
|
|
@@ -16159,8 +16400,8 @@ adminCodeExamplesRoutes.post("/", async (c) => {
|
|
|
16159
16400
|
const data = Object.fromEntries(formData.entries());
|
|
16160
16401
|
const validatedData = codeExampleSchema.parse(data);
|
|
16161
16402
|
const user = c.get("user");
|
|
16162
|
-
const
|
|
16163
|
-
if (!
|
|
16403
|
+
const db2 = c.env?.DB;
|
|
16404
|
+
if (!db2) {
|
|
16164
16405
|
return c.html(renderCodeExamplesForm({
|
|
16165
16406
|
isEdit: false,
|
|
16166
16407
|
user: user ? {
|
|
@@ -16172,7 +16413,7 @@ adminCodeExamplesRoutes.post("/", async (c) => {
|
|
|
16172
16413
|
messageType: "error"
|
|
16173
16414
|
}));
|
|
16174
16415
|
}
|
|
16175
|
-
const { results } = await
|
|
16416
|
+
const { results } = await db2.prepare(`
|
|
16176
16417
|
INSERT INTO code_examples (title, description, code, language, category, tags, isPublished, sortOrder)
|
|
16177
16418
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
16178
16419
|
RETURNING *
|
|
@@ -16205,7 +16446,7 @@ adminCodeExamplesRoutes.post("/", async (c) => {
|
|
|
16205
16446
|
const user = c.get("user");
|
|
16206
16447
|
if (error instanceof zod.z.ZodError) {
|
|
16207
16448
|
const errors = {};
|
|
16208
|
-
error.
|
|
16449
|
+
error.issues.forEach((err) => {
|
|
16209
16450
|
const field = err.path[0];
|
|
16210
16451
|
if (!errors[field]) errors[field] = [];
|
|
16211
16452
|
errors[field].push(err.message);
|
|
@@ -16238,8 +16479,8 @@ adminCodeExamplesRoutes.get("/:id", async (c) => {
|
|
|
16238
16479
|
try {
|
|
16239
16480
|
const id = parseInt(c.req.param("id"));
|
|
16240
16481
|
const user = c.get("user");
|
|
16241
|
-
const
|
|
16242
|
-
if (!
|
|
16482
|
+
const db2 = c.env?.DB;
|
|
16483
|
+
if (!db2) {
|
|
16243
16484
|
return c.html(renderCodeExamplesForm({
|
|
16244
16485
|
isEdit: true,
|
|
16245
16486
|
user: user ? {
|
|
@@ -16251,7 +16492,7 @@ adminCodeExamplesRoutes.get("/:id", async (c) => {
|
|
|
16251
16492
|
messageType: "error"
|
|
16252
16493
|
}));
|
|
16253
16494
|
}
|
|
16254
|
-
const { results } = await
|
|
16495
|
+
const { results } = await db2.prepare("SELECT * FROM code_examples WHERE id = ?").bind(id).all();
|
|
16255
16496
|
if (!results || results.length === 0) {
|
|
16256
16497
|
return c.redirect("/admin/code-examples?message=Code example not found&type=error");
|
|
16257
16498
|
}
|
|
@@ -16297,8 +16538,8 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
|
|
|
16297
16538
|
const data = Object.fromEntries(formData.entries());
|
|
16298
16539
|
const validatedData = codeExampleSchema.parse(data);
|
|
16299
16540
|
const user = c.get("user");
|
|
16300
|
-
const
|
|
16301
|
-
if (!
|
|
16541
|
+
const db2 = c.env?.DB;
|
|
16542
|
+
if (!db2) {
|
|
16302
16543
|
return c.html(renderCodeExamplesForm({
|
|
16303
16544
|
isEdit: true,
|
|
16304
16545
|
user: user ? {
|
|
@@ -16310,7 +16551,7 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
|
|
|
16310
16551
|
messageType: "error"
|
|
16311
16552
|
}));
|
|
16312
16553
|
}
|
|
16313
|
-
const { results } = await
|
|
16554
|
+
const { results } = await db2.prepare(`
|
|
16314
16555
|
UPDATE code_examples
|
|
16315
16556
|
SET title = ?, description = ?, code = ?, language = ?, category = ?, tags = ?, isPublished = ?, sortOrder = ?
|
|
16316
16557
|
WHERE id = ?
|
|
@@ -16357,7 +16598,7 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
|
|
|
16357
16598
|
const id = parseInt(c.req.param("id"));
|
|
16358
16599
|
if (error instanceof zod.z.ZodError) {
|
|
16359
16600
|
const errors = {};
|
|
16360
|
-
error.
|
|
16601
|
+
error.issues.forEach((err) => {
|
|
16361
16602
|
const field = err.path[0];
|
|
16362
16603
|
if (!errors[field]) errors[field] = [];
|
|
16363
16604
|
errors[field].push(err.message);
|
|
@@ -16411,11 +16652,11 @@ adminCodeExamplesRoutes.put("/:id", async (c) => {
|
|
|
16411
16652
|
adminCodeExamplesRoutes.delete("/:id", async (c) => {
|
|
16412
16653
|
try {
|
|
16413
16654
|
const id = parseInt(c.req.param("id"));
|
|
16414
|
-
const
|
|
16415
|
-
if (!
|
|
16655
|
+
const db2 = c.env?.DB;
|
|
16656
|
+
if (!db2) {
|
|
16416
16657
|
return c.json({ error: "Database not available" }, 500);
|
|
16417
16658
|
}
|
|
16418
|
-
const { changes } = await
|
|
16659
|
+
const { changes } = await db2.prepare("DELETE FROM code_examples WHERE id = ?").bind(id).run();
|
|
16419
16660
|
if (changes === 0) {
|
|
16420
16661
|
return c.json({ error: "Code example not found" }, 404);
|
|
16421
16662
|
}
|
|
@@ -17064,9 +17305,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
|
|
|
17064
17305
|
}
|
|
17065
17306
|
|
|
17066
17307
|
// src/routes/admin-dashboard.ts
|
|
17067
|
-
var VERSION =
|
|
17308
|
+
var VERSION = chunk2HRF65VF_cjs.getCoreVersion();
|
|
17068
17309
|
var router = new hono.Hono();
|
|
17069
|
-
router.use("*",
|
|
17310
|
+
router.use("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
17070
17311
|
router.get("/", async (c) => {
|
|
17071
17312
|
const user = c.get("user");
|
|
17072
17313
|
try {
|
|
@@ -17094,10 +17335,10 @@ router.get("/", async (c) => {
|
|
|
17094
17335
|
});
|
|
17095
17336
|
router.get("/stats", async (c) => {
|
|
17096
17337
|
try {
|
|
17097
|
-
const
|
|
17338
|
+
const db2 = c.env.DB;
|
|
17098
17339
|
let collectionsCount = 0;
|
|
17099
17340
|
try {
|
|
17100
|
-
const collectionsStmt =
|
|
17341
|
+
const collectionsStmt = db2.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
|
|
17101
17342
|
const collectionsResult = await collectionsStmt.first();
|
|
17102
17343
|
collectionsCount = collectionsResult?.count || 0;
|
|
17103
17344
|
} catch (error) {
|
|
@@ -17105,7 +17346,7 @@ router.get("/stats", async (c) => {
|
|
|
17105
17346
|
}
|
|
17106
17347
|
let contentCount = 0;
|
|
17107
17348
|
try {
|
|
17108
|
-
const contentStmt =
|
|
17349
|
+
const contentStmt = db2.prepare("SELECT COUNT(*) as count FROM content");
|
|
17109
17350
|
const contentResult = await contentStmt.first();
|
|
17110
17351
|
contentCount = contentResult?.count || 0;
|
|
17111
17352
|
} catch (error) {
|
|
@@ -17114,7 +17355,7 @@ router.get("/stats", async (c) => {
|
|
|
17114
17355
|
let mediaCount = 0;
|
|
17115
17356
|
let mediaSize = 0;
|
|
17116
17357
|
try {
|
|
17117
|
-
const mediaStmt =
|
|
17358
|
+
const mediaStmt = db2.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
|
|
17118
17359
|
const mediaResult = await mediaStmt.first();
|
|
17119
17360
|
mediaCount = mediaResult?.count || 0;
|
|
17120
17361
|
mediaSize = mediaResult?.total_size || 0;
|
|
@@ -17123,7 +17364,7 @@ router.get("/stats", async (c) => {
|
|
|
17123
17364
|
}
|
|
17124
17365
|
let usersCount = 0;
|
|
17125
17366
|
try {
|
|
17126
|
-
const usersStmt =
|
|
17367
|
+
const usersStmt = db2.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
|
|
17127
17368
|
const usersResult = await usersStmt.first();
|
|
17128
17369
|
usersCount = usersResult?.count || 0;
|
|
17129
17370
|
} catch (error) {
|
|
@@ -17144,17 +17385,17 @@ router.get("/stats", async (c) => {
|
|
|
17144
17385
|
});
|
|
17145
17386
|
router.get("/storage", async (c) => {
|
|
17146
17387
|
try {
|
|
17147
|
-
const
|
|
17388
|
+
const db2 = c.env.DB;
|
|
17148
17389
|
let databaseSize = 0;
|
|
17149
17390
|
try {
|
|
17150
|
-
const result = await
|
|
17391
|
+
const result = await db2.prepare("SELECT 1").run();
|
|
17151
17392
|
databaseSize = result?.meta?.size_after || 0;
|
|
17152
17393
|
} catch (error) {
|
|
17153
17394
|
console.error("Error fetching database size:", error);
|
|
17154
17395
|
}
|
|
17155
17396
|
let mediaSize = 0;
|
|
17156
17397
|
try {
|
|
17157
|
-
const mediaStmt =
|
|
17398
|
+
const mediaStmt = db2.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
|
|
17158
17399
|
const mediaResult = await mediaStmt.first();
|
|
17159
17400
|
mediaSize = mediaResult?.total_size || 0;
|
|
17160
17401
|
} catch (error) {
|
|
@@ -17169,9 +17410,9 @@ router.get("/storage", async (c) => {
|
|
|
17169
17410
|
});
|
|
17170
17411
|
router.get("/recent-activity", async (c) => {
|
|
17171
17412
|
try {
|
|
17172
|
-
const
|
|
17413
|
+
const db2 = c.env.DB;
|
|
17173
17414
|
const limit = parseInt(c.req.query("limit") || "5");
|
|
17174
|
-
const activityStmt =
|
|
17415
|
+
const activityStmt = db2.prepare(`
|
|
17175
17416
|
SELECT
|
|
17176
17417
|
a.id,
|
|
17177
17418
|
a.action,
|
|
@@ -17775,7 +18016,7 @@ function getFieldTypeBadge(fieldType) {
|
|
|
17775
18016
|
"text": "Text",
|
|
17776
18017
|
"richtext": "Rich Text (TinyMCE)",
|
|
17777
18018
|
"quill": "Rich Text (Quill)",
|
|
17778
|
-
"mdxeditor": "
|
|
18019
|
+
"mdxeditor": "EasyMDX",
|
|
17779
18020
|
"number": "Number",
|
|
17780
18021
|
"boolean": "Boolean",
|
|
17781
18022
|
"date": "Date",
|
|
@@ -17798,6 +18039,7 @@ function getFieldTypeBadge(fieldType) {
|
|
|
17798
18039
|
return `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ${color} ring-1 ring-inset">${label}</span>`;
|
|
17799
18040
|
}
|
|
17800
18041
|
function renderCollectionFormPage(data) {
|
|
18042
|
+
console.log("[renderCollectionFormPage] editorPlugins:", data.editorPlugins);
|
|
17801
18043
|
const isEdit = data.isEdit || !!data.id;
|
|
17802
18044
|
const title = isEdit ? "Edit Collection" : "Create New Collection";
|
|
17803
18045
|
const subtitle = isEdit ? `Update collection: ${data.display_name}` : "Define a new content collection with custom fields and settings.";
|
|
@@ -18262,7 +18504,7 @@ function renderCollectionFormPage(data) {
|
|
|
18262
18504
|
<option value="text">Text</option>
|
|
18263
18505
|
${data.editorPlugins?.tinymce ? '<option value="richtext">Rich Text (TinyMCE)</option>' : ""}
|
|
18264
18506
|
${data.editorPlugins?.quill ? '<option value="quill">Rich Text (Quill)</option>' : ""}
|
|
18265
|
-
${data.editorPlugins?.
|
|
18507
|
+
${data.editorPlugins?.easyMdx ? '<option value="mdxeditor">EasyMDX</option>' : ""}
|
|
18266
18508
|
<option value="number">Number</option>
|
|
18267
18509
|
<option value="boolean">Boolean</option>
|
|
18268
18510
|
<option value="date">Date</option>
|
|
@@ -18484,12 +18726,13 @@ function renderCollectionFormPage(data) {
|
|
|
18484
18726
|
|
|
18485
18727
|
// Check if it's a schema field with field_options that might indicate the actual type
|
|
18486
18728
|
if (field.field_options && typeof field.field_options === 'object') {
|
|
18487
|
-
//
|
|
18488
|
-
if
|
|
18729
|
+
// Only convert to richtext if type is explicitly 'string' and format is richtext
|
|
18730
|
+
// Don't convert if it's already a specific editor type like 'mdxeditor', 'quill', etc.
|
|
18731
|
+
if (field.field_options.format === 'richtext' && uiFieldType === 'string') {
|
|
18489
18732
|
uiFieldType = 'richtext';
|
|
18490
18733
|
}
|
|
18491
18734
|
// Check for other format indicators
|
|
18492
|
-
else if (field.field_options.type) {
|
|
18735
|
+
else if (field.field_options.type && !uiFieldType) {
|
|
18493
18736
|
uiFieldType = field.field_options.type;
|
|
18494
18737
|
}
|
|
18495
18738
|
}
|
|
@@ -18505,8 +18748,60 @@ function renderCollectionFormPage(data) {
|
|
|
18505
18748
|
uiFieldType = typeMapping[uiFieldType];
|
|
18506
18749
|
}
|
|
18507
18750
|
|
|
18751
|
+
// Log all available options
|
|
18752
|
+
const availableOptions = Array.from(fieldTypeSelect.options).map(opt => ({ value: opt.value, text: opt.text }));
|
|
18753
|
+
console.log('Available dropdown options:', availableOptions);
|
|
18754
|
+
console.log('Trying to set field-type to:', uiFieldType);
|
|
18755
|
+
|
|
18756
|
+
// Clear any existing selections first
|
|
18757
|
+
Array.from(fieldTypeSelect.options).forEach(opt => opt.selected = false);
|
|
18758
|
+
|
|
18759
|
+
// Try multiple approaches to set the value
|
|
18760
|
+
let selectionSucceeded = false;
|
|
18761
|
+
|
|
18762
|
+
// Approach 1: Direct value assignment
|
|
18508
18763
|
fieldTypeSelect.value = uiFieldType;
|
|
18509
|
-
|
|
18764
|
+
if (fieldTypeSelect.value === uiFieldType) {
|
|
18765
|
+
selectionSucceeded = true;
|
|
18766
|
+
console.log('\u2713 Approach 1 (direct value) succeeded');
|
|
18767
|
+
}
|
|
18768
|
+
|
|
18769
|
+
// Approach 2: Find and select the specific option
|
|
18770
|
+
if (!selectionSucceeded) {
|
|
18771
|
+
console.log('Approach 1 failed, trying approach 2 (direct option selection)');
|
|
18772
|
+
const optionToSelect = Array.from(fieldTypeSelect.options).find(opt => opt.value === uiFieldType);
|
|
18773
|
+
if (optionToSelect) {
|
|
18774
|
+
optionToSelect.selected = true;
|
|
18775
|
+
// Trigger change event
|
|
18776
|
+
fieldTypeSelect.dispatchEvent(new Event('change', { bubbles: true }));
|
|
18777
|
+
if (fieldTypeSelect.value === uiFieldType) {
|
|
18778
|
+
selectionSucceeded = true;
|
|
18779
|
+
console.log('\u2713 Approach 2 (option.selected) succeeded');
|
|
18780
|
+
}
|
|
18781
|
+
}
|
|
18782
|
+
}
|
|
18783
|
+
|
|
18784
|
+
// Approach 3: Set selectedIndex
|
|
18785
|
+
if (!selectionSucceeded) {
|
|
18786
|
+
console.log('Approach 2 failed, trying approach 3 (selectedIndex)');
|
|
18787
|
+
const optionIndex = Array.from(fieldTypeSelect.options).findIndex(opt => opt.value === uiFieldType);
|
|
18788
|
+
if (optionIndex !== -1) {
|
|
18789
|
+
fieldTypeSelect.selectedIndex = optionIndex;
|
|
18790
|
+
if (fieldTypeSelect.value === uiFieldType) {
|
|
18791
|
+
selectionSucceeded = true;
|
|
18792
|
+
console.log('\u2713 Approach 3 (selectedIndex) succeeded');
|
|
18793
|
+
}
|
|
18794
|
+
}
|
|
18795
|
+
}
|
|
18796
|
+
|
|
18797
|
+
console.log('Final field-type value:', fieldTypeSelect.value, '(wanted:', uiFieldType, ')');
|
|
18798
|
+
|
|
18799
|
+
if (!selectionSucceeded) {
|
|
18800
|
+
console.error('\u274C All approaches failed to set field-type!');
|
|
18801
|
+
console.error('Wanted:', uiFieldType);
|
|
18802
|
+
console.error('Got:', fieldTypeSelect.value);
|
|
18803
|
+
console.error('Available options:', availableOptions);
|
|
18804
|
+
}
|
|
18510
18805
|
} else {
|
|
18511
18806
|
console.error('field-type select not found!');
|
|
18512
18807
|
}
|
|
@@ -18577,9 +18872,15 @@ function renderCollectionFormPage(data) {
|
|
|
18577
18872
|
setTimeout(() => {
|
|
18578
18873
|
isEditingField = false;
|
|
18579
18874
|
console.log('Cleared isEditingField flag');
|
|
18580
|
-
}, 100);
|
|
18581
18875
|
|
|
18582
|
-
|
|
18876
|
+
// Double-check the field-type value after the flag is cleared
|
|
18877
|
+
const finalCheck = document.getElementById('field-type');
|
|
18878
|
+
if (finalCheck) {
|
|
18879
|
+
console.log('Post-flag-clear check - field-type value:', finalCheck.value);
|
|
18880
|
+
}
|
|
18881
|
+
}, 200); // Increased delay
|
|
18882
|
+
|
|
18883
|
+
}, 50); // Increased delay to ensure modal is fully rendered
|
|
18583
18884
|
}
|
|
18584
18885
|
|
|
18585
18886
|
function closeFieldModal() {
|
|
@@ -18760,17 +19061,17 @@ function renderCollectionFormPage(data) {
|
|
|
18760
19061
|
|
|
18761
19062
|
// src/routes/admin-collections.ts
|
|
18762
19063
|
var adminCollectionsRoutes = new hono.Hono();
|
|
18763
|
-
adminCollectionsRoutes.use("*",
|
|
19064
|
+
adminCollectionsRoutes.use("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
18764
19065
|
adminCollectionsRoutes.get("/", async (c) => {
|
|
18765
19066
|
try {
|
|
18766
19067
|
const user = c.get("user");
|
|
18767
|
-
const
|
|
19068
|
+
const db2 = c.env.DB;
|
|
18768
19069
|
const url = new URL(c.req.url);
|
|
18769
19070
|
const search = url.searchParams.get("search") || "";
|
|
18770
19071
|
let stmt;
|
|
18771
19072
|
let results;
|
|
18772
19073
|
if (search) {
|
|
18773
|
-
stmt =
|
|
19074
|
+
stmt = db2.prepare(`
|
|
18774
19075
|
SELECT id, name, display_name, description, created_at, managed, schema
|
|
18775
19076
|
FROM collections
|
|
18776
19077
|
WHERE is_active = 1
|
|
@@ -18781,11 +19082,11 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
18781
19082
|
const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all();
|
|
18782
19083
|
results = queryResults.results;
|
|
18783
19084
|
} else {
|
|
18784
|
-
stmt =
|
|
19085
|
+
stmt = db2.prepare("SELECT id, name, display_name, description, created_at, managed, schema FROM collections WHERE is_active = 1 ORDER BY created_at DESC");
|
|
18785
19086
|
const queryResults = await stmt.all();
|
|
18786
19087
|
results = queryResults.results;
|
|
18787
19088
|
}
|
|
18788
|
-
const fieldCountStmt =
|
|
19089
|
+
const fieldCountStmt = db2.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
|
|
18789
19090
|
const { results: fieldCountResults } = await fieldCountStmt.all();
|
|
18790
19091
|
const fieldCounts = new Map((fieldCountResults || []).map((row) => [String(row.collection_id), Number(row.count)]));
|
|
18791
19092
|
const collections = (results || []).filter((row) => row && row.id).map((row) => {
|
|
@@ -18826,21 +19127,22 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
18826
19127
|
return c.html(renderCollectionsListPage(pageData));
|
|
18827
19128
|
} catch (error) {
|
|
18828
19129
|
console.error("Error fetching collections:", error);
|
|
18829
|
-
|
|
19130
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
19131
|
+
return c.html(html.html`<p>Error loading collections: ${errorMessage}</p>`);
|
|
18830
19132
|
}
|
|
18831
19133
|
});
|
|
18832
19134
|
adminCollectionsRoutes.get("/new", async (c) => {
|
|
18833
19135
|
const user = c.get("user");
|
|
18834
|
-
const
|
|
19136
|
+
const db2 = c.env.DB;
|
|
18835
19137
|
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
18836
|
-
isPluginActive2(
|
|
18837
|
-
isPluginActive2(
|
|
18838
|
-
isPluginActive2(
|
|
19138
|
+
isPluginActive2(db2, "tinymce-plugin"),
|
|
19139
|
+
isPluginActive2(db2, "quill-editor"),
|
|
19140
|
+
isPluginActive2(db2, "easy-mdx")
|
|
18839
19141
|
]);
|
|
18840
19142
|
console.log("[Collections /new] Editor plugins status:", {
|
|
18841
19143
|
tinymce: tinymceActive,
|
|
18842
19144
|
quill: quillActive,
|
|
18843
|
-
|
|
19145
|
+
easyMdx: mdxeditorActive
|
|
18844
19146
|
});
|
|
18845
19147
|
const formData = {
|
|
18846
19148
|
isEdit: false,
|
|
@@ -18853,7 +19155,7 @@ adminCollectionsRoutes.get("/new", async (c) => {
|
|
|
18853
19155
|
editorPlugins: {
|
|
18854
19156
|
tinymce: tinymceActive,
|
|
18855
19157
|
quill: quillActive,
|
|
18856
|
-
|
|
19158
|
+
easyMdx: mdxeditorActive
|
|
18857
19159
|
}
|
|
18858
19160
|
};
|
|
18859
19161
|
return c.html(renderCollectionFormPage(formData));
|
|
@@ -18889,8 +19191,8 @@ adminCollectionsRoutes.post("/", async (c) => {
|
|
|
18889
19191
|
return c.redirect("/admin/collections/new");
|
|
18890
19192
|
}
|
|
18891
19193
|
}
|
|
18892
|
-
const
|
|
18893
|
-
const existingStmt =
|
|
19194
|
+
const db2 = c.env.DB;
|
|
19195
|
+
const existingStmt = db2.prepare("SELECT id FROM collections WHERE name = ?");
|
|
18894
19196
|
const existing = await existingStmt.bind(name).first();
|
|
18895
19197
|
if (existing) {
|
|
18896
19198
|
const errorMsg = "A collection with this name already exists.";
|
|
@@ -18926,9 +19228,9 @@ adminCollectionsRoutes.post("/", async (c) => {
|
|
|
18926
19228
|
},
|
|
18927
19229
|
required: ["title"]
|
|
18928
19230
|
};
|
|
18929
|
-
const collectionId =
|
|
19231
|
+
const collectionId = crypto.randomUUID();
|
|
18930
19232
|
const now = Date.now();
|
|
18931
|
-
const insertStmt =
|
|
19233
|
+
const insertStmt = db2.prepare(`
|
|
18932
19234
|
INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)
|
|
18933
19235
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
18934
19236
|
`);
|
|
@@ -18983,10 +19285,15 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
18983
19285
|
try {
|
|
18984
19286
|
const id = c.req.param("id");
|
|
18985
19287
|
const user = c.get("user");
|
|
18986
|
-
const
|
|
18987
|
-
const stmt =
|
|
19288
|
+
const db2 = c.env.DB;
|
|
19289
|
+
const stmt = db2.prepare("SELECT * FROM collections WHERE id = ?");
|
|
18988
19290
|
const collection = await stmt.bind(id).first();
|
|
18989
19291
|
if (!collection) {
|
|
19292
|
+
const [tinymceActive2, quillActive2, mdxeditorActive2] = await Promise.all([
|
|
19293
|
+
isPluginActive2(db2, "tinymce-plugin"),
|
|
19294
|
+
isPluginActive2(db2, "quill-editor"),
|
|
19295
|
+
isPluginActive2(db2, "easy-mdx")
|
|
19296
|
+
]);
|
|
18990
19297
|
const formData2 = {
|
|
18991
19298
|
isEdit: true,
|
|
18992
19299
|
error: "Collection not found.",
|
|
@@ -18995,7 +19302,12 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
18995
19302
|
email: user.email,
|
|
18996
19303
|
role: user.role
|
|
18997
19304
|
} : void 0,
|
|
18998
|
-
version: c.get("appVersion")
|
|
19305
|
+
version: c.get("appVersion"),
|
|
19306
|
+
editorPlugins: {
|
|
19307
|
+
tinymce: tinymceActive2,
|
|
19308
|
+
quill: quillActive2,
|
|
19309
|
+
easyMdx: mdxeditorActive2
|
|
19310
|
+
}
|
|
18999
19311
|
};
|
|
19000
19312
|
return c.html(renderCollectionFormPage(formData2));
|
|
19001
19313
|
}
|
|
@@ -19021,28 +19333,44 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
19021
19333
|
}
|
|
19022
19334
|
}
|
|
19023
19335
|
if (fields.length === 0) {
|
|
19024
|
-
const fieldsStmt =
|
|
19336
|
+
const fieldsStmt = db2.prepare(`
|
|
19025
19337
|
SELECT * FROM content_fields
|
|
19026
19338
|
WHERE collection_id = ?
|
|
19027
19339
|
ORDER BY field_order ASC
|
|
19028
19340
|
`);
|
|
19029
19341
|
const { results: fieldsResults } = await fieldsStmt.bind(id).all();
|
|
19030
|
-
fields = (fieldsResults || []).map((row) =>
|
|
19031
|
-
|
|
19032
|
-
|
|
19033
|
-
|
|
19034
|
-
|
|
19035
|
-
|
|
19036
|
-
|
|
19037
|
-
|
|
19038
|
-
|
|
19039
|
-
|
|
19342
|
+
fields = (fieldsResults || []).map((row) => {
|
|
19343
|
+
let fieldOptions = {};
|
|
19344
|
+
if (row.field_options) {
|
|
19345
|
+
try {
|
|
19346
|
+
fieldOptions = typeof row.field_options === "string" ? JSON.parse(row.field_options) : row.field_options;
|
|
19347
|
+
} catch (e) {
|
|
19348
|
+
console.error("Error parsing field_options for field:", row.field_name, e);
|
|
19349
|
+
fieldOptions = {};
|
|
19350
|
+
}
|
|
19351
|
+
}
|
|
19352
|
+
return {
|
|
19353
|
+
id: row.id,
|
|
19354
|
+
field_name: row.field_name,
|
|
19355
|
+
field_type: row.field_type,
|
|
19356
|
+
field_label: row.field_label,
|
|
19357
|
+
field_options: fieldOptions,
|
|
19358
|
+
field_order: row.field_order,
|
|
19359
|
+
is_required: row.is_required === 1,
|
|
19360
|
+
is_searchable: row.is_searchable === 1
|
|
19361
|
+
};
|
|
19362
|
+
});
|
|
19040
19363
|
}
|
|
19041
19364
|
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
19042
|
-
isPluginActive2(
|
|
19043
|
-
isPluginActive2(
|
|
19044
|
-
isPluginActive2(
|
|
19365
|
+
isPluginActive2(db2, "tinymce-plugin"),
|
|
19366
|
+
isPluginActive2(db2, "quill-editor"),
|
|
19367
|
+
isPluginActive2(db2, "easy-mdx")
|
|
19045
19368
|
]);
|
|
19369
|
+
console.log("[Collections /:id] Editor plugins status:", {
|
|
19370
|
+
tinymce: tinymceActive,
|
|
19371
|
+
quill: quillActive,
|
|
19372
|
+
easyMdx: mdxeditorActive
|
|
19373
|
+
});
|
|
19046
19374
|
const formData = {
|
|
19047
19375
|
id: collection.id,
|
|
19048
19376
|
name: collection.name,
|
|
@@ -19060,13 +19388,18 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
19060
19388
|
editorPlugins: {
|
|
19061
19389
|
tinymce: tinymceActive,
|
|
19062
19390
|
quill: quillActive,
|
|
19063
|
-
|
|
19391
|
+
easyMdx: mdxeditorActive
|
|
19064
19392
|
}
|
|
19065
19393
|
};
|
|
19066
19394
|
return c.html(renderCollectionFormPage(formData));
|
|
19067
19395
|
} catch (error) {
|
|
19068
19396
|
console.error("Error fetching collection:", error);
|
|
19069
19397
|
const user = c.get("user");
|
|
19398
|
+
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
19399
|
+
isPluginActive2(db, "tinymce-plugin"),
|
|
19400
|
+
isPluginActive2(db, "quill-editor"),
|
|
19401
|
+
isPluginActive2(db, "easy-mdx")
|
|
19402
|
+
]);
|
|
19070
19403
|
const formData = {
|
|
19071
19404
|
isEdit: true,
|
|
19072
19405
|
error: "Failed to load collection.",
|
|
@@ -19075,7 +19408,12 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
19075
19408
|
email: user.email,
|
|
19076
19409
|
role: user.role
|
|
19077
19410
|
} : void 0,
|
|
19078
|
-
version: c.get("appVersion")
|
|
19411
|
+
version: c.get("appVersion"),
|
|
19412
|
+
editorPlugins: {
|
|
19413
|
+
tinymce: tinymceActive,
|
|
19414
|
+
quill: quillActive,
|
|
19415
|
+
easyMdx: mdxeditorActive
|
|
19416
|
+
}
|
|
19079
19417
|
};
|
|
19080
19418
|
return c.html(renderCollectionFormPage(formData));
|
|
19081
19419
|
}
|
|
@@ -19093,8 +19431,8 @@ adminCollectionsRoutes.put("/:id", async (c) => {
|
|
|
19093
19431
|
</div>
|
|
19094
19432
|
`);
|
|
19095
19433
|
}
|
|
19096
|
-
const
|
|
19097
|
-
const updateStmt =
|
|
19434
|
+
const db2 = c.env.DB;
|
|
19435
|
+
const updateStmt = db2.prepare(`
|
|
19098
19436
|
UPDATE collections
|
|
19099
19437
|
SET display_name = ?, description = ?, updated_at = ?
|
|
19100
19438
|
WHERE id = ?
|
|
@@ -19117,8 +19455,8 @@ adminCollectionsRoutes.put("/:id", async (c) => {
|
|
|
19117
19455
|
adminCollectionsRoutes.delete("/:id", async (c) => {
|
|
19118
19456
|
try {
|
|
19119
19457
|
const id = c.req.param("id");
|
|
19120
|
-
const
|
|
19121
|
-
const contentStmt =
|
|
19458
|
+
const db2 = c.env.DB;
|
|
19459
|
+
const contentStmt = db2.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
|
|
19122
19460
|
const contentResult = await contentStmt.bind(id).first();
|
|
19123
19461
|
if (contentResult && contentResult.count > 0) {
|
|
19124
19462
|
return c.html(html.html`
|
|
@@ -19127,9 +19465,9 @@ adminCollectionsRoutes.delete("/:id", async (c) => {
|
|
|
19127
19465
|
</div>
|
|
19128
19466
|
`);
|
|
19129
19467
|
}
|
|
19130
|
-
const deleteFieldsStmt =
|
|
19468
|
+
const deleteFieldsStmt = db2.prepare("DELETE FROM content_fields WHERE collection_id = ?");
|
|
19131
19469
|
await deleteFieldsStmt.bind(id).run();
|
|
19132
|
-
const deleteStmt =
|
|
19470
|
+
const deleteStmt = db2.prepare("DELETE FROM collections WHERE id = ?");
|
|
19133
19471
|
await deleteStmt.bind(id).run();
|
|
19134
19472
|
return c.html(html.html`
|
|
19135
19473
|
<script>
|
|
@@ -19161,18 +19499,18 @@ adminCollectionsRoutes.post("/:id/fields", async (c) => {
|
|
|
19161
19499
|
if (!/^[a-z0-9_]+$/.test(fieldName)) {
|
|
19162
19500
|
return c.json({ success: false, error: "Field name must contain only lowercase letters, numbers, and underscores." });
|
|
19163
19501
|
}
|
|
19164
|
-
const
|
|
19165
|
-
const existingStmt =
|
|
19502
|
+
const db2 = c.env.DB;
|
|
19503
|
+
const existingStmt = db2.prepare("SELECT id FROM content_fields WHERE collection_id = ? AND field_name = ?");
|
|
19166
19504
|
const existing = await existingStmt.bind(collectionId, fieldName).first();
|
|
19167
19505
|
if (existing) {
|
|
19168
19506
|
return c.json({ success: false, error: "A field with this name already exists." });
|
|
19169
19507
|
}
|
|
19170
|
-
const orderStmt =
|
|
19508
|
+
const orderStmt = db2.prepare("SELECT MAX(field_order) as max_order FROM content_fields WHERE collection_id = ?");
|
|
19171
19509
|
const orderResult = await orderStmt.bind(collectionId).first();
|
|
19172
19510
|
const nextOrder = (orderResult?.max_order || 0) + 1;
|
|
19173
|
-
const fieldId =
|
|
19511
|
+
const fieldId = crypto.randomUUID();
|
|
19174
19512
|
const now = Date.now();
|
|
19175
|
-
const insertStmt =
|
|
19513
|
+
const insertStmt = db2.prepare(`
|
|
19176
19514
|
INSERT INTO content_fields (
|
|
19177
19515
|
id, collection_id, field_name, field_type, field_label,
|
|
19178
19516
|
field_options, field_order, is_required, is_searchable,
|
|
@@ -19221,11 +19559,11 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19221
19559
|
if (!fieldLabel) {
|
|
19222
19560
|
return c.json({ success: false, error: "Field label is required." });
|
|
19223
19561
|
}
|
|
19224
|
-
const
|
|
19562
|
+
const db2 = c.env.DB;
|
|
19225
19563
|
if (fieldId.startsWith("schema-")) {
|
|
19226
19564
|
const fieldName = fieldId.replace("schema-", "");
|
|
19227
19565
|
console.log("[Field Update] Updating schema field:", fieldName);
|
|
19228
|
-
const getCollectionStmt =
|
|
19566
|
+
const getCollectionStmt = db2.prepare("SELECT * FROM collections WHERE id = ?");
|
|
19229
19567
|
const collection = await getCollectionStmt.bind(collectionId).first();
|
|
19230
19568
|
if (!collection) {
|
|
19231
19569
|
return c.json({ success: false, error: "Collection not found." });
|
|
@@ -19270,7 +19608,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19270
19608
|
console.log("[Field Update] Final required array:", schema.required);
|
|
19271
19609
|
console.log("[Field Update] Final field config:", schema.properties[fieldName]);
|
|
19272
19610
|
}
|
|
19273
|
-
const updateCollectionStmt =
|
|
19611
|
+
const updateCollectionStmt = db2.prepare(`
|
|
19274
19612
|
UPDATE collections
|
|
19275
19613
|
SET schema = ?, updated_at = ?
|
|
19276
19614
|
WHERE id = ?
|
|
@@ -19282,7 +19620,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19282
19620
|
});
|
|
19283
19621
|
return c.json({ success: true });
|
|
19284
19622
|
}
|
|
19285
|
-
const updateStmt =
|
|
19623
|
+
const updateStmt = db2.prepare(`
|
|
19286
19624
|
UPDATE content_fields
|
|
19287
19625
|
SET field_label = ?, field_type = ?, field_options = ?, is_required = ?, is_searchable = ?, updated_at = ?
|
|
19288
19626
|
WHERE id = ?
|
|
@@ -19294,7 +19632,7 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19294
19632
|
changes: result.meta?.changes,
|
|
19295
19633
|
last_row_id: result.meta?.last_row_id
|
|
19296
19634
|
});
|
|
19297
|
-
const verifyStmt =
|
|
19635
|
+
const verifyStmt = db2.prepare("SELECT * FROM content_fields WHERE id = ?");
|
|
19298
19636
|
const verifyResult = await verifyStmt.bind(fieldId).first();
|
|
19299
19637
|
console.log("[Field Update] Verification - field after update:", verifyResult);
|
|
19300
19638
|
console.log("[Field Update] Successfully updated field with type:", fieldType);
|
|
@@ -19307,8 +19645,8 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
|
19307
19645
|
adminCollectionsRoutes.delete("/:collectionId/fields/:fieldId", async (c) => {
|
|
19308
19646
|
try {
|
|
19309
19647
|
const fieldId = c.req.param("fieldId");
|
|
19310
|
-
const
|
|
19311
|
-
const deleteStmt =
|
|
19648
|
+
const db2 = c.env.DB;
|
|
19649
|
+
const deleteStmt = db2.prepare("DELETE FROM content_fields WHERE id = ?");
|
|
19312
19650
|
await deleteStmt.bind(fieldId).run();
|
|
19313
19651
|
return c.json({ success: true });
|
|
19314
19652
|
} catch (error) {
|
|
@@ -19323,9 +19661,9 @@ adminCollectionsRoutes.post("/:collectionId/fields/reorder", async (c) => {
|
|
|
19323
19661
|
if (!Array.isArray(fieldIds)) {
|
|
19324
19662
|
return c.json({ success: false, error: "Invalid field order data." });
|
|
19325
19663
|
}
|
|
19326
|
-
const
|
|
19664
|
+
const db2 = c.env.DB;
|
|
19327
19665
|
for (let i = 0; i < fieldIds.length; i++) {
|
|
19328
|
-
const updateStmt =
|
|
19666
|
+
const updateStmt = db2.prepare("UPDATE content_fields SET field_order = ?, updated_at = ? WHERE id = ?");
|
|
19329
19667
|
await updateStmt.bind(i + 1, Date.now(), fieldIds[i]).run();
|
|
19330
19668
|
}
|
|
19331
19669
|
return c.json({ success: true });
|
|
@@ -20784,7 +21122,7 @@ function renderDatabaseToolsSettings(settings) {
|
|
|
20784
21122
|
|
|
20785
21123
|
// src/routes/admin-settings.ts
|
|
20786
21124
|
var adminSettingsRoutes = new hono.Hono();
|
|
20787
|
-
adminSettingsRoutes.use("*",
|
|
21125
|
+
adminSettingsRoutes.use("*", chunkF4IGVB2V_cjs.requireAuth());
|
|
20788
21126
|
function getMockSettings(user) {
|
|
20789
21127
|
return {
|
|
20790
21128
|
general: {
|
|
@@ -20848,8 +21186,8 @@ adminSettingsRoutes.get("/", (c) => {
|
|
|
20848
21186
|
});
|
|
20849
21187
|
adminSettingsRoutes.get("/general", async (c) => {
|
|
20850
21188
|
const user = c.get("user");
|
|
20851
|
-
const
|
|
20852
|
-
const settingsService = new
|
|
21189
|
+
const db2 = c.env.DB;
|
|
21190
|
+
const settingsService = new chunk3F4LF7LW_cjs.SettingsService(db2);
|
|
20853
21191
|
const generalSettings = await settingsService.getGeneralSettings(user?.email);
|
|
20854
21192
|
const mockSettings = getMockSettings(user);
|
|
20855
21193
|
mockSettings.general = generalSettings;
|
|
@@ -20951,8 +21289,8 @@ adminSettingsRoutes.get("/database-tools", (c) => {
|
|
|
20951
21289
|
});
|
|
20952
21290
|
adminSettingsRoutes.get("/api/migrations/status", async (c) => {
|
|
20953
21291
|
try {
|
|
20954
|
-
const
|
|
20955
|
-
const migrationService = new
|
|
21292
|
+
const db2 = c.env.DB;
|
|
21293
|
+
const migrationService = new chunkRDJ2QLA2_cjs.MigrationService(db2);
|
|
20956
21294
|
const status = await migrationService.getMigrationStatus();
|
|
20957
21295
|
return c.json({
|
|
20958
21296
|
success: true,
|
|
@@ -20975,8 +21313,8 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
20975
21313
|
error: "Unauthorized. Admin access required."
|
|
20976
21314
|
}, 403);
|
|
20977
21315
|
}
|
|
20978
|
-
const
|
|
20979
|
-
const migrationService = new
|
|
21316
|
+
const db2 = c.env.DB;
|
|
21317
|
+
const migrationService = new chunkRDJ2QLA2_cjs.MigrationService(db2);
|
|
20980
21318
|
const result = await migrationService.runPendingMigrations();
|
|
20981
21319
|
return c.json({
|
|
20982
21320
|
success: result.success,
|
|
@@ -20993,8 +21331,8 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
20993
21331
|
});
|
|
20994
21332
|
adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
20995
21333
|
try {
|
|
20996
|
-
const
|
|
20997
|
-
const migrationService = new
|
|
21334
|
+
const db2 = c.env.DB;
|
|
21335
|
+
const migrationService = new chunkRDJ2QLA2_cjs.MigrationService(db2);
|
|
20998
21336
|
const validation = await migrationService.validateSchema();
|
|
20999
21337
|
return c.json({
|
|
21000
21338
|
success: true,
|
|
@@ -21010,8 +21348,8 @@ adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
|
21010
21348
|
});
|
|
21011
21349
|
adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
|
|
21012
21350
|
try {
|
|
21013
|
-
const
|
|
21014
|
-
const tablesQuery = await
|
|
21351
|
+
const db2 = c.env.DB;
|
|
21352
|
+
const tablesQuery = await db2.prepare(`
|
|
21015
21353
|
SELECT name FROM sqlite_master
|
|
21016
21354
|
WHERE type='table'
|
|
21017
21355
|
AND name NOT LIKE 'sqlite_%'
|
|
@@ -21023,7 +21361,7 @@ adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
|
|
|
21023
21361
|
const tableStats = await Promise.all(
|
|
21024
21362
|
tables.map(async (table) => {
|
|
21025
21363
|
try {
|
|
21026
|
-
const countResult = await
|
|
21364
|
+
const countResult = await db2.prepare(`SELECT COUNT(*) as count FROM ${table.name}`).first();
|
|
21027
21365
|
const rowCount = countResult?.count || 0;
|
|
21028
21366
|
totalRows += rowCount;
|
|
21029
21367
|
return {
|
|
@@ -21060,8 +21398,8 @@ adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
|
|
|
21060
21398
|
});
|
|
21061
21399
|
adminSettingsRoutes.get("/api/database-tools/validate", async (c) => {
|
|
21062
21400
|
try {
|
|
21063
|
-
const
|
|
21064
|
-
const integrityResult = await
|
|
21401
|
+
const db2 = c.env.DB;
|
|
21402
|
+
const integrityResult = await db2.prepare("PRAGMA integrity_check").first();
|
|
21065
21403
|
const isValid = integrityResult?.integrity_check === "ok";
|
|
21066
21404
|
return c.json({
|
|
21067
21405
|
success: true,
|
|
@@ -21116,11 +21454,11 @@ adminSettingsRoutes.post("/api/database-tools/truncate", async (c) => {
|
|
|
21116
21454
|
error: "No tables specified for truncation"
|
|
21117
21455
|
}, 400);
|
|
21118
21456
|
}
|
|
21119
|
-
const
|
|
21457
|
+
const db2 = c.env.DB;
|
|
21120
21458
|
const results = [];
|
|
21121
21459
|
for (const tableName of tablesToTruncate) {
|
|
21122
21460
|
try {
|
|
21123
|
-
await
|
|
21461
|
+
await db2.prepare(`DELETE FROM ${tableName}`).run();
|
|
21124
21462
|
results.push({ table: tableName, success: true });
|
|
21125
21463
|
} catch (error) {
|
|
21126
21464
|
console.error(`Error truncating ${tableName}:`, error);
|
|
@@ -21150,8 +21488,8 @@ adminSettingsRoutes.post("/general", async (c) => {
|
|
|
21150
21488
|
}, 403);
|
|
21151
21489
|
}
|
|
21152
21490
|
const formData = await c.req.formData();
|
|
21153
|
-
const
|
|
21154
|
-
const settingsService = new
|
|
21491
|
+
const db2 = c.env.DB;
|
|
21492
|
+
const settingsService = new chunk3F4LF7LW_cjs.SettingsService(db2);
|
|
21155
21493
|
const settings = {
|
|
21156
21494
|
siteName: formData.get("siteName"),
|
|
21157
21495
|
siteDescription: formData.get("siteDescription"),
|
|
@@ -21200,6 +21538,7 @@ var ROUTES_INFO = {
|
|
|
21200
21538
|
"apiSystemRoutes",
|
|
21201
21539
|
"adminApiRoutes",
|
|
21202
21540
|
"authRoutes",
|
|
21541
|
+
"testCleanupRoutes",
|
|
21203
21542
|
"adminContentRoutes",
|
|
21204
21543
|
"adminUsersRoutes",
|
|
21205
21544
|
"adminMediaRoutes",
|
|
@@ -21236,6 +21575,7 @@ exports.api_media_default = api_media_default;
|
|
|
21236
21575
|
exports.api_system_default = api_system_default;
|
|
21237
21576
|
exports.auth_default = auth_default;
|
|
21238
21577
|
exports.router = router;
|
|
21578
|
+
exports.test_cleanup_default = test_cleanup_default;
|
|
21239
21579
|
exports.userRoutes = userRoutes;
|
|
21240
|
-
//# sourceMappingURL=chunk-
|
|
21241
|
-
//# sourceMappingURL=chunk-
|
|
21580
|
+
//# sourceMappingURL=chunk-K5WUGEXH.cjs.map
|
|
21581
|
+
//# sourceMappingURL=chunk-K5WUGEXH.cjs.map
|