@sonicjs-cms/core 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-O46XKBFM.js → chunk-3LZ6TLPC.js} +14 -24
- package/dist/chunk-3LZ6TLPC.js.map +1 -0
- package/dist/{chunk-SRCY43RN.cjs → chunk-3NVJ6W27.cjs} +2 -2
- package/dist/chunk-3NVJ6W27.cjs.map +1 -0
- package/dist/{chunk-ALOS2CBJ.cjs → chunk-3SPQ3J4N.cjs} +14 -24
- package/dist/chunk-3SPQ3J4N.cjs.map +1 -0
- package/dist/chunk-4BJGEGX5.cjs +236 -0
- package/dist/chunk-4BJGEGX5.cjs.map +1 -0
- package/dist/{chunk-EGFHFM4N.cjs → chunk-5APKEYFK.cjs} +5 -5
- package/dist/{chunk-EGFHFM4N.cjs.map → chunk-5APKEYFK.cjs.map} +1 -1
- package/dist/{chunk-5FDDDD4J.cjs → chunk-5B3VMVEX.cjs} +559 -390
- package/dist/chunk-5B3VMVEX.cjs.map +1 -0
- package/dist/chunk-CDBVZEWR.js.map +1 -1
- package/dist/{chunk-BITQ4MFX.js → chunk-EAELJXRV.js} +93 -115
- package/dist/chunk-EAELJXRV.js.map +1 -0
- package/dist/chunk-FICTAGD4.js +59 -0
- package/dist/chunk-FICTAGD4.js.map +1 -0
- package/dist/{chunk-FVMV5DKA.cjs → chunk-HJZOA2O5.cjs} +93 -115
- package/dist/chunk-HJZOA2O5.cjs.map +1 -0
- package/dist/chunk-LEG4KNFP.cjs.map +1 -1
- package/dist/{chunk-5XTB4FE5.js → chunk-LH4Z7QID.js} +2 -2
- package/dist/chunk-LH4Z7QID.js.map +1 -0
- package/dist/chunk-M6FPVS7E.js +214 -0
- package/dist/chunk-M6FPVS7E.js.map +1 -0
- package/dist/{chunk-QSF34IYQ.js → chunk-PPUKPNTP.js} +401 -232
- package/dist/chunk-PPUKPNTP.js.map +1 -0
- package/dist/chunk-RCQ2HIQD.cjs +61 -0
- package/dist/chunk-RCQ2HIQD.cjs.map +1 -0
- package/dist/{chunk-P2PTTBO5.js → chunk-RYQCT2IV.js} +3 -3
- package/dist/{chunk-P2PTTBO5.js.map → chunk-RYQCT2IV.js.map} +1 -1
- package/dist/{chunk-NK6FN5R5.cjs → chunk-UL32L2KV.cjs} +3 -60
- package/dist/chunk-UL32L2KV.cjs.map +1 -0
- package/dist/{chunk-OL2OE3VJ.js → chunk-XJETEIRU.js} +4 -60
- package/dist/chunk-XJETEIRU.js.map +1 -0
- package/dist/index.cjs +145 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +19 -15
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +26 -21
- package/dist/middleware.js +2 -1
- package/dist/plugins.cjs +7 -7
- package/dist/plugins.js +1 -1
- package/dist/routes.cjs +26 -25
- package/dist/routes.js +6 -5
- package/dist/services.cjs +7 -7
- package/dist/services.js +1 -1
- package/dist/templates.cjs +18 -18
- package/dist/templates.js +2 -2
- package/dist/utils.cjs +16 -15
- package/dist/utils.js +2 -1
- package/package.json +1 -1
- package/dist/chunk-5FDDDD4J.cjs.map +0 -1
- package/dist/chunk-5XTB4FE5.js.map +0 -1
- package/dist/chunk-ALOS2CBJ.cjs.map +0 -1
- package/dist/chunk-BITQ4MFX.js.map +0 -1
- package/dist/chunk-FVMV5DKA.cjs.map +0 -1
- package/dist/chunk-KM4AJFXI.cjs +0 -101
- package/dist/chunk-KM4AJFXI.cjs.map +0 -1
- package/dist/chunk-NK6FN5R5.cjs.map +0 -1
- package/dist/chunk-O46XKBFM.js.map +0 -1
- package/dist/chunk-OL2OE3VJ.js.map +0 -1
- package/dist/chunk-QSF34IYQ.js.map +0 -1
- package/dist/chunk-SRCY43RN.cjs.map +0 -1
- package/dist/chunk-TY3NHEBN.js +0 -80
- package/dist/chunk-TY3NHEBN.js.map +0 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunk3NVJ6W27_cjs = require('./chunk-3NVJ6W27.cjs');
|
|
4
|
+
var chunk4BJGEGX5_cjs = require('./chunk-4BJGEGX5.cjs');
|
|
5
5
|
var chunkLEG4KNFP_cjs = require('./chunk-LEG4KNFP.cjs');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var chunk3SPQ3J4N_cjs = require('./chunk-3SPQ3J4N.cjs');
|
|
7
|
+
var chunkUL32L2KV_cjs = require('./chunk-UL32L2KV.cjs');
|
|
8
|
+
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
8
9
|
var hono = require('hono');
|
|
9
10
|
var cors = require('hono/cors');
|
|
10
11
|
var zod = require('zod');
|
|
@@ -42,7 +43,7 @@ apiContentCrudRoutes.get("/:id", async (c) => {
|
|
|
42
43
|
}, 500);
|
|
43
44
|
}
|
|
44
45
|
});
|
|
45
|
-
apiContentCrudRoutes.post("/",
|
|
46
|
+
apiContentCrudRoutes.post("/", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
46
47
|
try {
|
|
47
48
|
const db = c.env.DB;
|
|
48
49
|
const user = c.get("user");
|
|
@@ -83,7 +84,7 @@ apiContentCrudRoutes.post("/", chunkKM4AJFXI_cjs.requireAuth(), async (c) => {
|
|
|
83
84
|
now,
|
|
84
85
|
now
|
|
85
86
|
).run();
|
|
86
|
-
const cache =
|
|
87
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
|
|
87
88
|
await cache.invalidate(`content:list:${collectionId}:*`);
|
|
88
89
|
await cache.invalidate("content-filtered:*");
|
|
89
90
|
const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
@@ -108,7 +109,7 @@ apiContentCrudRoutes.post("/", chunkKM4AJFXI_cjs.requireAuth(), async (c) => {
|
|
|
108
109
|
}, 500);
|
|
109
110
|
}
|
|
110
111
|
});
|
|
111
|
-
apiContentCrudRoutes.put("/:id",
|
|
112
|
+
apiContentCrudRoutes.put("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
112
113
|
try {
|
|
113
114
|
const id = c.req.param("id");
|
|
114
115
|
const db = c.env.DB;
|
|
@@ -146,7 +147,7 @@ apiContentCrudRoutes.put("/:id", chunkKM4AJFXI_cjs.requireAuth(), async (c) => {
|
|
|
146
147
|
WHERE id = ?
|
|
147
148
|
`);
|
|
148
149
|
await updateStmt.bind(...params).run();
|
|
149
|
-
const cache =
|
|
150
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
|
|
150
151
|
await cache.delete(cache.generateKey("content", id));
|
|
151
152
|
await cache.invalidate(`content:list:${existing.collection_id}:*`);
|
|
152
153
|
await cache.invalidate("content-filtered:*");
|
|
@@ -172,7 +173,7 @@ apiContentCrudRoutes.put("/:id", chunkKM4AJFXI_cjs.requireAuth(), async (c) => {
|
|
|
172
173
|
}, 500);
|
|
173
174
|
}
|
|
174
175
|
});
|
|
175
|
-
apiContentCrudRoutes.delete("/:id",
|
|
176
|
+
apiContentCrudRoutes.delete("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
176
177
|
try {
|
|
177
178
|
const id = c.req.param("id");
|
|
178
179
|
const db = c.env.DB;
|
|
@@ -183,7 +184,7 @@ apiContentCrudRoutes.delete("/:id", chunkKM4AJFXI_cjs.requireAuth(), async (c) =
|
|
|
183
184
|
}
|
|
184
185
|
const deleteStmt = db.prepare("DELETE FROM content WHERE id = ?");
|
|
185
186
|
await deleteStmt.bind(id).run();
|
|
186
|
-
const cache =
|
|
187
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
|
|
187
188
|
await cache.delete(cache.generateKey("content", id));
|
|
188
189
|
await cache.invalidate(`content:list:${existing.collection_id}:*`);
|
|
189
190
|
await cache.invalidate("content-filtered:*");
|
|
@@ -208,7 +209,7 @@ apiRoutes.use("*", async (c, next) => {
|
|
|
208
209
|
c.header("X-Response-Time", `${totalTime}ms`);
|
|
209
210
|
});
|
|
210
211
|
apiRoutes.use("*", async (c, next) => {
|
|
211
|
-
const cacheEnabled = await
|
|
212
|
+
const cacheEnabled = await chunk4BJGEGX5_cjs.isPluginActive(c.env.DB, "core-cache");
|
|
212
213
|
c.set("cacheEnabled", cacheEnabled);
|
|
213
214
|
await next();
|
|
214
215
|
});
|
|
@@ -256,7 +257,7 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
256
257
|
try {
|
|
257
258
|
const db = c.env.DB;
|
|
258
259
|
const cacheEnabled = c.get("cacheEnabled");
|
|
259
|
-
const cache =
|
|
260
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
|
|
260
261
|
const cacheKey = cache.generateKey("collections", "all");
|
|
261
262
|
if (cacheEnabled) {
|
|
262
263
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -333,12 +334,12 @@ apiRoutes.get("/content", async (c) => {
|
|
|
333
334
|
});
|
|
334
335
|
}
|
|
335
336
|
}
|
|
336
|
-
const filter =
|
|
337
|
+
const filter = chunkUL32L2KV_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
337
338
|
if (!filter.limit) {
|
|
338
339
|
filter.limit = 50;
|
|
339
340
|
}
|
|
340
341
|
filter.limit = Math.min(filter.limit, 1e3);
|
|
341
|
-
const builder = new
|
|
342
|
+
const builder = new chunkUL32L2KV_cjs.QueryFilterBuilder();
|
|
342
343
|
const queryResult = builder.build("content", filter);
|
|
343
344
|
if (queryResult.errors.length > 0) {
|
|
344
345
|
return c.json({
|
|
@@ -347,7 +348,7 @@ apiRoutes.get("/content", async (c) => {
|
|
|
347
348
|
}, 400);
|
|
348
349
|
}
|
|
349
350
|
const cacheEnabled = c.get("cacheEnabled");
|
|
350
|
-
const cache =
|
|
351
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
|
|
351
352
|
const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter, query: queryResult.sql }));
|
|
352
353
|
if (cacheEnabled) {
|
|
353
354
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -425,7 +426,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
425
426
|
if (!collectionResult) {
|
|
426
427
|
return c.json({ error: "Collection not found" }, 404);
|
|
427
428
|
}
|
|
428
|
-
const filter =
|
|
429
|
+
const filter = chunkUL32L2KV_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
429
430
|
if (!filter.where) {
|
|
430
431
|
filter.where = { and: [] };
|
|
431
432
|
}
|
|
@@ -441,7 +442,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
441
442
|
filter.limit = 50;
|
|
442
443
|
}
|
|
443
444
|
filter.limit = Math.min(filter.limit, 1e3);
|
|
444
|
-
const builder = new
|
|
445
|
+
const builder = new chunkUL32L2KV_cjs.QueryFilterBuilder();
|
|
445
446
|
const queryResult = builder.build("content", filter);
|
|
446
447
|
if (queryResult.errors.length > 0) {
|
|
447
448
|
return c.json({
|
|
@@ -450,7 +451,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
450
451
|
}, 400);
|
|
451
452
|
}
|
|
452
453
|
const cacheEnabled = c.get("cacheEnabled");
|
|
453
|
-
const cache =
|
|
454
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.api);
|
|
454
455
|
const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter, query: queryResult.sql })}`);
|
|
455
456
|
if (cacheEnabled) {
|
|
456
457
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -566,7 +567,7 @@ var fileValidationSchema = zod.z.object({
|
|
|
566
567
|
// 50MB max
|
|
567
568
|
});
|
|
568
569
|
var apiMediaRoutes = new hono.Hono();
|
|
569
|
-
apiMediaRoutes.use("*",
|
|
570
|
+
apiMediaRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
570
571
|
apiMediaRoutes.post("/upload", async (c) => {
|
|
571
572
|
try {
|
|
572
573
|
const user = c.get("user");
|
|
@@ -1301,8 +1302,8 @@ apiSystemRoutes.get("/env", (c) => {
|
|
|
1301
1302
|
});
|
|
1302
1303
|
var api_system_default = apiSystemRoutes;
|
|
1303
1304
|
var adminApiRoutes = new hono.Hono();
|
|
1304
|
-
adminApiRoutes.use("*",
|
|
1305
|
-
adminApiRoutes.use("*",
|
|
1305
|
+
adminApiRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
1306
|
+
adminApiRoutes.use("*", chunk4BJGEGX5_cjs.requireRole(["admin", "editor"]));
|
|
1306
1307
|
adminApiRoutes.get("/stats", async (c) => {
|
|
1307
1308
|
try {
|
|
1308
1309
|
const db = c.env.DB;
|
|
@@ -1754,8 +1755,8 @@ function renderLoginPage(data, demoLoginActive = false) {
|
|
|
1754
1755
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
1755
1756
|
<div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
|
|
1756
1757
|
<!-- Alerts -->
|
|
1757
|
-
${data.error ? `<div class="mb-6">${
|
|
1758
|
-
${data.message ? `<div class="mb-6">${
|
|
1758
|
+
${data.error ? `<div class="mb-6">${chunk3SPQ3J4N_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
|
|
1759
|
+
${data.message ? `<div class="mb-6">${chunk3SPQ3J4N_cjs.renderAlert({ type: "success", message: data.message })}</div>` : ""}
|
|
1759
1760
|
|
|
1760
1761
|
<!-- Form Response (HTMX target) -->
|
|
1761
1762
|
<div id="form-response" class="mb-6"></div>
|
|
@@ -1919,7 +1920,7 @@ function renderRegisterPage(data) {
|
|
|
1919
1920
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
1920
1921
|
<div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
|
|
1921
1922
|
<!-- Alerts -->
|
|
1922
|
-
${data.error ? `<div class="mb-6">${
|
|
1923
|
+
${data.error ? `<div class="mb-6">${chunk3SPQ3J4N_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
|
|
1923
1924
|
|
|
1924
1925
|
<!-- Form -->
|
|
1925
1926
|
<form
|
|
@@ -2032,9 +2033,36 @@ function renderRegisterPage(data) {
|
|
|
2032
2033
|
</html>
|
|
2033
2034
|
`;
|
|
2034
2035
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2036
|
+
var authValidationService = {
|
|
2037
|
+
/**
|
|
2038
|
+
* Build registration schema dynamically based on auth settings
|
|
2039
|
+
* For now, returns a static schema with standard fields
|
|
2040
|
+
*/
|
|
2041
|
+
async buildRegistrationSchema(_db) {
|
|
2042
|
+
return zod.z.object({
|
|
2043
|
+
email: zod.z.string().email("Valid email is required"),
|
|
2044
|
+
password: zod.z.string().min(8, "Password must be at least 8 characters"),
|
|
2045
|
+
username: zod.z.string().min(3, "Username must be at least 3 characters").optional(),
|
|
2046
|
+
firstName: zod.z.string().min(1, "First name is required").optional(),
|
|
2047
|
+
lastName: zod.z.string().min(1, "Last name is required").optional()
|
|
2048
|
+
});
|
|
2049
|
+
},
|
|
2050
|
+
/**
|
|
2051
|
+
* Generate default values for optional fields
|
|
2052
|
+
*/
|
|
2053
|
+
generateDefaultValue(field, data) {
|
|
2054
|
+
switch (field) {
|
|
2055
|
+
case "username":
|
|
2056
|
+
return data.email ? data.email.split("@")[0] : `user${Date.now()}`;
|
|
2057
|
+
case "firstName":
|
|
2058
|
+
return "User";
|
|
2059
|
+
case "lastName":
|
|
2060
|
+
return data.email ? data.email.split("@")[0] : "Account";
|
|
2061
|
+
default:
|
|
2062
|
+
return "";
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
};
|
|
2038
2066
|
|
|
2039
2067
|
// src/routes/auth.ts
|
|
2040
2068
|
var authRoutes = new hono.Hono();
|
|
@@ -2091,7 +2119,7 @@ authRoutes.post(
|
|
|
2091
2119
|
if (existingUser) {
|
|
2092
2120
|
return c.json({ error: "User with this email or username already exists" }, 400);
|
|
2093
2121
|
}
|
|
2094
|
-
const passwordHash = await
|
|
2122
|
+
const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
|
|
2095
2123
|
const userId = crypto.randomUUID();
|
|
2096
2124
|
const now = /* @__PURE__ */ new Date();
|
|
2097
2125
|
await db.prepare(`
|
|
@@ -2111,7 +2139,7 @@ authRoutes.post(
|
|
|
2111
2139
|
now.getTime(),
|
|
2112
2140
|
now.getTime()
|
|
2113
2141
|
).run();
|
|
2114
|
-
const token = await
|
|
2142
|
+
const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer");
|
|
2115
2143
|
cookie.setCookie(c, "auth_token", token, {
|
|
2116
2144
|
httpOnly: true,
|
|
2117
2145
|
secure: true,
|
|
@@ -2146,7 +2174,7 @@ authRoutes.post("/login", async (c) => {
|
|
|
2146
2174
|
const { email, password } = validation.data;
|
|
2147
2175
|
const db = c.env.DB;
|
|
2148
2176
|
const normalizedEmail = email.toLowerCase();
|
|
2149
|
-
const cache =
|
|
2177
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.user);
|
|
2150
2178
|
let user = await cache.get(cache.generateKey("user", `email:${normalizedEmail}`));
|
|
2151
2179
|
if (!user) {
|
|
2152
2180
|
user = await db.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
|
|
@@ -2158,11 +2186,11 @@ authRoutes.post("/login", async (c) => {
|
|
|
2158
2186
|
if (!user) {
|
|
2159
2187
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2160
2188
|
}
|
|
2161
|
-
const isValidPassword = await
|
|
2189
|
+
const isValidPassword = await chunk4BJGEGX5_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2162
2190
|
if (!isValidPassword) {
|
|
2163
2191
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2164
2192
|
}
|
|
2165
|
-
const token = await
|
|
2193
|
+
const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2166
2194
|
cookie.setCookie(c, "auth_token", token, {
|
|
2167
2195
|
httpOnly: true,
|
|
2168
2196
|
secure: true,
|
|
@@ -2211,7 +2239,7 @@ authRoutes.get("/logout", (c) => {
|
|
|
2211
2239
|
});
|
|
2212
2240
|
return c.redirect("/auth/login?message=You have been logged out successfully");
|
|
2213
2241
|
});
|
|
2214
|
-
authRoutes.get("/me",
|
|
2242
|
+
authRoutes.get("/me", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
2215
2243
|
try {
|
|
2216
2244
|
const user = c.get("user");
|
|
2217
2245
|
if (!user) {
|
|
@@ -2228,13 +2256,13 @@ authRoutes.get("/me", chunkKM4AJFXI_cjs.requireAuth(), async (c) => {
|
|
|
2228
2256
|
return c.json({ error: "Failed to get user" }, 500);
|
|
2229
2257
|
}
|
|
2230
2258
|
});
|
|
2231
|
-
authRoutes.post("/refresh",
|
|
2259
|
+
authRoutes.post("/refresh", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
2232
2260
|
try {
|
|
2233
2261
|
const user = c.get("user");
|
|
2234
2262
|
if (!user) {
|
|
2235
2263
|
return c.json({ error: "Not authenticated" }, 401);
|
|
2236
2264
|
}
|
|
2237
|
-
const token = await
|
|
2265
|
+
const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(user.userId, user.email, user.role);
|
|
2238
2266
|
cookie.setCookie(c, "auth_token", token, {
|
|
2239
2267
|
httpOnly: true,
|
|
2240
2268
|
secure: true,
|
|
@@ -2284,7 +2312,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2284
2312
|
</div>
|
|
2285
2313
|
`);
|
|
2286
2314
|
}
|
|
2287
|
-
const passwordHash = await
|
|
2315
|
+
const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
|
|
2288
2316
|
const userId = crypto.randomUUID();
|
|
2289
2317
|
const now = /* @__PURE__ */ new Date();
|
|
2290
2318
|
await db.prepare(`
|
|
@@ -2304,7 +2332,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2304
2332
|
now.getTime(),
|
|
2305
2333
|
now.getTime()
|
|
2306
2334
|
).run();
|
|
2307
|
-
const token = await
|
|
2335
|
+
const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(userId, normalizedEmail, "admin");
|
|
2308
2336
|
cookie.setCookie(c, "auth_token", token, {
|
|
2309
2337
|
httpOnly: true,
|
|
2310
2338
|
secure: false,
|
|
@@ -2355,7 +2383,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2355
2383
|
</div>
|
|
2356
2384
|
`);
|
|
2357
2385
|
}
|
|
2358
|
-
const isValidPassword = await
|
|
2386
|
+
const isValidPassword = await chunk4BJGEGX5_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2359
2387
|
if (!isValidPassword) {
|
|
2360
2388
|
return c.html(html.html`
|
|
2361
2389
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2363,7 +2391,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2363
2391
|
</div>
|
|
2364
2392
|
`);
|
|
2365
2393
|
}
|
|
2366
|
-
const token = await
|
|
2394
|
+
const token = await chunk4BJGEGX5_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2367
2395
|
cookie.setCookie(c, "auth_token", token, {
|
|
2368
2396
|
httpOnly: true,
|
|
2369
2397
|
secure: false,
|
|
@@ -2432,7 +2460,7 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2432
2460
|
}
|
|
2433
2461
|
});
|
|
2434
2462
|
}
|
|
2435
|
-
const passwordHash = await
|
|
2463
|
+
const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword("admin123");
|
|
2436
2464
|
const userId = "admin-user-id";
|
|
2437
2465
|
const now = Date.now();
|
|
2438
2466
|
const adminEmail = "admin@sonicjs.com".toLowerCase();
|
|
@@ -2652,7 +2680,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2652
2680
|
if (existingUsername) {
|
|
2653
2681
|
return c.json({ error: "Username is already taken" }, 400);
|
|
2654
2682
|
}
|
|
2655
|
-
const passwordHash = await
|
|
2683
|
+
const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
|
|
2656
2684
|
const updateStmt = db.prepare(`
|
|
2657
2685
|
UPDATE users SET
|
|
2658
2686
|
username = ?,
|
|
@@ -2671,7 +2699,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2671
2699
|
Date.now(),
|
|
2672
2700
|
invitedUser.id
|
|
2673
2701
|
).run();
|
|
2674
|
-
const authToken = await
|
|
2702
|
+
const authToken = await chunk4BJGEGX5_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role);
|
|
2675
2703
|
cookie.setCookie(c, "auth_token", authToken, {
|
|
2676
2704
|
httpOnly: true,
|
|
2677
2705
|
secure: true,
|
|
@@ -2901,7 +2929,7 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
2901
2929
|
if (Date.now() > user.password_reset_expires) {
|
|
2902
2930
|
return c.json({ error: "Reset token has expired" }, 400);
|
|
2903
2931
|
}
|
|
2904
|
-
const newPasswordHash = await
|
|
2932
|
+
const newPasswordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
|
|
2905
2933
|
try {
|
|
2906
2934
|
const historyStmt = db.prepare(`
|
|
2907
2935
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
@@ -2938,7 +2966,7 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
2938
2966
|
var auth_default = authRoutes;
|
|
2939
2967
|
|
|
2940
2968
|
// src/templates/pages/admin-content-form.template.ts
|
|
2941
|
-
|
|
2969
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
2942
2970
|
|
|
2943
2971
|
// src/templates/components/dynamic-field.template.ts
|
|
2944
2972
|
function renderDynamicField(field, options = {}) {
|
|
@@ -3342,8 +3370,8 @@ function renderContentFormPage(data) {
|
|
|
3342
3370
|
<!-- Form Content -->
|
|
3343
3371
|
<div class="px-6 py-6">
|
|
3344
3372
|
<div id="form-messages">
|
|
3345
|
-
${data.error ?
|
|
3346
|
-
${data.success ?
|
|
3373
|
+
${data.error ? chunk3SPQ3J4N_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
3374
|
+
${data.success ? chunk3SPQ3J4N_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
3347
3375
|
</div>
|
|
3348
3376
|
|
|
3349
3377
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
@@ -3578,7 +3606,7 @@ function renderContentFormPage(data) {
|
|
|
3578
3606
|
</div>
|
|
3579
3607
|
|
|
3580
3608
|
<!-- Confirmation Dialogs -->
|
|
3581
|
-
${
|
|
3609
|
+
${chunk3SPQ3J4N_cjs.renderConfirmationDialog({
|
|
3582
3610
|
id: "duplicate-content-confirm",
|
|
3583
3611
|
title: "Duplicate Content",
|
|
3584
3612
|
message: "Create a copy of this content?",
|
|
@@ -3589,7 +3617,7 @@ function renderContentFormPage(data) {
|
|
|
3589
3617
|
onConfirm: "performDuplicateContent()"
|
|
3590
3618
|
})}
|
|
3591
3619
|
|
|
3592
|
-
${
|
|
3620
|
+
${chunk3SPQ3J4N_cjs.renderConfirmationDialog({
|
|
3593
3621
|
id: "delete-content-confirm",
|
|
3594
3622
|
title: "Delete Content",
|
|
3595
3623
|
message: "Are you sure you want to delete this content? This action cannot be undone.",
|
|
@@ -3600,7 +3628,7 @@ function renderContentFormPage(data) {
|
|
|
3600
3628
|
onConfirm: `performDeleteContent('${data.id}')`
|
|
3601
3629
|
})}
|
|
3602
3630
|
|
|
3603
|
-
${
|
|
3631
|
+
${chunk3SPQ3J4N_cjs.getConfirmationDialogScript()}
|
|
3604
3632
|
|
|
3605
3633
|
<!-- TinyMCE CDN -->
|
|
3606
3634
|
<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/6/tinymce.min.js" referrerpolicy="origin"></script>
|
|
@@ -3888,11 +3916,11 @@ function renderContentFormPage(data) {
|
|
|
3888
3916
|
content: pageContent,
|
|
3889
3917
|
version: data.version
|
|
3890
3918
|
};
|
|
3891
|
-
return
|
|
3919
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
3892
3920
|
}
|
|
3893
3921
|
|
|
3894
3922
|
// src/templates/pages/admin-content-list.template.ts
|
|
3895
|
-
|
|
3923
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
3896
3924
|
function renderContentListPage(data) {
|
|
3897
3925
|
const urlParams = new URLSearchParams();
|
|
3898
3926
|
if (data.modelName && data.modelName !== "all") urlParams.set("model", data.modelName);
|
|
@@ -4288,8 +4316,8 @@ function renderContentListPage(data) {
|
|
|
4288
4316
|
|
|
4289
4317
|
<!-- Content List -->
|
|
4290
4318
|
<div id="content-list">
|
|
4291
|
-
${
|
|
4292
|
-
${
|
|
4319
|
+
${chunk3SPQ3J4N_cjs.renderTable(tableData)}
|
|
4320
|
+
${chunk3SPQ3J4N_cjs.renderPagination(paginationData)}
|
|
4293
4321
|
</div>
|
|
4294
4322
|
|
|
4295
4323
|
</div>
|
|
@@ -4498,7 +4526,7 @@ function renderContentListPage(data) {
|
|
|
4498
4526
|
</script>
|
|
4499
4527
|
|
|
4500
4528
|
<!-- Confirmation Dialog for Bulk Actions -->
|
|
4501
|
-
${
|
|
4529
|
+
${chunk3SPQ3J4N_cjs.renderConfirmationDialog({
|
|
4502
4530
|
id: "bulk-action-confirm",
|
|
4503
4531
|
title: "Confirm Bulk Action",
|
|
4504
4532
|
message: "Are you sure you want to perform this action? This operation will affect multiple items.",
|
|
@@ -4510,7 +4538,7 @@ function renderContentListPage(data) {
|
|
|
4510
4538
|
})}
|
|
4511
4539
|
|
|
4512
4540
|
<!-- Confirmation Dialog Script -->
|
|
4513
|
-
${
|
|
4541
|
+
${chunk3SPQ3J4N_cjs.getConfirmationDialogScript()}
|
|
4514
4542
|
`;
|
|
4515
4543
|
const layoutData = {
|
|
4516
4544
|
title: "Content Management",
|
|
@@ -4520,7 +4548,7 @@ function renderContentListPage(data) {
|
|
|
4520
4548
|
version: data.version,
|
|
4521
4549
|
content: pageContent
|
|
4522
4550
|
};
|
|
4523
|
-
return
|
|
4551
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
4524
4552
|
}
|
|
4525
4553
|
|
|
4526
4554
|
// src/templates/components/version-history.template.ts
|
|
@@ -4706,8 +4734,9 @@ var isPluginActive2 = () => false;
|
|
|
4706
4734
|
|
|
4707
4735
|
// src/routes/admin-content.ts
|
|
4708
4736
|
var adminContentRoutes = new hono.Hono();
|
|
4737
|
+
adminContentRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
4709
4738
|
async function getCollectionFields(db, collectionId) {
|
|
4710
|
-
const cache =
|
|
4739
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.collection);
|
|
4711
4740
|
return cache.getOrSet(
|
|
4712
4741
|
cache.generateKey("fields", collectionId),
|
|
4713
4742
|
async () => {
|
|
@@ -4731,7 +4760,7 @@ async function getCollectionFields(db, collectionId) {
|
|
|
4731
4760
|
);
|
|
4732
4761
|
}
|
|
4733
4762
|
async function getCollection(db, collectionId) {
|
|
4734
|
-
const cache =
|
|
4763
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.collection);
|
|
4735
4764
|
return cache.getOrSet(
|
|
4736
4765
|
cache.generateKey("collection", collectionId),
|
|
4737
4766
|
async () => {
|
|
@@ -4987,7 +5016,7 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
4987
5016
|
const db = c.env.DB;
|
|
4988
5017
|
const url = new URL(c.req.url);
|
|
4989
5018
|
const referrerParams = url.searchParams.get("ref") || "";
|
|
4990
|
-
const cache =
|
|
5019
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
|
|
4991
5020
|
const content = await cache.getOrSet(
|
|
4992
5021
|
cache.generateKey("content", id),
|
|
4993
5022
|
async () => {
|
|
@@ -5177,7 +5206,7 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
5177
5206
|
now,
|
|
5178
5207
|
now
|
|
5179
5208
|
).run();
|
|
5180
|
-
const cache =
|
|
5209
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
|
|
5181
5210
|
await cache.invalidate(`content:list:${collectionId}:*`);
|
|
5182
5211
|
const versionStmt = db.prepare(`
|
|
5183
5212
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
@@ -5325,7 +5354,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
5325
5354
|
now,
|
|
5326
5355
|
id
|
|
5327
5356
|
).run();
|
|
5328
|
-
const cache =
|
|
5357
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
|
|
5329
5358
|
await cache.delete(cache.generateKey("content", id));
|
|
5330
5359
|
await cache.invalidate(`content:list:${existingContent.collection_id}:*`);
|
|
5331
5360
|
const existingData = JSON.parse(existingContent.data || "{}");
|
|
@@ -5618,7 +5647,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
5618
5647
|
} else {
|
|
5619
5648
|
return c.json({ success: false, error: "Invalid action" });
|
|
5620
5649
|
}
|
|
5621
|
-
const cache =
|
|
5650
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
|
|
5622
5651
|
for (const contentId of ids) {
|
|
5623
5652
|
await cache.delete(cache.generateKey("content", contentId));
|
|
5624
5653
|
}
|
|
@@ -5646,7 +5675,7 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
5646
5675
|
WHERE id = ?
|
|
5647
5676
|
`);
|
|
5648
5677
|
await deleteStmt.bind(now, id).run();
|
|
5649
|
-
const cache =
|
|
5678
|
+
const cache = chunk3NVJ6W27_cjs.getCacheService(chunk3NVJ6W27_cjs.CACHE_CONFIGS.content);
|
|
5650
5679
|
await cache.delete(cache.generateKey("content", id));
|
|
5651
5680
|
await cache.invalidate("content:list:*");
|
|
5652
5681
|
return c.html(`
|
|
@@ -5838,170 +5867,157 @@ ${JSON.stringify(data, null, 2)}
|
|
|
5838
5867
|
var admin_content_default = adminContentRoutes;
|
|
5839
5868
|
|
|
5840
5869
|
// src/templates/pages/admin-profile.template.ts
|
|
5870
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
5841
5871
|
function renderProfilePage(data) {
|
|
5842
5872
|
const pageContent = `
|
|
5843
|
-
<div class="
|
|
5873
|
+
<div class="space-y-8">
|
|
5844
5874
|
<!-- Header -->
|
|
5845
|
-
<div class="
|
|
5875
|
+
<div class="sm:flex sm:items-center sm:justify-between">
|
|
5846
5876
|
<div>
|
|
5847
|
-
<h1 class="text-2xl font-semibold text-white">User Profile</h1>
|
|
5848
|
-
<p class="mt-2 text-sm text-
|
|
5877
|
+
<h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">User Profile</h1>
|
|
5878
|
+
<p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
|
|
5879
|
+
Manage your account settings and preferences
|
|
5880
|
+
</p>
|
|
5849
5881
|
</div>
|
|
5850
5882
|
</div>
|
|
5851
5883
|
|
|
5852
|
-
<!-- Breadcrumb -->
|
|
5853
|
-
<nav class="flex mb-6" aria-label="Breadcrumb">
|
|
5854
|
-
<ol class="flex items-center space-x-3">
|
|
5855
|
-
<li>
|
|
5856
|
-
<a href="/admin" class="text-gray-300 hover:text-white transition-colors">
|
|
5857
|
-
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
|
|
5858
|
-
<path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"/>
|
|
5859
|
-
</svg>
|
|
5860
|
-
</a>
|
|
5861
|
-
</li>
|
|
5862
|
-
<li class="flex items-center">
|
|
5863
|
-
<svg class="h-5 w-5 text-gray-400 mx-2" fill="currentColor" viewBox="0 0 20 20">
|
|
5864
|
-
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
|
|
5865
|
-
</svg>
|
|
5866
|
-
<span class="text-sm font-medium text-gray-200">Profile</span>
|
|
5867
|
-
</li>
|
|
5868
|
-
</ol>
|
|
5869
|
-
</nav>
|
|
5870
|
-
|
|
5871
5884
|
<!-- Alert Messages -->
|
|
5872
|
-
${data.error ?
|
|
5873
|
-
${data.success ?
|
|
5885
|
+
${data.error ? chunk3SPQ3J4N_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
5886
|
+
${data.success ? chunk3SPQ3J4N_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
5874
5887
|
|
|
5875
5888
|
<!-- Profile Form -->
|
|
5876
|
-
<div class="grid grid-cols-1 lg:grid-cols-3 gap-
|
|
5889
|
+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
5877
5890
|
<!-- Main Profile Form -->
|
|
5878
5891
|
<div class="lg:col-span-2">
|
|
5879
|
-
<div class="
|
|
5892
|
+
<div class="rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10">
|
|
5880
5893
|
<!-- Form Header -->
|
|
5881
|
-
<div class="
|
|
5882
|
-
<div class="
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
<svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
5894
|
+
<div class="px-6 py-5 border-b border-zinc-950/5 dark:border-white/5">
|
|
5895
|
+
<div class="flex items-center gap-x-3">
|
|
5896
|
+
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-zinc-950 dark:bg-white">
|
|
5897
|
+
<svg class="h-5 w-5 text-white dark:text-zinc-950" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
5886
5898
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
|
|
5887
5899
|
</svg>
|
|
5888
5900
|
</div>
|
|
5889
5901
|
<div>
|
|
5890
|
-
<h2 class="text-
|
|
5891
|
-
<p class="text-sm text-
|
|
5902
|
+
<h2 class="text-base font-semibold text-zinc-950 dark:text-white">Profile Information</h2>
|
|
5903
|
+
<p class="text-sm text-zinc-500 dark:text-zinc-400">Update your account details</p>
|
|
5892
5904
|
</div>
|
|
5893
5905
|
</div>
|
|
5894
5906
|
</div>
|
|
5895
5907
|
|
|
5896
5908
|
<!-- Form Content -->
|
|
5897
|
-
<form id="profile-form" hx-put="/admin/profile" hx-target="#form-messages" class="p-
|
|
5909
|
+
<form id="profile-form" hx-put="/admin/profile" hx-target="#form-messages" class="p-6 space-y-6">
|
|
5898
5910
|
<div id="form-messages"></div>
|
|
5899
5911
|
|
|
5900
5912
|
<!-- Basic Information -->
|
|
5901
5913
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
5902
5914
|
<div>
|
|
5903
|
-
<label class="block text-sm font-medium text-
|
|
5904
|
-
<input
|
|
5905
|
-
type="text"
|
|
5906
|
-
name="first_name"
|
|
5915
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">First Name</label>
|
|
5916
|
+
<input
|
|
5917
|
+
type="text"
|
|
5918
|
+
name="first_name"
|
|
5907
5919
|
value="${data.profile.first_name}"
|
|
5908
5920
|
required
|
|
5909
|
-
class="w-full px-
|
|
5921
|
+
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"
|
|
5910
5922
|
placeholder="Enter your first name"
|
|
5911
5923
|
>
|
|
5912
5924
|
</div>
|
|
5913
5925
|
<div>
|
|
5914
|
-
<label class="block text-sm font-medium text-
|
|
5915
|
-
<input
|
|
5916
|
-
type="text"
|
|
5917
|
-
name="last_name"
|
|
5926
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">Last Name</label>
|
|
5927
|
+
<input
|
|
5928
|
+
type="text"
|
|
5929
|
+
name="last_name"
|
|
5918
5930
|
value="${data.profile.last_name}"
|
|
5919
5931
|
required
|
|
5920
|
-
class="w-full px-
|
|
5932
|
+
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"
|
|
5921
5933
|
placeholder="Enter your last name"
|
|
5922
5934
|
>
|
|
5923
5935
|
</div>
|
|
5924
5936
|
</div>
|
|
5925
5937
|
|
|
5926
5938
|
<div>
|
|
5927
|
-
<label class="block text-sm font-medium text-
|
|
5928
|
-
<input
|
|
5929
|
-
type="text"
|
|
5930
|
-
name="username"
|
|
5939
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">Username</label>
|
|
5940
|
+
<input
|
|
5941
|
+
type="text"
|
|
5942
|
+
name="username"
|
|
5931
5943
|
value="${data.profile.username}"
|
|
5932
5944
|
required
|
|
5933
|
-
class="w-full px-
|
|
5945
|
+
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"
|
|
5934
5946
|
placeholder="Enter your username"
|
|
5935
5947
|
>
|
|
5936
5948
|
</div>
|
|
5937
5949
|
|
|
5938
5950
|
<div>
|
|
5939
|
-
<label class="block text-sm font-medium text-
|
|
5940
|
-
<input
|
|
5941
|
-
type="email"
|
|
5942
|
-
name="email"
|
|
5951
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">Email Address</label>
|
|
5952
|
+
<input
|
|
5953
|
+
type="email"
|
|
5954
|
+
name="email"
|
|
5943
5955
|
value="${data.profile.email}"
|
|
5944
5956
|
required
|
|
5945
|
-
class="w-full px-
|
|
5957
|
+
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"
|
|
5946
5958
|
placeholder="Enter your email address"
|
|
5947
5959
|
>
|
|
5948
5960
|
</div>
|
|
5949
5961
|
|
|
5950
5962
|
<div>
|
|
5951
|
-
<label class="block text-sm font-medium text-
|
|
5952
|
-
<input
|
|
5953
|
-
type="tel"
|
|
5954
|
-
name="phone"
|
|
5963
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">Phone Number</label>
|
|
5964
|
+
<input
|
|
5965
|
+
type="tel"
|
|
5966
|
+
name="phone"
|
|
5955
5967
|
value="${data.profile.phone || ""}"
|
|
5956
|
-
class="w-full px-
|
|
5968
|
+
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"
|
|
5957
5969
|
placeholder="Enter your phone number"
|
|
5958
5970
|
>
|
|
5959
5971
|
</div>
|
|
5960
5972
|
|
|
5961
5973
|
<div>
|
|
5962
|
-
<label class="block text-sm font-medium text-
|
|
5963
|
-
<textarea
|
|
5964
|
-
name="bio"
|
|
5974
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">Bio</label>
|
|
5975
|
+
<textarea
|
|
5976
|
+
name="bio"
|
|
5965
5977
|
rows="3"
|
|
5966
|
-
class="w-full px-
|
|
5978
|
+
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 resize-none"
|
|
5967
5979
|
placeholder="Tell us about yourself..."
|
|
5968
5980
|
>${data.profile.bio || ""}</textarea>
|
|
5969
5981
|
</div>
|
|
5970
5982
|
|
|
5971
5983
|
<!-- Preferences -->
|
|
5972
|
-
<div class="pt-6 border-t border-white/
|
|
5973
|
-
<h3 class="text-
|
|
5974
|
-
|
|
5984
|
+
<div class="pt-6 border-t border-zinc-950/5 dark:border-white/5">
|
|
5985
|
+
<h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Preferences</h3>
|
|
5986
|
+
|
|
5975
5987
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
5976
5988
|
<div>
|
|
5977
|
-
<label class="block text-sm font-medium text-
|
|
5978
|
-
<
|
|
5979
|
-
name="timezone"
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5989
|
+
<label for="timezone" class="block text-sm/6 font-medium text-zinc-950 dark:text-white mb-2">Timezone</label>
|
|
5990
|
+
<div class="grid grid-cols-1">
|
|
5991
|
+
<select id="timezone" name="timezone" 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">
|
|
5992
|
+
${data.timezones.map((tz) => `
|
|
5993
|
+
<option value="${tz.value}" ${tz.value === data.profile.timezone ? "selected" : ""}>${tz.label}</option>
|
|
5994
|
+
`).join("")}
|
|
5995
|
+
</select>
|
|
5996
|
+
<svg viewBox="0 0 16 16" fill="currentColor" 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">
|
|
5997
|
+
<path d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" fill-rule="evenodd" />
|
|
5998
|
+
</svg>
|
|
5999
|
+
</div>
|
|
5986
6000
|
</div>
|
|
5987
6001
|
<div>
|
|
5988
|
-
<label class="block text-sm font-medium text-
|
|
5989
|
-
<
|
|
5990
|
-
name="language"
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
6002
|
+
<label for="language" class="block text-sm/6 font-medium text-zinc-950 dark:text-white mb-2">Language</label>
|
|
6003
|
+
<div class="grid grid-cols-1">
|
|
6004
|
+
<select id="language" name="language" 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">
|
|
6005
|
+
${data.languages.map((lang) => `
|
|
6006
|
+
<option value="${lang.value}" ${lang.value === data.profile.language ? "selected" : ""}>${lang.label}</option>
|
|
6007
|
+
`).join("")}
|
|
6008
|
+
</select>
|
|
6009
|
+
<svg viewBox="0 0 16 16" fill="currentColor" 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">
|
|
6010
|
+
<path d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" fill-rule="evenodd" />
|
|
6011
|
+
</svg>
|
|
6012
|
+
</div>
|
|
5997
6013
|
</div>
|
|
5998
6014
|
</div>
|
|
5999
6015
|
</div>
|
|
6000
6016
|
|
|
6001
6017
|
<!-- Notifications -->
|
|
6002
|
-
<div class="pt-6 border-t border-white/
|
|
6003
|
-
<h3 class="text-
|
|
6004
|
-
|
|
6018
|
+
<div class="pt-6 border-t border-zinc-950/5 dark:border-white/5">
|
|
6019
|
+
<h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Notifications</h3>
|
|
6020
|
+
|
|
6005
6021
|
<div class="space-y-5">
|
|
6006
6022
|
<div class="flex gap-3">
|
|
6007
6023
|
<div class="flex h-6 shrink-0 items-center">
|
|
@@ -6012,27 +6028,30 @@ function renderProfilePage(data) {
|
|
|
6012
6028
|
name="email_notifications"
|
|
6013
6029
|
value="1"
|
|
6014
6030
|
${data.profile.email_notifications ? "checked" : ""}
|
|
6015
|
-
class="col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500
|
|
6031
|
+
class="col-start-1 row-start-1 appearance-none rounded border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-white/5 checked:border-indigo-500 checked:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 disabled:border-zinc-950/5 dark:disabled:border-white/5 disabled:bg-zinc-950/10 dark:disabled:bg-white/10 forced-colors:appearance-auto"
|
|
6016
6032
|
/>
|
|
6017
6033
|
<svg viewBox="0 0 14 14" fill="none" class="pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white group-has-[:disabled]:stroke-zinc-950/25 dark:group-has-[:disabled]:stroke-white/25">
|
|
6018
6034
|
<path d="M3 8L6 11L11 3.5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="opacity-0 group-has-[:checked]:opacity-100" />
|
|
6019
|
-
<path d="M3 7H11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="opacity-0 group-has-[:indeterminate]:opacity-100" />
|
|
6020
6035
|
</svg>
|
|
6021
6036
|
</div>
|
|
6022
6037
|
</div>
|
|
6023
6038
|
<div class="text-sm/6">
|
|
6024
6039
|
<label for="email_notifications" class="font-medium text-zinc-950 dark:text-white">Email notifications</label>
|
|
6040
|
+
<p class="text-zinc-500 dark:text-zinc-400">Receive email updates about new features and product announcements.</p>
|
|
6025
6041
|
</div>
|
|
6026
6042
|
</div>
|
|
6027
6043
|
</div>
|
|
6028
6044
|
</div>
|
|
6029
6045
|
|
|
6030
6046
|
<!-- Submit Button -->
|
|
6031
|
-
<div class="pt-6 border-t border-white/
|
|
6032
|
-
<button
|
|
6047
|
+
<div class="pt-6 border-t border-zinc-950/5 dark:border-white/5">
|
|
6048
|
+
<button
|
|
6033
6049
|
type="submit"
|
|
6034
|
-
class="
|
|
6050
|
+
class="inline-flex justify-center items-center gap-x-2 rounded-lg bg-zinc-950 dark:bg-white px-4 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-950 dark:focus-visible:outline-white transition-colors"
|
|
6035
6051
|
>
|
|
6052
|
+
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
6053
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
|
6054
|
+
</svg>
|
|
6036
6055
|
Update Profile
|
|
6037
6056
|
</button>
|
|
6038
6057
|
</div>
|
|
@@ -6043,86 +6062,96 @@ function renderProfilePage(data) {
|
|
|
6043
6062
|
<!-- Profile Sidebar -->
|
|
6044
6063
|
<div class="lg:col-span-1 space-y-6">
|
|
6045
6064
|
<!-- Avatar -->
|
|
6046
|
-
<div class="
|
|
6047
|
-
<h3 class="text-
|
|
6048
|
-
|
|
6065
|
+
<div class="rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 p-6">
|
|
6066
|
+
<h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Profile Picture</h3>
|
|
6067
|
+
|
|
6049
6068
|
<div class="text-center">
|
|
6050
|
-
<div class="w-24 h-24 rounded-full mx-auto mb-4 overflow-hidden bg-gradient-to-br from-
|
|
6069
|
+
<div class="w-24 h-24 rounded-full mx-auto mb-4 overflow-hidden bg-gradient-to-br from-cyan-400 to-purple-400 flex items-center justify-center ring-4 ring-zinc-950/5 dark:ring-white/10">
|
|
6051
6070
|
${data.profile.avatar_url ? `<img src="${data.profile.avatar_url}" alt="Profile picture" class="w-full h-full object-cover">` : `<span class="text-2xl font-bold text-white">${data.profile.first_name.charAt(0)}${data.profile.last_name.charAt(0)}</span>`}
|
|
6052
6071
|
</div>
|
|
6053
|
-
|
|
6072
|
+
|
|
6054
6073
|
<form id="avatar-form" hx-post="/admin/profile/avatar" hx-target="#avatar-messages" hx-encoding="multipart/form-data">
|
|
6055
|
-
<input
|
|
6056
|
-
type="file"
|
|
6057
|
-
name="avatar"
|
|
6074
|
+
<input
|
|
6075
|
+
type="file"
|
|
6076
|
+
name="avatar"
|
|
6058
6077
|
accept="image/*"
|
|
6059
6078
|
class="hidden"
|
|
6060
6079
|
id="avatar-input"
|
|
6061
6080
|
onchange="document.getElementById('avatar-form').dispatchEvent(new Event('submit'))"
|
|
6062
6081
|
>
|
|
6063
|
-
<label
|
|
6082
|
+
<label
|
|
6064
6083
|
for="avatar-input"
|
|
6065
|
-
class="inline-
|
|
6084
|
+
class="inline-flex items-center gap-x-2 rounded-lg bg-white dark:bg-zinc-800 px-4 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors cursor-pointer"
|
|
6066
6085
|
>
|
|
6086
|
+
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
6087
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"/>
|
|
6088
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"/>
|
|
6089
|
+
</svg>
|
|
6067
6090
|
Change Picture
|
|
6068
6091
|
</label>
|
|
6069
6092
|
</form>
|
|
6070
|
-
|
|
6093
|
+
|
|
6071
6094
|
<div id="avatar-messages" class="mt-3"></div>
|
|
6072
6095
|
</div>
|
|
6073
6096
|
</div>
|
|
6074
6097
|
|
|
6075
6098
|
<!-- Account Info -->
|
|
6076
|
-
<div class="
|
|
6077
|
-
<h3 class="text-
|
|
6078
|
-
|
|
6079
|
-
<
|
|
6099
|
+
<div class="rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 p-6">
|
|
6100
|
+
<h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Account Information</h3>
|
|
6101
|
+
|
|
6102
|
+
<dl class="space-y-3 text-sm">
|
|
6080
6103
|
<div>
|
|
6081
|
-
<
|
|
6082
|
-
<
|
|
6104
|
+
<dt class="text-zinc-500 dark:text-zinc-400">Role</dt>
|
|
6105
|
+
<dd class="mt-1">
|
|
6106
|
+
<span class="inline-flex items-center rounded-md bg-blue-50 dark:bg-blue-500/10 px-2 py-1 text-xs font-medium text-blue-700 dark:text-blue-400 ring-1 ring-inset ring-blue-700/10 dark:ring-blue-400/20 capitalize">
|
|
6107
|
+
${data.profile.role}
|
|
6108
|
+
</span>
|
|
6109
|
+
</dd>
|
|
6083
6110
|
</div>
|
|
6084
6111
|
<div>
|
|
6085
|
-
<
|
|
6086
|
-
<
|
|
6112
|
+
<dt class="text-zinc-500 dark:text-zinc-400">Member Since</dt>
|
|
6113
|
+
<dd class="mt-1 text-zinc-950 dark:text-white">${new Date(data.profile.created_at).toLocaleDateString()}</dd>
|
|
6087
6114
|
</div>
|
|
6088
6115
|
${data.profile.last_login_at ? `
|
|
6089
6116
|
<div>
|
|
6090
|
-
<
|
|
6091
|
-
<
|
|
6117
|
+
<dt class="text-zinc-500 dark:text-zinc-400">Last Login</dt>
|
|
6118
|
+
<dd class="mt-1 text-zinc-950 dark:text-white">${new Date(data.profile.last_login_at).toLocaleDateString()}</dd>
|
|
6092
6119
|
</div>
|
|
6093
6120
|
` : ""}
|
|
6094
6121
|
<div>
|
|
6095
|
-
<
|
|
6096
|
-
<
|
|
6122
|
+
<dt class="text-zinc-500 dark:text-zinc-400">Two-Factor Auth</dt>
|
|
6123
|
+
<dd class="mt-1">
|
|
6124
|
+
${data.profile.two_factor_enabled ? '<span class="inline-flex items-center rounded-md bg-green-50 dark:bg-green-500/10 px-2 py-1 text-xs font-medium text-green-700 dark:text-green-400 ring-1 ring-inset ring-green-600/20 dark:ring-green-500/20">Enabled</span>' : '<span class="inline-flex items-center rounded-md bg-zinc-50 dark:bg-zinc-800 px-2 py-1 text-xs font-medium text-zinc-600 dark:text-zinc-400 ring-1 ring-inset ring-zinc-500/10 dark:ring-zinc-400/20">Disabled</span>'}
|
|
6125
|
+
</dd>
|
|
6097
6126
|
</div>
|
|
6098
|
-
</
|
|
6127
|
+
</dl>
|
|
6099
6128
|
</div>
|
|
6100
6129
|
|
|
6101
6130
|
<!-- Security Actions -->
|
|
6102
|
-
<div class="
|
|
6103
|
-
<h3 class="text-
|
|
6104
|
-
|
|
6105
|
-
<div class="space-y-
|
|
6106
|
-
<button
|
|
6131
|
+
<div class="rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 p-6">
|
|
6132
|
+
<h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Security</h3>
|
|
6133
|
+
|
|
6134
|
+
<div class="space-y-2">
|
|
6135
|
+
<button
|
|
6107
6136
|
type="button"
|
|
6108
6137
|
onclick="showChangePasswordModal()"
|
|
6109
|
-
class="w-full text-left px-3 py-2 text-sm text-
|
|
6138
|
+
class="w-full text-left flex items-center gap-x-3 px-3 py-2 text-sm text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-800/50 rounded-lg transition-colors"
|
|
6110
6139
|
>
|
|
6111
|
-
<svg class="w-4 h-4
|
|
6140
|
+
<svg class="w-4 h-4 text-zinc-500 dark:text-zinc-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
6112
6141
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-3.586l4.293-4.293A6 6 0 0119 9z"/>
|
|
6113
6142
|
</svg>
|
|
6114
|
-
Change Password
|
|
6143
|
+
<span class="font-medium">Change Password</span>
|
|
6115
6144
|
</button>
|
|
6116
|
-
|
|
6117
|
-
<button
|
|
6145
|
+
|
|
6146
|
+
<button
|
|
6118
6147
|
type="button"
|
|
6119
6148
|
onclick="toggle2FA()"
|
|
6120
|
-
class="w-full text-left px-3 py-2 text-sm text-
|
|
6149
|
+
class="w-full text-left flex items-center gap-x-3 px-3 py-2 text-sm text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-800/50 rounded-lg transition-colors"
|
|
6121
6150
|
>
|
|
6122
|
-
<svg class="w-4 h-4
|
|
6151
|
+
<svg class="w-4 h-4 text-zinc-500 dark:text-zinc-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
6123
6152
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
|
|
6124
6153
|
</svg>
|
|
6125
|
-
|
|
6154
|
+
<span class="font-medium">${data.profile.two_factor_enabled ? "Disable" : "Enable"} 2FA</span>
|
|
6126
6155
|
</button>
|
|
6127
6156
|
</div>
|
|
6128
6157
|
</div>
|
|
@@ -6131,67 +6160,73 @@ function renderProfilePage(data) {
|
|
|
6131
6160
|
</div>
|
|
6132
6161
|
|
|
6133
6162
|
<!-- Change Password Modal -->
|
|
6134
|
-
<div id="password-modal" class="fixed inset-0 bg-
|
|
6135
|
-
<div class="
|
|
6136
|
-
<div class="
|
|
6137
|
-
<div class="
|
|
6138
|
-
|
|
6139
|
-
<
|
|
6140
|
-
|
|
6141
|
-
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
6163
|
+
<div id="password-modal" class="fixed inset-0 bg-zinc-950/50 backdrop-blur-sm flex items-center justify-center z-50 hidden">
|
|
6164
|
+
<div class="rounded-xl bg-white dark:bg-zinc-900 shadow-2xl ring-1 ring-zinc-950/5 dark:ring-white/10 w-full max-w-md mx-4">
|
|
6165
|
+
<div class="px-6 py-5 border-b border-zinc-950/5 dark:border-white/5">
|
|
6166
|
+
<div class="flex items-center justify-between">
|
|
6167
|
+
<h3 class="text-base font-semibold text-zinc-950 dark:text-white">Change Password</h3>
|
|
6168
|
+
<button onclick="closePasswordModal()" class="text-zinc-500 dark:text-zinc-400 hover:text-zinc-950 dark:hover:text-white transition-colors">
|
|
6169
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
6142
6170
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
6143
6171
|
</svg>
|
|
6144
6172
|
</button>
|
|
6145
6173
|
</div>
|
|
6146
6174
|
</div>
|
|
6147
|
-
|
|
6175
|
+
|
|
6148
6176
|
<form id="password-form" hx-post="/admin/profile/password" hx-target="#password-messages" class="p-6 space-y-4">
|
|
6149
6177
|
<div id="password-messages"></div>
|
|
6150
|
-
|
|
6178
|
+
|
|
6151
6179
|
<div>
|
|
6152
|
-
<label class="block text-sm font-medium text-
|
|
6153
|
-
<input
|
|
6154
|
-
type="password"
|
|
6155
|
-
name="current_password"
|
|
6180
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">Current Password</label>
|
|
6181
|
+
<input
|
|
6182
|
+
type="password"
|
|
6183
|
+
name="current_password"
|
|
6156
6184
|
required
|
|
6157
|
-
class="w-full px-
|
|
6185
|
+
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"
|
|
6186
|
+
placeholder="Enter current password"
|
|
6158
6187
|
>
|
|
6159
6188
|
</div>
|
|
6160
6189
|
|
|
6161
6190
|
<div>
|
|
6162
|
-
<label class="block text-sm font-medium text-
|
|
6163
|
-
<input
|
|
6164
|
-
type="password"
|
|
6165
|
-
name="new_password"
|
|
6191
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">New Password</label>
|
|
6192
|
+
<input
|
|
6193
|
+
type="password"
|
|
6194
|
+
name="new_password"
|
|
6166
6195
|
required
|
|
6167
6196
|
minlength="8"
|
|
6168
|
-
class="w-full px-
|
|
6197
|
+
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"
|
|
6198
|
+
placeholder="Enter new password"
|
|
6169
6199
|
>
|
|
6200
|
+
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Must be at least 8 characters</p>
|
|
6170
6201
|
</div>
|
|
6171
6202
|
|
|
6172
6203
|
<div>
|
|
6173
|
-
<label class="block text-sm font-medium text-
|
|
6174
|
-
<input
|
|
6175
|
-
type="password"
|
|
6176
|
-
name="confirm_password"
|
|
6204
|
+
<label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">Confirm New Password</label>
|
|
6205
|
+
<input
|
|
6206
|
+
type="password"
|
|
6207
|
+
name="confirm_password"
|
|
6177
6208
|
required
|
|
6178
6209
|
minlength="8"
|
|
6179
|
-
class="w-full px-
|
|
6210
|
+
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"
|
|
6211
|
+
placeholder="Confirm new password"
|
|
6180
6212
|
>
|
|
6181
6213
|
</div>
|
|
6182
6214
|
|
|
6183
|
-
<div class="flex justify-end
|
|
6184
|
-
<button
|
|
6185
|
-
type="button"
|
|
6215
|
+
<div class="flex justify-end gap-x-3 pt-4 border-t border-zinc-950/5 dark:border-white/5">
|
|
6216
|
+
<button
|
|
6217
|
+
type="button"
|
|
6186
6218
|
onclick="closePasswordModal()"
|
|
6187
|
-
class="px-4 py-2
|
|
6219
|
+
class="rounded-lg bg-white dark:bg-zinc-800 px-4 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors"
|
|
6188
6220
|
>
|
|
6189
6221
|
Cancel
|
|
6190
6222
|
</button>
|
|
6191
|
-
<button
|
|
6223
|
+
<button
|
|
6192
6224
|
type="submit"
|
|
6193
|
-
class="
|
|
6225
|
+
class="inline-flex items-center gap-x-2 rounded-lg bg-zinc-950 dark:bg-white px-4 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors"
|
|
6194
6226
|
>
|
|
6227
|
+
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
6228
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
|
6229
|
+
</svg>
|
|
6195
6230
|
Update Password
|
|
6196
6231
|
</button>
|
|
6197
6232
|
</div>
|
|
@@ -6234,9 +6269,10 @@ function renderProfilePage(data) {
|
|
|
6234
6269
|
pageTitle: "Profile",
|
|
6235
6270
|
currentPath: "/admin/profile",
|
|
6236
6271
|
user: data.user,
|
|
6272
|
+
version: data.version,
|
|
6237
6273
|
content: pageContent
|
|
6238
6274
|
};
|
|
6239
|
-
return
|
|
6275
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
6240
6276
|
}
|
|
6241
6277
|
|
|
6242
6278
|
// src/templates/components/alert.template.ts
|
|
@@ -6519,7 +6555,7 @@ function renderActivityLogsPage(data) {
|
|
|
6519
6555
|
user: data.user,
|
|
6520
6556
|
content: pageContent
|
|
6521
6557
|
};
|
|
6522
|
-
return
|
|
6558
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayout(layoutData);
|
|
6523
6559
|
}
|
|
6524
6560
|
function getActionBadgeClass(action) {
|
|
6525
6561
|
if (action.includes("login") || action.includes("logout")) {
|
|
@@ -6539,7 +6575,7 @@ function formatAction(action) {
|
|
|
6539
6575
|
}
|
|
6540
6576
|
|
|
6541
6577
|
// src/templates/pages/admin-user-edit.template.ts
|
|
6542
|
-
|
|
6578
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
6543
6579
|
|
|
6544
6580
|
// src/templates/components/confirmation-dialog.template.ts
|
|
6545
6581
|
function renderConfirmationDialog2(options) {
|
|
@@ -6660,8 +6696,8 @@ function renderUserEditPage(data) {
|
|
|
6660
6696
|
|
|
6661
6697
|
<!-- Alert Messages -->
|
|
6662
6698
|
<div id="form-messages">
|
|
6663
|
-
${data.error ?
|
|
6664
|
-
${data.success ?
|
|
6699
|
+
${data.error ? chunk3SPQ3J4N_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
6700
|
+
${data.success ? chunk3SPQ3J4N_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
6665
6701
|
</div>
|
|
6666
6702
|
|
|
6667
6703
|
<!-- User Edit Form -->
|
|
@@ -6680,7 +6716,7 @@ function renderUserEditPage(data) {
|
|
|
6680
6716
|
<input
|
|
6681
6717
|
type="text"
|
|
6682
6718
|
name="first_name"
|
|
6683
|
-
value="${
|
|
6719
|
+
value="${chunkUL32L2KV_cjs.escapeHtml(data.userToEdit.firstName || "")}"
|
|
6684
6720
|
required
|
|
6685
6721
|
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"
|
|
6686
6722
|
/>
|
|
@@ -6691,7 +6727,7 @@ function renderUserEditPage(data) {
|
|
|
6691
6727
|
<input
|
|
6692
6728
|
type="text"
|
|
6693
6729
|
name="last_name"
|
|
6694
|
-
value="${
|
|
6730
|
+
value="${chunkUL32L2KV_cjs.escapeHtml(data.userToEdit.lastName || "")}"
|
|
6695
6731
|
required
|
|
6696
6732
|
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"
|
|
6697
6733
|
/>
|
|
@@ -6702,7 +6738,7 @@ function renderUserEditPage(data) {
|
|
|
6702
6738
|
<input
|
|
6703
6739
|
type="text"
|
|
6704
6740
|
name="username"
|
|
6705
|
-
value="${
|
|
6741
|
+
value="${chunkUL32L2KV_cjs.escapeHtml(data.userToEdit.username || "")}"
|
|
6706
6742
|
required
|
|
6707
6743
|
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"
|
|
6708
6744
|
/>
|
|
@@ -6713,7 +6749,7 @@ function renderUserEditPage(data) {
|
|
|
6713
6749
|
<input
|
|
6714
6750
|
type="email"
|
|
6715
6751
|
name="email"
|
|
6716
|
-
value="${
|
|
6752
|
+
value="${chunkUL32L2KV_cjs.escapeHtml(data.userToEdit.email || "")}"
|
|
6717
6753
|
required
|
|
6718
6754
|
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"
|
|
6719
6755
|
/>
|
|
@@ -6724,7 +6760,7 @@ function renderUserEditPage(data) {
|
|
|
6724
6760
|
<input
|
|
6725
6761
|
type="tel"
|
|
6726
6762
|
name="phone"
|
|
6727
|
-
value="${
|
|
6763
|
+
value="${chunkUL32L2KV_cjs.escapeHtml(data.userToEdit.phone || "")}"
|
|
6728
6764
|
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"
|
|
6729
6765
|
/>
|
|
6730
6766
|
</div>
|
|
@@ -6738,7 +6774,7 @@ function renderUserEditPage(data) {
|
|
|
6738
6774
|
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"
|
|
6739
6775
|
>
|
|
6740
6776
|
${data.roles.map((role) => `
|
|
6741
|
-
<option value="${
|
|
6777
|
+
<option value="${chunkUL32L2KV_cjs.escapeHtml(role.value)}" ${data.userToEdit.role === role.value ? "selected" : ""}>${chunkUL32L2KV_cjs.escapeHtml(role.label)}</option>
|
|
6742
6778
|
`).join("")}
|
|
6743
6779
|
</select>
|
|
6744
6780
|
<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">
|
|
@@ -6754,7 +6790,7 @@ function renderUserEditPage(data) {
|
|
|
6754
6790
|
name="bio"
|
|
6755
6791
|
rows="3"
|
|
6756
6792
|
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"
|
|
6757
|
-
>${
|
|
6793
|
+
>${chunkUL32L2KV_cjs.escapeHtml(data.userToEdit.bio || "")}</textarea>
|
|
6758
6794
|
</div>
|
|
6759
6795
|
</div>
|
|
6760
6796
|
|
|
@@ -6954,11 +6990,11 @@ function renderUserEditPage(data) {
|
|
|
6954
6990
|
user: data.user,
|
|
6955
6991
|
content: pageContent
|
|
6956
6992
|
};
|
|
6957
|
-
return
|
|
6993
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
6958
6994
|
}
|
|
6959
6995
|
|
|
6960
6996
|
// src/templates/pages/admin-user-new.template.ts
|
|
6961
|
-
|
|
6997
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
6962
6998
|
function renderUserNewPage(data) {
|
|
6963
6999
|
const pageContent = `
|
|
6964
7000
|
<div>
|
|
@@ -6997,8 +7033,8 @@ function renderUserNewPage(data) {
|
|
|
6997
7033
|
|
|
6998
7034
|
<!-- Alert Messages -->
|
|
6999
7035
|
<div id="form-messages">
|
|
7000
|
-
${data.error ?
|
|
7001
|
-
${data.success ?
|
|
7036
|
+
${data.error ? chunk3SPQ3J4N_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
7037
|
+
${data.success ? chunk3SPQ3J4N_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
7002
7038
|
</div>
|
|
7003
7039
|
|
|
7004
7040
|
<!-- User New Form -->
|
|
@@ -7242,11 +7278,11 @@ function renderUserNewPage(data) {
|
|
|
7242
7278
|
user: data.user,
|
|
7243
7279
|
content: pageContent
|
|
7244
7280
|
};
|
|
7245
|
-
return
|
|
7281
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
7246
7282
|
}
|
|
7247
7283
|
|
|
7248
7284
|
// src/templates/pages/admin-users-list.template.ts
|
|
7249
|
-
|
|
7285
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
7250
7286
|
function renderUsersListPage(data) {
|
|
7251
7287
|
const columns = [
|
|
7252
7288
|
{
|
|
@@ -7397,8 +7433,8 @@ function renderUsersListPage(data) {
|
|
|
7397
7433
|
</div>
|
|
7398
7434
|
|
|
7399
7435
|
<!-- Alert Messages -->
|
|
7400
|
-
${data.error ?
|
|
7401
|
-
${data.success ?
|
|
7436
|
+
${data.error ? chunk3SPQ3J4N_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
7437
|
+
${data.success ? chunk3SPQ3J4N_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
7402
7438
|
|
|
7403
7439
|
<!-- Stats -->
|
|
7404
7440
|
<div class="mb-6">
|
|
@@ -7575,10 +7611,10 @@ function renderUsersListPage(data) {
|
|
|
7575
7611
|
</div>
|
|
7576
7612
|
|
|
7577
7613
|
<!-- Users Table -->
|
|
7578
|
-
${
|
|
7614
|
+
${chunk3SPQ3J4N_cjs.renderTable(tableData)}
|
|
7579
7615
|
|
|
7580
7616
|
<!-- Pagination -->
|
|
7581
|
-
${data.pagination ?
|
|
7617
|
+
${data.pagination ? chunk3SPQ3J4N_cjs.renderPagination(data.pagination) : ""}
|
|
7582
7618
|
</div>
|
|
7583
7619
|
|
|
7584
7620
|
<script>
|
|
@@ -7649,12 +7685,15 @@ function renderUsersListPage(data) {
|
|
|
7649
7685
|
version: data.version,
|
|
7650
7686
|
content: pageContent
|
|
7651
7687
|
};
|
|
7652
|
-
return
|
|
7688
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
7653
7689
|
}
|
|
7654
7690
|
|
|
7655
7691
|
// src/routes/admin-users.ts
|
|
7656
7692
|
var userRoutes = new hono.Hono();
|
|
7657
|
-
userRoutes.use("*",
|
|
7693
|
+
userRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
7694
|
+
userRoutes.get("/", (c) => {
|
|
7695
|
+
return c.redirect("/admin/dashboard");
|
|
7696
|
+
});
|
|
7658
7697
|
var TIMEZONES = [
|
|
7659
7698
|
{ value: "UTC", label: "UTC" },
|
|
7660
7699
|
{ value: "America/New_York", label: "Eastern Time" },
|
|
@@ -7750,12 +7789,12 @@ userRoutes.put("/profile", async (c) => {
|
|
|
7750
7789
|
const db = c.env.DB;
|
|
7751
7790
|
try {
|
|
7752
7791
|
const formData = await c.req.formData();
|
|
7753
|
-
const firstName =
|
|
7754
|
-
const lastName =
|
|
7755
|
-
const username =
|
|
7792
|
+
const firstName = chunkUL32L2KV_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
7793
|
+
const lastName = chunkUL32L2KV_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
7794
|
+
const username = chunkUL32L2KV_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
7756
7795
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
7757
|
-
const phone =
|
|
7758
|
-
const bio =
|
|
7796
|
+
const phone = chunkUL32L2KV_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
7797
|
+
const bio = chunkUL32L2KV_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
7759
7798
|
const timezone = formData.get("timezone")?.toString() || "UTC";
|
|
7760
7799
|
const language = formData.get("language")?.toString() || "en";
|
|
7761
7800
|
const emailNotifications = formData.get("email_notifications") === "1";
|
|
@@ -7806,7 +7845,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
7806
7845
|
Date.now(),
|
|
7807
7846
|
user.userId
|
|
7808
7847
|
).run();
|
|
7809
|
-
await
|
|
7848
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
7810
7849
|
db,
|
|
7811
7850
|
user.userId,
|
|
7812
7851
|
"profile.update",
|
|
@@ -7865,7 +7904,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
7865
7904
|
WHERE id = ?
|
|
7866
7905
|
`);
|
|
7867
7906
|
await updateStmt.bind(avatarUrl, Date.now(), user.userId).run();
|
|
7868
|
-
await
|
|
7907
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
7869
7908
|
db,
|
|
7870
7909
|
user.userId,
|
|
7871
7910
|
"profile.avatar_update",
|
|
@@ -7929,7 +7968,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
7929
7968
|
dismissible: true
|
|
7930
7969
|
}));
|
|
7931
7970
|
}
|
|
7932
|
-
const validPassword = await
|
|
7971
|
+
const validPassword = await chunk4BJGEGX5_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
|
|
7933
7972
|
if (!validPassword) {
|
|
7934
7973
|
return c.html(renderAlert2({
|
|
7935
7974
|
type: "error",
|
|
@@ -7937,7 +7976,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
7937
7976
|
dismissible: true
|
|
7938
7977
|
}));
|
|
7939
7978
|
}
|
|
7940
|
-
const newPasswordHash = await
|
|
7979
|
+
const newPasswordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(newPassword);
|
|
7941
7980
|
const historyStmt = db.prepare(`
|
|
7942
7981
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
7943
7982
|
VALUES (?, ?, ?, ?)
|
|
@@ -7953,7 +7992,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
7953
7992
|
WHERE id = ?
|
|
7954
7993
|
`);
|
|
7955
7994
|
await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
|
|
7956
|
-
await
|
|
7995
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
7957
7996
|
db,
|
|
7958
7997
|
user.userId,
|
|
7959
7998
|
"profile.password_change",
|
|
@@ -7977,7 +8016,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
7977
8016
|
}));
|
|
7978
8017
|
}
|
|
7979
8018
|
});
|
|
7980
|
-
userRoutes.get("/users",
|
|
8019
|
+
userRoutes.get("/users", async (c) => {
|
|
7981
8020
|
const db = c.env.DB;
|
|
7982
8021
|
const user = c.get("user");
|
|
7983
8022
|
try {
|
|
@@ -8020,7 +8059,7 @@ userRoutes.get("/users", chunkKM4AJFXI_cjs.requirePermission("users.read"), asyn
|
|
|
8020
8059
|
`);
|
|
8021
8060
|
const countResult = await countStmt.bind(...params).first();
|
|
8022
8061
|
const totalUsers = countResult?.total || 0;
|
|
8023
|
-
await
|
|
8062
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8024
8063
|
db,
|
|
8025
8064
|
user.userId,
|
|
8026
8065
|
"users.list_view",
|
|
@@ -8096,7 +8135,7 @@ userRoutes.get("/users", chunkKM4AJFXI_cjs.requirePermission("users.read"), asyn
|
|
|
8096
8135
|
}), 500);
|
|
8097
8136
|
}
|
|
8098
8137
|
});
|
|
8099
|
-
userRoutes.get("/users/new",
|
|
8138
|
+
userRoutes.get("/users/new", async (c) => {
|
|
8100
8139
|
const user = c.get("user");
|
|
8101
8140
|
try {
|
|
8102
8141
|
const pageData = {
|
|
@@ -8117,17 +8156,17 @@ userRoutes.get("/users/new", chunkKM4AJFXI_cjs.requirePermission("users.create")
|
|
|
8117
8156
|
}), 500);
|
|
8118
8157
|
}
|
|
8119
8158
|
});
|
|
8120
|
-
userRoutes.post("/users/new",
|
|
8159
|
+
userRoutes.post("/users/new", async (c) => {
|
|
8121
8160
|
const db = c.env.DB;
|
|
8122
8161
|
const user = c.get("user");
|
|
8123
8162
|
try {
|
|
8124
8163
|
const formData = await c.req.formData();
|
|
8125
|
-
const firstName =
|
|
8126
|
-
const lastName =
|
|
8127
|
-
const username =
|
|
8164
|
+
const firstName = chunkUL32L2KV_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
8165
|
+
const lastName = chunkUL32L2KV_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
8166
|
+
const username = chunkUL32L2KV_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
8128
8167
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
8129
|
-
const phone =
|
|
8130
|
-
const bio =
|
|
8168
|
+
const phone = chunkUL32L2KV_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
8169
|
+
const bio = chunkUL32L2KV_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
8131
8170
|
const role = formData.get("role")?.toString() || "viewer";
|
|
8132
8171
|
const password = formData.get("password")?.toString() || "";
|
|
8133
8172
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
@@ -8174,7 +8213,7 @@ userRoutes.post("/users/new", chunkKM4AJFXI_cjs.requirePermission("users.create"
|
|
|
8174
8213
|
dismissible: true
|
|
8175
8214
|
}));
|
|
8176
8215
|
}
|
|
8177
|
-
const passwordHash = await
|
|
8216
|
+
const passwordHash = await chunk4BJGEGX5_cjs.AuthManager.hashPassword(password);
|
|
8178
8217
|
const userId = globalThis.crypto.randomUUID();
|
|
8179
8218
|
const createStmt = db.prepare(`
|
|
8180
8219
|
INSERT INTO users (
|
|
@@ -8197,7 +8236,7 @@ userRoutes.post("/users/new", chunkKM4AJFXI_cjs.requirePermission("users.create"
|
|
|
8197
8236
|
Date.now(),
|
|
8198
8237
|
Date.now()
|
|
8199
8238
|
).run();
|
|
8200
|
-
await
|
|
8239
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8201
8240
|
db,
|
|
8202
8241
|
user.userId,
|
|
8203
8242
|
"user!.create",
|
|
@@ -8217,7 +8256,7 @@ userRoutes.post("/users/new", chunkKM4AJFXI_cjs.requirePermission("users.create"
|
|
|
8217
8256
|
}));
|
|
8218
8257
|
}
|
|
8219
8258
|
});
|
|
8220
|
-
userRoutes.get("/users/:id",
|
|
8259
|
+
userRoutes.get("/users/:id", async (c) => {
|
|
8221
8260
|
if (c.req.path.endsWith("/edit")) {
|
|
8222
8261
|
return c.notFound();
|
|
8223
8262
|
}
|
|
@@ -8235,7 +8274,7 @@ userRoutes.get("/users/:id", chunkKM4AJFXI_cjs.requirePermission("users.read"),
|
|
|
8235
8274
|
if (!userRecord) {
|
|
8236
8275
|
return c.json({ error: "User not found" }, 404);
|
|
8237
8276
|
}
|
|
8238
|
-
await
|
|
8277
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8239
8278
|
db,
|
|
8240
8279
|
user.userId,
|
|
8241
8280
|
"user!.view",
|
|
@@ -8268,7 +8307,7 @@ userRoutes.get("/users/:id", chunkKM4AJFXI_cjs.requirePermission("users.read"),
|
|
|
8268
8307
|
return c.json({ error: "Failed to fetch user" }, 500);
|
|
8269
8308
|
}
|
|
8270
8309
|
});
|
|
8271
|
-
userRoutes.get("/users/:id/edit",
|
|
8310
|
+
userRoutes.get("/users/:id/edit", async (c) => {
|
|
8272
8311
|
const db = c.env.DB;
|
|
8273
8312
|
const user = c.get("user");
|
|
8274
8313
|
const userId = c.req.param("id");
|
|
@@ -8322,18 +8361,18 @@ userRoutes.get("/users/:id/edit", chunkKM4AJFXI_cjs.requirePermission("users.upd
|
|
|
8322
8361
|
}), 500);
|
|
8323
8362
|
}
|
|
8324
8363
|
});
|
|
8325
|
-
userRoutes.put("/users/:id",
|
|
8364
|
+
userRoutes.put("/users/:id", async (c) => {
|
|
8326
8365
|
const db = c.env.DB;
|
|
8327
8366
|
const user = c.get("user");
|
|
8328
8367
|
const userId = c.req.param("id");
|
|
8329
8368
|
try {
|
|
8330
8369
|
const formData = await c.req.formData();
|
|
8331
|
-
const firstName =
|
|
8332
|
-
const lastName =
|
|
8333
|
-
const username =
|
|
8370
|
+
const firstName = chunkUL32L2KV_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
8371
|
+
const lastName = chunkUL32L2KV_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
8372
|
+
const username = chunkUL32L2KV_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
8334
8373
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
8335
|
-
const phone =
|
|
8336
|
-
const bio =
|
|
8374
|
+
const phone = chunkUL32L2KV_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
8375
|
+
const bio = chunkUL32L2KV_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
8337
8376
|
const role = formData.get("role")?.toString() || "viewer";
|
|
8338
8377
|
const isActive = formData.get("is_active") === "1";
|
|
8339
8378
|
const emailVerified = formData.get("email_verified") === "1";
|
|
@@ -8384,7 +8423,7 @@ userRoutes.put("/users/:id", chunkKM4AJFXI_cjs.requirePermission("users.update")
|
|
|
8384
8423
|
Date.now(),
|
|
8385
8424
|
userId
|
|
8386
8425
|
).run();
|
|
8387
|
-
await
|
|
8426
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8388
8427
|
db,
|
|
8389
8428
|
user.userId,
|
|
8390
8429
|
"user!.update",
|
|
@@ -8408,7 +8447,7 @@ userRoutes.put("/users/:id", chunkKM4AJFXI_cjs.requirePermission("users.update")
|
|
|
8408
8447
|
}));
|
|
8409
8448
|
}
|
|
8410
8449
|
});
|
|
8411
|
-
userRoutes.delete("/users/:id",
|
|
8450
|
+
userRoutes.delete("/users/:id", async (c) => {
|
|
8412
8451
|
const db = c.env.DB;
|
|
8413
8452
|
const user = c.get("user");
|
|
8414
8453
|
const userId = c.req.param("id");
|
|
@@ -8430,7 +8469,7 @@ userRoutes.delete("/users/:id", chunkKM4AJFXI_cjs.requirePermission("users.delet
|
|
|
8430
8469
|
DELETE FROM users WHERE id = ?
|
|
8431
8470
|
`);
|
|
8432
8471
|
await deleteStmt.bind(userId).run();
|
|
8433
|
-
await
|
|
8472
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8434
8473
|
db,
|
|
8435
8474
|
user.userId,
|
|
8436
8475
|
"user!.hard_delete",
|
|
@@ -8449,7 +8488,7 @@ userRoutes.delete("/users/:id", chunkKM4AJFXI_cjs.requirePermission("users.delet
|
|
|
8449
8488
|
UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?
|
|
8450
8489
|
`);
|
|
8451
8490
|
await deleteStmt.bind(Date.now(), userId).run();
|
|
8452
|
-
await
|
|
8491
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8453
8492
|
db,
|
|
8454
8493
|
user.userId,
|
|
8455
8494
|
"user!.soft_delete",
|
|
@@ -8469,15 +8508,15 @@ userRoutes.delete("/users/:id", chunkKM4AJFXI_cjs.requirePermission("users.delet
|
|
|
8469
8508
|
return c.json({ error: "Failed to delete user" }, 500);
|
|
8470
8509
|
}
|
|
8471
8510
|
});
|
|
8472
|
-
userRoutes.post("/invite-user",
|
|
8511
|
+
userRoutes.post("/invite-user", async (c) => {
|
|
8473
8512
|
const db = c.env.DB;
|
|
8474
8513
|
const user = c.get("user");
|
|
8475
8514
|
try {
|
|
8476
8515
|
const formData = await c.req.formData();
|
|
8477
8516
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
8478
8517
|
const role = formData.get("role")?.toString()?.trim() || "viewer";
|
|
8479
|
-
const firstName =
|
|
8480
|
-
const lastName =
|
|
8518
|
+
const firstName = chunkUL32L2KV_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
8519
|
+
const lastName = chunkUL32L2KV_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
8481
8520
|
if (!email || !firstName || !lastName) {
|
|
8482
8521
|
return c.json({ error: "Email, first name, and last name are required" }, 400);
|
|
8483
8522
|
}
|
|
@@ -8516,7 +8555,7 @@ userRoutes.post("/invite-user", chunkKM4AJFXI_cjs.requirePermission("users.creat
|
|
|
8516
8555
|
Date.now(),
|
|
8517
8556
|
Date.now()
|
|
8518
8557
|
).run();
|
|
8519
|
-
await
|
|
8558
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8520
8559
|
db,
|
|
8521
8560
|
user.userId,
|
|
8522
8561
|
"user!.invite_sent",
|
|
@@ -8545,7 +8584,7 @@ userRoutes.post("/invite-user", chunkKM4AJFXI_cjs.requirePermission("users.creat
|
|
|
8545
8584
|
return c.json({ error: "Failed to send user invitation" }, 500);
|
|
8546
8585
|
}
|
|
8547
8586
|
});
|
|
8548
|
-
userRoutes.post("/resend-invitation/:id",
|
|
8587
|
+
userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
8549
8588
|
const db = c.env.DB;
|
|
8550
8589
|
const user = c.get("user");
|
|
8551
8590
|
const userId = c.req.param("id");
|
|
@@ -8573,7 +8612,7 @@ userRoutes.post("/resend-invitation/:id", chunkKM4AJFXI_cjs.requirePermission("u
|
|
|
8573
8612
|
Date.now(),
|
|
8574
8613
|
userId
|
|
8575
8614
|
).run();
|
|
8576
|
-
await
|
|
8615
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8577
8616
|
db,
|
|
8578
8617
|
user.userId,
|
|
8579
8618
|
"user!.invitation_resent",
|
|
@@ -8594,7 +8633,7 @@ userRoutes.post("/resend-invitation/:id", chunkKM4AJFXI_cjs.requirePermission("u
|
|
|
8594
8633
|
return c.json({ error: "Failed to resend invitation" }, 500);
|
|
8595
8634
|
}
|
|
8596
8635
|
});
|
|
8597
|
-
userRoutes.delete("/cancel-invitation/:id",
|
|
8636
|
+
userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
8598
8637
|
const db = c.env.DB;
|
|
8599
8638
|
const user = c.get("user");
|
|
8600
8639
|
const userId = c.req.param("id");
|
|
@@ -8609,7 +8648,7 @@ userRoutes.delete("/cancel-invitation/:id", chunkKM4AJFXI_cjs.requirePermission(
|
|
|
8609
8648
|
}
|
|
8610
8649
|
const deleteStmt = db.prepare(`DELETE FROM users WHERE id = ?`);
|
|
8611
8650
|
await deleteStmt.bind(userId).run();
|
|
8612
|
-
await
|
|
8651
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8613
8652
|
db,
|
|
8614
8653
|
user.userId,
|
|
8615
8654
|
"user!.invitation_cancelled",
|
|
@@ -8628,7 +8667,7 @@ userRoutes.delete("/cancel-invitation/:id", chunkKM4AJFXI_cjs.requirePermission(
|
|
|
8628
8667
|
return c.json({ error: "Failed to cancel invitation" }, 500);
|
|
8629
8668
|
}
|
|
8630
8669
|
});
|
|
8631
|
-
userRoutes.get("/activity-logs",
|
|
8670
|
+
userRoutes.get("/activity-logs", async (c) => {
|
|
8632
8671
|
const db = c.env.DB;
|
|
8633
8672
|
const user = c.get("user");
|
|
8634
8673
|
try {
|
|
@@ -8692,7 +8731,7 @@ userRoutes.get("/activity-logs", chunkKM4AJFXI_cjs.requirePermission("activity.r
|
|
|
8692
8731
|
...log,
|
|
8693
8732
|
details: log.details ? JSON.parse(log.details) : null
|
|
8694
8733
|
}));
|
|
8695
|
-
await
|
|
8734
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8696
8735
|
db,
|
|
8697
8736
|
user.userId,
|
|
8698
8737
|
"activity.logs_viewed",
|
|
@@ -8734,7 +8773,7 @@ userRoutes.get("/activity-logs", chunkKM4AJFXI_cjs.requirePermission("activity.r
|
|
|
8734
8773
|
return c.html(renderActivityLogsPage(pageData));
|
|
8735
8774
|
}
|
|
8736
8775
|
});
|
|
8737
|
-
userRoutes.get("/activity-logs/export",
|
|
8776
|
+
userRoutes.get("/activity-logs/export", async (c) => {
|
|
8738
8777
|
const db = c.env.DB;
|
|
8739
8778
|
const user = c.get("user");
|
|
8740
8779
|
try {
|
|
@@ -8799,7 +8838,7 @@ userRoutes.get("/activity-logs/export", chunkKM4AJFXI_cjs.requirePermission("act
|
|
|
8799
8838
|
csvRows.push(row.join(","));
|
|
8800
8839
|
}
|
|
8801
8840
|
const csvContent = csvRows.join("\n");
|
|
8802
|
-
await
|
|
8841
|
+
await chunk4BJGEGX5_cjs.logActivity(
|
|
8803
8842
|
db,
|
|
8804
8843
|
user.userId,
|
|
8805
8844
|
"activity.logs_exported",
|
|
@@ -9017,7 +9056,7 @@ function getFileIcon(mimeType) {
|
|
|
9017
9056
|
}
|
|
9018
9057
|
|
|
9019
9058
|
// src/templates/pages/admin-media-library.template.ts
|
|
9020
|
-
|
|
9059
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
9021
9060
|
function renderMediaLibraryPage(data) {
|
|
9022
9061
|
const pageContent = `
|
|
9023
9062
|
<div>
|
|
@@ -9949,7 +9988,7 @@ function renderMediaLibraryPage(data) {
|
|
|
9949
9988
|
version: data.version,
|
|
9950
9989
|
content: pageContent
|
|
9951
9990
|
};
|
|
9952
|
-
return
|
|
9991
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
9953
9992
|
}
|
|
9954
9993
|
|
|
9955
9994
|
// src/templates/components/media-file-details.template.ts
|
|
@@ -10135,6 +10174,7 @@ var fileValidationSchema2 = zod.z.object({
|
|
|
10135
10174
|
// 50MB max
|
|
10136
10175
|
});
|
|
10137
10176
|
var adminMediaRoutes = new hono.Hono();
|
|
10177
|
+
adminMediaRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
10138
10178
|
adminMediaRoutes.get("/", async (c) => {
|
|
10139
10179
|
try {
|
|
10140
10180
|
const user = c.get("user");
|
|
@@ -10867,7 +10907,7 @@ function formatFileSize(bytes) {
|
|
|
10867
10907
|
}
|
|
10868
10908
|
|
|
10869
10909
|
// src/templates/pages/admin-plugins-list.template.ts
|
|
10870
|
-
|
|
10910
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
10871
10911
|
function renderPluginsListPage(data) {
|
|
10872
10912
|
const pageContent = `
|
|
10873
10913
|
<div>
|
|
@@ -11241,7 +11281,7 @@ function renderPluginsListPage(data) {
|
|
|
11241
11281
|
version: data.version,
|
|
11242
11282
|
content: pageContent
|
|
11243
11283
|
};
|
|
11244
|
-
return
|
|
11284
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
11245
11285
|
}
|
|
11246
11286
|
function renderPluginCard(plugin) {
|
|
11247
11287
|
const statusColors = {
|
|
@@ -11891,7 +11931,7 @@ function renderPluginSettingsPage(data) {
|
|
|
11891
11931
|
user,
|
|
11892
11932
|
content: pageContent
|
|
11893
11933
|
};
|
|
11894
|
-
return
|
|
11934
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayout(layoutData);
|
|
11895
11935
|
}
|
|
11896
11936
|
function renderStatusBadge(status) {
|
|
11897
11937
|
const statusColors = {
|
|
@@ -12154,6 +12194,7 @@ function formatTimestamp(timestamp) {
|
|
|
12154
12194
|
|
|
12155
12195
|
// src/routes/admin-plugins.ts
|
|
12156
12196
|
var adminPluginRoutes = new hono.Hono();
|
|
12197
|
+
adminPluginRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
12157
12198
|
adminPluginRoutes.get("/", async (c) => {
|
|
12158
12199
|
try {
|
|
12159
12200
|
const user = c.get("user");
|
|
@@ -12488,7 +12529,7 @@ function formatLastUpdated(timestamp) {
|
|
|
12488
12529
|
}
|
|
12489
12530
|
|
|
12490
12531
|
// src/templates/pages/admin-logs-list.template.ts
|
|
12491
|
-
|
|
12532
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
12492
12533
|
function renderLogsListPage(data) {
|
|
12493
12534
|
const { logs, pagination, filters, user } = data;
|
|
12494
12535
|
const content = `
|
|
@@ -12799,7 +12840,7 @@ function renderLogsListPage(data) {
|
|
|
12799
12840
|
user,
|
|
12800
12841
|
content
|
|
12801
12842
|
};
|
|
12802
|
-
return
|
|
12843
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
12803
12844
|
}
|
|
12804
12845
|
function renderLogDetailsPage(data) {
|
|
12805
12846
|
const { log, user } = data;
|
|
@@ -13011,7 +13052,7 @@ function renderLogDetailsPage(data) {
|
|
|
13011
13052
|
</div>
|
|
13012
13053
|
</div>
|
|
13013
13054
|
`;
|
|
13014
|
-
return
|
|
13055
|
+
return chunk3SPQ3J4N_cjs.adminLayoutV2({
|
|
13015
13056
|
title: `Log Details - ${log.id}`,
|
|
13016
13057
|
user,
|
|
13017
13058
|
content
|
|
@@ -13254,7 +13295,7 @@ function renderLogConfigPage(data) {
|
|
|
13254
13295
|
|
|
13255
13296
|
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
|
|
13256
13297
|
`;
|
|
13257
|
-
return
|
|
13298
|
+
return chunk3SPQ3J4N_cjs.adminLayoutV2({
|
|
13258
13299
|
title: "Log Configuration",
|
|
13259
13300
|
user,
|
|
13260
13301
|
content
|
|
@@ -13263,10 +13304,11 @@ function renderLogConfigPage(data) {
|
|
|
13263
13304
|
|
|
13264
13305
|
// src/routes/admin-logs.ts
|
|
13265
13306
|
var adminLogsRoutes = new hono.Hono();
|
|
13307
|
+
adminLogsRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
13266
13308
|
adminLogsRoutes.get("/", async (c) => {
|
|
13267
13309
|
try {
|
|
13268
13310
|
const user = c.get("user");
|
|
13269
|
-
const logger =
|
|
13311
|
+
const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
|
|
13270
13312
|
const query = c.req.query();
|
|
13271
13313
|
const page = parseInt(query.page || "1");
|
|
13272
13314
|
const limit = parseInt(query.limit || "50");
|
|
@@ -13346,7 +13388,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
13346
13388
|
try {
|
|
13347
13389
|
const id = c.req.param("id");
|
|
13348
13390
|
const user = c.get("user");
|
|
13349
|
-
const logger =
|
|
13391
|
+
const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
|
|
13350
13392
|
const { logs } = await logger.getLogs({
|
|
13351
13393
|
limit: 1,
|
|
13352
13394
|
offset: 0,
|
|
@@ -13383,7 +13425,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
13383
13425
|
adminLogsRoutes.get("/config", async (c) => {
|
|
13384
13426
|
try {
|
|
13385
13427
|
const user = c.get("user");
|
|
13386
|
-
const logger =
|
|
13428
|
+
const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
|
|
13387
13429
|
const configs = await logger.getAllConfigs();
|
|
13388
13430
|
const pageData = {
|
|
13389
13431
|
configs,
|
|
@@ -13407,7 +13449,7 @@ adminLogsRoutes.post("/config/:category", async (c) => {
|
|
|
13407
13449
|
const level = formData.get("level");
|
|
13408
13450
|
const retention = parseInt(formData.get("retention"));
|
|
13409
13451
|
const maxSize = parseInt(formData.get("max_size"));
|
|
13410
|
-
const logger =
|
|
13452
|
+
const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
|
|
13411
13453
|
await logger.updateConfig(category, {
|
|
13412
13454
|
enabled,
|
|
13413
13455
|
level,
|
|
@@ -13436,7 +13478,7 @@ adminLogsRoutes.get("/export", async (c) => {
|
|
|
13436
13478
|
const category = query.category;
|
|
13437
13479
|
const startDate = query.start_date;
|
|
13438
13480
|
const endDate = query.end_date;
|
|
13439
|
-
const logger =
|
|
13481
|
+
const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
|
|
13440
13482
|
const filter = {
|
|
13441
13483
|
limit: 1e4,
|
|
13442
13484
|
// Export up to 10k logs
|
|
@@ -13517,7 +13559,7 @@ adminLogsRoutes.post("/cleanup", async (c) => {
|
|
|
13517
13559
|
error: "Unauthorized. Admin access required."
|
|
13518
13560
|
}, 403);
|
|
13519
13561
|
}
|
|
13520
|
-
const logger =
|
|
13562
|
+
const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
|
|
13521
13563
|
await logger.cleanupByRetention();
|
|
13522
13564
|
return c.html(html.html`
|
|
13523
13565
|
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded">
|
|
@@ -13539,7 +13581,7 @@ adminLogsRoutes.post("/search", async (c) => {
|
|
|
13539
13581
|
const search = formData.get("search");
|
|
13540
13582
|
const level = formData.get("level");
|
|
13541
13583
|
const category = formData.get("category");
|
|
13542
|
-
const logger =
|
|
13584
|
+
const logger = chunk3NVJ6W27_cjs.getLogger(c.env.DB);
|
|
13543
13585
|
const filter = {
|
|
13544
13586
|
limit: 20,
|
|
13545
13587
|
offset: 0,
|
|
@@ -13634,7 +13676,7 @@ adminDesignRoutes.get("/", (c) => {
|
|
|
13634
13676
|
role: user.role
|
|
13635
13677
|
} : void 0
|
|
13636
13678
|
};
|
|
13637
|
-
return c.html(
|
|
13679
|
+
return c.html(chunk3SPQ3J4N_cjs.renderDesignPage(pageData));
|
|
13638
13680
|
});
|
|
13639
13681
|
var adminCheckboxRoutes = new hono.Hono();
|
|
13640
13682
|
adminCheckboxRoutes.get("/", (c) => {
|
|
@@ -13646,7 +13688,7 @@ adminCheckboxRoutes.get("/", (c) => {
|
|
|
13646
13688
|
role: user.role
|
|
13647
13689
|
} : void 0
|
|
13648
13690
|
};
|
|
13649
|
-
return c.html(
|
|
13691
|
+
return c.html(chunk3SPQ3J4N_cjs.renderCheckboxPage(pageData));
|
|
13650
13692
|
});
|
|
13651
13693
|
|
|
13652
13694
|
// src/templates/pages/admin-faq-form.template.ts
|
|
@@ -13674,7 +13716,7 @@ function renderFAQForm(data) {
|
|
|
13674
13716
|
</div>
|
|
13675
13717
|
</div>
|
|
13676
13718
|
|
|
13677
|
-
${message ?
|
|
13719
|
+
${message ? chunk3SPQ3J4N_cjs.renderAlert({ type: messageType || "info", message, dismissible: true }) : ""}
|
|
13678
13720
|
|
|
13679
13721
|
<!-- Form -->
|
|
13680
13722
|
<div class="backdrop-blur-xl bg-white/10 rounded-xl border border-white/20 shadow-2xl">
|
|
@@ -13887,7 +13929,7 @@ function renderFAQForm(data) {
|
|
|
13887
13929
|
user: data.user,
|
|
13888
13930
|
content: pageContent
|
|
13889
13931
|
};
|
|
13890
|
-
return
|
|
13932
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayout(layoutData);
|
|
13891
13933
|
}
|
|
13892
13934
|
function escapeHtml4(unsafe) {
|
|
13893
13935
|
return unsafe.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -13912,7 +13954,7 @@ adminFAQRoutes.get("/", async (c) => {
|
|
|
13912
13954
|
const offset = (currentPage - 1) * limit;
|
|
13913
13955
|
const db = c.env?.DB;
|
|
13914
13956
|
if (!db) {
|
|
13915
|
-
return c.html(
|
|
13957
|
+
return c.html(chunk3SPQ3J4N_cjs.renderFAQList({
|
|
13916
13958
|
faqs: [],
|
|
13917
13959
|
totalCount: 0,
|
|
13918
13960
|
currentPage: 1,
|
|
@@ -13952,7 +13994,7 @@ adminFAQRoutes.get("/", async (c) => {
|
|
|
13952
13994
|
`;
|
|
13953
13995
|
const { results: faqs } = await db.prepare(dataQuery).bind(...params, limit, offset).all();
|
|
13954
13996
|
const totalPages = Math.ceil(totalCount / limit);
|
|
13955
|
-
return c.html(
|
|
13997
|
+
return c.html(chunk3SPQ3J4N_cjs.renderFAQList({
|
|
13956
13998
|
faqs: faqs || [],
|
|
13957
13999
|
totalCount,
|
|
13958
14000
|
currentPage,
|
|
@@ -13966,7 +14008,7 @@ adminFAQRoutes.get("/", async (c) => {
|
|
|
13966
14008
|
} catch (error) {
|
|
13967
14009
|
console.error("Error fetching FAQs:", error);
|
|
13968
14010
|
const user = c.get("user");
|
|
13969
|
-
return c.html(
|
|
14011
|
+
return c.html(chunk3SPQ3J4N_cjs.renderFAQList({
|
|
13970
14012
|
faqs: [],
|
|
13971
14013
|
totalCount: 0,
|
|
13972
14014
|
currentPage: 1,
|
|
@@ -14279,7 +14321,7 @@ function renderTestimonialsForm(data) {
|
|
|
14279
14321
|
</div>
|
|
14280
14322
|
</div>
|
|
14281
14323
|
|
|
14282
|
-
${message ?
|
|
14324
|
+
${message ? chunk3SPQ3J4N_cjs.renderAlert({ type: messageType || "info", message, dismissible: true }) : ""}
|
|
14283
14325
|
|
|
14284
14326
|
<!-- Form -->
|
|
14285
14327
|
<div class="backdrop-blur-xl bg-white/10 rounded-xl border border-white/20 shadow-2xl">
|
|
@@ -14508,7 +14550,7 @@ function renderTestimonialsForm(data) {
|
|
|
14508
14550
|
user: data.user,
|
|
14509
14551
|
content: pageContent
|
|
14510
14552
|
};
|
|
14511
|
-
return
|
|
14553
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayout(layoutData);
|
|
14512
14554
|
}
|
|
14513
14555
|
function escapeHtml5(unsafe) {
|
|
14514
14556
|
return unsafe.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -14534,7 +14576,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
14534
14576
|
const offset = (currentPage - 1) * limit;
|
|
14535
14577
|
const db = c.env?.DB;
|
|
14536
14578
|
if (!db) {
|
|
14537
|
-
return c.html(
|
|
14579
|
+
return c.html(chunk3SPQ3J4N_cjs.renderTestimonialsList({
|
|
14538
14580
|
testimonials: [],
|
|
14539
14581
|
totalCount: 0,
|
|
14540
14582
|
currentPage: 1,
|
|
@@ -14574,7 +14616,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
14574
14616
|
`;
|
|
14575
14617
|
const { results: testimonials } = await db.prepare(dataQuery).bind(...params, limit, offset).all();
|
|
14576
14618
|
const totalPages = Math.ceil(totalCount / limit);
|
|
14577
|
-
return c.html(
|
|
14619
|
+
return c.html(chunk3SPQ3J4N_cjs.renderTestimonialsList({
|
|
14578
14620
|
testimonials: testimonials || [],
|
|
14579
14621
|
totalCount,
|
|
14580
14622
|
currentPage,
|
|
@@ -14588,7 +14630,7 @@ adminTestimonialsRoutes.get("/", async (c) => {
|
|
|
14588
14630
|
} catch (error) {
|
|
14589
14631
|
console.error("Error fetching testimonials:", error);
|
|
14590
14632
|
const user = c.get("user");
|
|
14591
|
-
return c.html(
|
|
14633
|
+
return c.html(chunk3SPQ3J4N_cjs.renderTestimonialsList({
|
|
14592
14634
|
testimonials: [],
|
|
14593
14635
|
totalCount: 0,
|
|
14594
14636
|
currentPage: 1,
|
|
@@ -14907,7 +14949,7 @@ function renderCodeExamplesForm(data) {
|
|
|
14907
14949
|
</div>
|
|
14908
14950
|
</div>
|
|
14909
14951
|
|
|
14910
|
-
${message ?
|
|
14952
|
+
${message ? chunk3SPQ3J4N_cjs.renderAlert({ type: messageType || "info", message, dismissible: true }) : ""}
|
|
14911
14953
|
|
|
14912
14954
|
<!-- Form -->
|
|
14913
14955
|
<div class="backdrop-blur-xl bg-white/10 rounded-xl border border-white/20 shadow-2xl">
|
|
@@ -15177,7 +15219,7 @@ function renderCodeExamplesForm(data) {
|
|
|
15177
15219
|
user: data.user,
|
|
15178
15220
|
content: pageContent
|
|
15179
15221
|
};
|
|
15180
|
-
return
|
|
15222
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayout(layoutData);
|
|
15181
15223
|
}
|
|
15182
15224
|
function escapeHtml6(unsafe) {
|
|
15183
15225
|
return unsafe.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -15204,7 +15246,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
15204
15246
|
const offset = (currentPage - 1) * limit;
|
|
15205
15247
|
const db = c.env?.DB;
|
|
15206
15248
|
if (!db) {
|
|
15207
|
-
return c.html(
|
|
15249
|
+
return c.html(chunk3SPQ3J4N_cjs.renderCodeExamplesList({
|
|
15208
15250
|
codeExamples: [],
|
|
15209
15251
|
totalCount: 0,
|
|
15210
15252
|
currentPage: 1,
|
|
@@ -15244,7 +15286,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
15244
15286
|
`;
|
|
15245
15287
|
const { results: codeExamples } = await db.prepare(dataQuery).bind(...params, limit, offset).all();
|
|
15246
15288
|
const totalPages = Math.ceil(totalCount / limit);
|
|
15247
|
-
return c.html(
|
|
15289
|
+
return c.html(chunk3SPQ3J4N_cjs.renderCodeExamplesList({
|
|
15248
15290
|
codeExamples: codeExamples || [],
|
|
15249
15291
|
totalCount,
|
|
15250
15292
|
currentPage,
|
|
@@ -15258,7 +15300,7 @@ adminCodeExamplesRoutes.get("/", async (c) => {
|
|
|
15258
15300
|
} catch (error) {
|
|
15259
15301
|
console.error("Error fetching code examples:", error);
|
|
15260
15302
|
const user = c.get("user");
|
|
15261
|
-
return c.html(
|
|
15303
|
+
return c.html(chunk3SPQ3J4N_cjs.renderCodeExamplesList({
|
|
15262
15304
|
codeExamples: [],
|
|
15263
15305
|
totalCount: 0,
|
|
15264
15306
|
currentPage: 1,
|
|
@@ -15647,7 +15689,7 @@ function renderDashboardPage(data) {
|
|
|
15647
15689
|
version: data.version,
|
|
15648
15690
|
content: pageContent
|
|
15649
15691
|
};
|
|
15650
|
-
return
|
|
15692
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayout(layoutData);
|
|
15651
15693
|
}
|
|
15652
15694
|
function renderStatsCards(stats) {
|
|
15653
15695
|
const cards = [
|
|
@@ -15745,7 +15787,7 @@ function renderAnalyticsChart() {
|
|
|
15745
15787
|
|
|
15746
15788
|
<!-- Hidden div to trigger HTMX polling -->
|
|
15747
15789
|
<div
|
|
15748
|
-
hx-get="/admin/api/metrics"
|
|
15790
|
+
hx-get="/admin/dashboard/api/metrics"
|
|
15749
15791
|
hx-trigger="every 1s"
|
|
15750
15792
|
hx-swap="none"
|
|
15751
15793
|
style="display: none;"
|
|
@@ -15848,9 +15890,12 @@ function renderAnalyticsChart() {
|
|
|
15848
15890
|
|
|
15849
15891
|
// Listen for metrics updates from HTMX
|
|
15850
15892
|
window.addEventListener('htmx:afterRequest', function(event) {
|
|
15851
|
-
|
|
15893
|
+
console.log('[Dashboard] HTMX request completed:', event.detail.pathInfo.requestPath);
|
|
15894
|
+
|
|
15895
|
+
if (event.detail.pathInfo.requestPath === '/admin/dashboard/api/metrics') {
|
|
15852
15896
|
try {
|
|
15853
15897
|
const metrics = JSON.parse(event.detail.xhr.responseText);
|
|
15898
|
+
console.log('[Dashboard] Metrics received:', metrics);
|
|
15854
15899
|
|
|
15855
15900
|
// Update current RPS display
|
|
15856
15901
|
const rpsElement = document.getElementById('current-rps');
|
|
@@ -15871,8 +15916,9 @@ function renderAnalyticsChart() {
|
|
|
15871
15916
|
chart.data.labels = newLabels;
|
|
15872
15917
|
|
|
15873
15918
|
chart.update('none'); // Update without animation for smoother real-time updates
|
|
15919
|
+
console.log('[Dashboard] Chart updated with RPS:', metrics.requestsPerSecond);
|
|
15874
15920
|
} catch (e) {
|
|
15875
|
-
console.error('Error updating metrics:', e);
|
|
15921
|
+
console.error('[Dashboard] Error updating metrics:', e);
|
|
15876
15922
|
}
|
|
15877
15923
|
}
|
|
15878
15924
|
});
|
|
@@ -16191,9 +16237,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
|
|
|
16191
16237
|
}
|
|
16192
16238
|
|
|
16193
16239
|
// src/routes/admin-dashboard.ts
|
|
16194
|
-
var VERSION =
|
|
16240
|
+
var VERSION = chunkUL32L2KV_cjs.getCoreVersion();
|
|
16195
16241
|
var router = new hono.Hono();
|
|
16196
|
-
router.use("*",
|
|
16242
|
+
router.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
16197
16243
|
router.get("/", async (c) => {
|
|
16198
16244
|
const user = c.get("user");
|
|
16199
16245
|
try {
|
|
@@ -16219,7 +16265,7 @@ router.get("/", async (c) => {
|
|
|
16219
16265
|
return c.html(renderDashboardPage(pageData));
|
|
16220
16266
|
}
|
|
16221
16267
|
});
|
|
16222
|
-
router.get("/
|
|
16268
|
+
router.get("/stats", async (c) => {
|
|
16223
16269
|
try {
|
|
16224
16270
|
const db = c.env.DB;
|
|
16225
16271
|
let collectionsCount = 0;
|
|
@@ -16269,7 +16315,7 @@ router.get("/dashboard/stats", async (c) => {
|
|
|
16269
16315
|
return c.html('<div class="text-red-500">Failed to load statistics</div>');
|
|
16270
16316
|
}
|
|
16271
16317
|
});
|
|
16272
|
-
router.get("/
|
|
16318
|
+
router.get("/storage", async (c) => {
|
|
16273
16319
|
try {
|
|
16274
16320
|
const db = c.env.DB;
|
|
16275
16321
|
let databaseSize = 0;
|
|
@@ -16294,7 +16340,7 @@ router.get("/dashboard/storage", async (c) => {
|
|
|
16294
16340
|
return c.html('<div class="text-red-500">Failed to load storage information</div>');
|
|
16295
16341
|
}
|
|
16296
16342
|
});
|
|
16297
|
-
router.get("/
|
|
16343
|
+
router.get("/recent-activity", async (c) => {
|
|
16298
16344
|
try {
|
|
16299
16345
|
const db = c.env.DB;
|
|
16300
16346
|
const limit = parseInt(c.req.query("limit") || "5");
|
|
@@ -16346,25 +16392,14 @@ router.get("/dashboard/recent-activity", async (c) => {
|
|
|
16346
16392
|
}
|
|
16347
16393
|
});
|
|
16348
16394
|
router.get("/api/metrics", async (c) => {
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16355
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16356
|
-
});
|
|
16357
|
-
} catch (error) {
|
|
16358
|
-
console.error("Error fetching metrics:", error);
|
|
16359
|
-
return c.json({
|
|
16360
|
-
requestsPerSecond: 0,
|
|
16361
|
-
totalRequests: 0,
|
|
16362
|
-
averageRPS: 0,
|
|
16363
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16364
|
-
});
|
|
16365
|
-
}
|
|
16395
|
+
return c.json({
|
|
16396
|
+
requestsPerSecond: chunkRCQ2HIQD_cjs.metricsTracker.getRequestsPerSecond(),
|
|
16397
|
+
totalRequests: chunkRCQ2HIQD_cjs.metricsTracker.getTotalRequests(),
|
|
16398
|
+
averageRPS: Number(chunkRCQ2HIQD_cjs.metricsTracker.getAverageRPS().toFixed(2)),
|
|
16399
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16400
|
+
});
|
|
16366
16401
|
});
|
|
16367
|
-
router.get("/
|
|
16402
|
+
router.get("/system-status", async (c) => {
|
|
16368
16403
|
try {
|
|
16369
16404
|
const html9 = `
|
|
16370
16405
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
@@ -16429,7 +16464,7 @@ router.get("/dashboard/system-status", async (c) => {
|
|
|
16429
16464
|
});
|
|
16430
16465
|
|
|
16431
16466
|
// src/templates/pages/admin-collections-list.template.ts
|
|
16432
|
-
|
|
16467
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
16433
16468
|
|
|
16434
16469
|
// src/templates/components/table.template.ts
|
|
16435
16470
|
function renderTable2(data) {
|
|
@@ -16903,11 +16938,11 @@ function renderCollectionsListPage(data) {
|
|
|
16903
16938
|
version: data.version,
|
|
16904
16939
|
content: pageContent
|
|
16905
16940
|
};
|
|
16906
|
-
return
|
|
16941
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
16907
16942
|
}
|
|
16908
16943
|
|
|
16909
16944
|
// src/templates/pages/admin-collections-form.template.ts
|
|
16910
|
-
|
|
16945
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
16911
16946
|
function renderCollectionFormPage(data) {
|
|
16912
16947
|
const isEdit = data.isEdit || !!data.id;
|
|
16913
16948
|
const title = isEdit ? "Edit Collection" : "Create New Collection";
|
|
@@ -17136,7 +17171,7 @@ function renderCollectionFormPage(data) {
|
|
|
17136
17171
|
}
|
|
17137
17172
|
</style>
|
|
17138
17173
|
|
|
17139
|
-
${
|
|
17174
|
+
${chunk3SPQ3J4N_cjs.renderForm(formData)}
|
|
17140
17175
|
|
|
17141
17176
|
${isEdit && !data.managed ? `
|
|
17142
17177
|
<!-- Fields Management Section -->
|
|
@@ -17680,12 +17715,13 @@ function renderCollectionFormPage(data) {
|
|
|
17680
17715
|
version: data.version,
|
|
17681
17716
|
content: pageContent
|
|
17682
17717
|
};
|
|
17683
|
-
return
|
|
17718
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
17684
17719
|
}
|
|
17685
17720
|
|
|
17686
17721
|
// src/routes/admin-collections.ts
|
|
17687
17722
|
var adminCollectionsRoutes = new hono.Hono();
|
|
17688
|
-
adminCollectionsRoutes.
|
|
17723
|
+
adminCollectionsRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
17724
|
+
adminCollectionsRoutes.get("/", async (c) => {
|
|
17689
17725
|
try {
|
|
17690
17726
|
const user = c.get("user");
|
|
17691
17727
|
const db = c.env.DB;
|
|
@@ -17740,7 +17776,7 @@ adminCollectionsRoutes.get("/collections", async (c) => {
|
|
|
17740
17776
|
return c.html(html.html`<p>Error loading collections</p>`);
|
|
17741
17777
|
}
|
|
17742
17778
|
});
|
|
17743
|
-
adminCollectionsRoutes.get("/
|
|
17779
|
+
adminCollectionsRoutes.get("/new", (c) => {
|
|
17744
17780
|
const user = c.get("user");
|
|
17745
17781
|
const formData = {
|
|
17746
17782
|
isEdit: false,
|
|
@@ -17753,7 +17789,7 @@ adminCollectionsRoutes.get("/collections/new", (c) => {
|
|
|
17753
17789
|
};
|
|
17754
17790
|
return c.html(renderCollectionFormPage(formData));
|
|
17755
17791
|
});
|
|
17756
|
-
adminCollectionsRoutes.post("/
|
|
17792
|
+
adminCollectionsRoutes.post("/", async (c) => {
|
|
17757
17793
|
try {
|
|
17758
17794
|
const formData = await c.req.formData();
|
|
17759
17795
|
const name = formData.get("name");
|
|
@@ -17872,7 +17908,7 @@ adminCollectionsRoutes.post("/collections", async (c) => {
|
|
|
17872
17908
|
}
|
|
17873
17909
|
}
|
|
17874
17910
|
});
|
|
17875
|
-
adminCollectionsRoutes.get("
|
|
17911
|
+
adminCollectionsRoutes.get("/:id", async (c) => {
|
|
17876
17912
|
try {
|
|
17877
17913
|
const id = c.req.param("id");
|
|
17878
17914
|
const user = c.get("user");
|
|
@@ -17940,7 +17976,7 @@ adminCollectionsRoutes.get("/collections/:id", async (c) => {
|
|
|
17940
17976
|
return c.html(renderCollectionFormPage(formData));
|
|
17941
17977
|
}
|
|
17942
17978
|
});
|
|
17943
|
-
adminCollectionsRoutes.put("
|
|
17979
|
+
adminCollectionsRoutes.put("/:id", async (c) => {
|
|
17944
17980
|
try {
|
|
17945
17981
|
const id = c.req.param("id");
|
|
17946
17982
|
const formData = await c.req.formData();
|
|
@@ -17974,7 +18010,7 @@ adminCollectionsRoutes.put("/collections/:id", async (c) => {
|
|
|
17974
18010
|
`);
|
|
17975
18011
|
}
|
|
17976
18012
|
});
|
|
17977
|
-
adminCollectionsRoutes.delete("
|
|
18013
|
+
adminCollectionsRoutes.delete("/:id", async (c) => {
|
|
17978
18014
|
try {
|
|
17979
18015
|
const id = c.req.param("id");
|
|
17980
18016
|
const db = c.env.DB;
|
|
@@ -18005,7 +18041,7 @@ adminCollectionsRoutes.delete("/collections/:id", async (c) => {
|
|
|
18005
18041
|
`);
|
|
18006
18042
|
}
|
|
18007
18043
|
});
|
|
18008
|
-
adminCollectionsRoutes.post("
|
|
18044
|
+
adminCollectionsRoutes.post("/:id/fields", async (c) => {
|
|
18009
18045
|
try {
|
|
18010
18046
|
const collectionId = c.req.param("id");
|
|
18011
18047
|
const formData = await c.req.formData();
|
|
@@ -18058,7 +18094,7 @@ adminCollectionsRoutes.post("/collections/:id/fields", async (c) => {
|
|
|
18058
18094
|
return c.json({ success: false, error: "Failed to add field." });
|
|
18059
18095
|
}
|
|
18060
18096
|
});
|
|
18061
|
-
adminCollectionsRoutes.put("
|
|
18097
|
+
adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
|
|
18062
18098
|
try {
|
|
18063
18099
|
const fieldId = c.req.param("fieldId");
|
|
18064
18100
|
const formData = await c.req.formData();
|
|
@@ -18082,7 +18118,7 @@ adminCollectionsRoutes.put("/collections/:collectionId/fields/:fieldId", async (
|
|
|
18082
18118
|
return c.json({ success: false, error: "Failed to update field." });
|
|
18083
18119
|
}
|
|
18084
18120
|
});
|
|
18085
|
-
adminCollectionsRoutes.delete("
|
|
18121
|
+
adminCollectionsRoutes.delete("/:collectionId/fields/:fieldId", async (c) => {
|
|
18086
18122
|
try {
|
|
18087
18123
|
const fieldId = c.req.param("fieldId");
|
|
18088
18124
|
const db = c.env.DB;
|
|
@@ -18094,7 +18130,7 @@ adminCollectionsRoutes.delete("/collections/:collectionId/fields/:fieldId", asyn
|
|
|
18094
18130
|
return c.json({ success: false, error: "Failed to delete field." });
|
|
18095
18131
|
}
|
|
18096
18132
|
});
|
|
18097
|
-
adminCollectionsRoutes.post("
|
|
18133
|
+
adminCollectionsRoutes.post("/:collectionId/fields/reorder", async (c) => {
|
|
18098
18134
|
try {
|
|
18099
18135
|
const body = await c.req.json();
|
|
18100
18136
|
const fieldIds = body.fieldIds;
|
|
@@ -18114,7 +18150,7 @@ adminCollectionsRoutes.post("/collections/:collectionId/fields/reorder", async (
|
|
|
18114
18150
|
});
|
|
18115
18151
|
|
|
18116
18152
|
// src/templates/pages/admin-settings.template.ts
|
|
18117
|
-
|
|
18153
|
+
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
18118
18154
|
function renderSettingsPage(data) {
|
|
18119
18155
|
const activeTab = data.activeTab || "general";
|
|
18120
18156
|
const pageContent = `
|
|
@@ -18215,7 +18251,7 @@ function renderSettingsPage(data) {
|
|
|
18215
18251
|
// Migration functions
|
|
18216
18252
|
window.refreshMigrationStatus = async function() {
|
|
18217
18253
|
try {
|
|
18218
|
-
const response = await fetch('/admin/api/migrations/status');
|
|
18254
|
+
const response = await fetch('/admin/settings/api/migrations/status');
|
|
18219
18255
|
const result = await response.json();
|
|
18220
18256
|
|
|
18221
18257
|
if (result.success) {
|
|
@@ -18243,7 +18279,7 @@ function renderSettingsPage(data) {
|
|
|
18243
18279
|
btn.innerHTML = 'Running...';
|
|
18244
18280
|
|
|
18245
18281
|
try {
|
|
18246
|
-
const response = await fetch('/admin/api/migrations/run', {
|
|
18282
|
+
const response = await fetch('/admin/settings/api/migrations/run', {
|
|
18247
18283
|
method: 'POST'
|
|
18248
18284
|
});
|
|
18249
18285
|
const result = await response.json();
|
|
@@ -18264,7 +18300,7 @@ function renderSettingsPage(data) {
|
|
|
18264
18300
|
|
|
18265
18301
|
window.validateSchema = async function() {
|
|
18266
18302
|
try {
|
|
18267
|
-
const response = await fetch('/admin/api/migrations/validate');
|
|
18303
|
+
const response = await fetch('/admin/settings/api/migrations/validate');
|
|
18268
18304
|
const result = await response.json();
|
|
18269
18305
|
|
|
18270
18306
|
if (result.success) {
|
|
@@ -18342,7 +18378,7 @@ function renderSettingsPage(data) {
|
|
|
18342
18378
|
// Database Tools functions
|
|
18343
18379
|
window.refreshDatabaseStats = async function() {
|
|
18344
18380
|
try {
|
|
18345
|
-
const response = await fetch('/admin/database-tools/
|
|
18381
|
+
const response = await fetch('/admin/settings/api/database-tools/stats');
|
|
18346
18382
|
const result = await response.json();
|
|
18347
18383
|
|
|
18348
18384
|
if (result.success) {
|
|
@@ -18363,7 +18399,7 @@ function renderSettingsPage(data) {
|
|
|
18363
18399
|
btn.innerHTML = 'Creating Backup...';
|
|
18364
18400
|
|
|
18365
18401
|
try {
|
|
18366
|
-
const response = await fetch('/admin/database-tools/
|
|
18402
|
+
const response = await fetch('/admin/settings/api/database-tools/backup', {
|
|
18367
18403
|
method: 'POST'
|
|
18368
18404
|
});
|
|
18369
18405
|
const result = await response.json();
|
|
@@ -18402,7 +18438,7 @@ function renderSettingsPage(data) {
|
|
|
18402
18438
|
btn.innerHTML = 'Truncating...';
|
|
18403
18439
|
|
|
18404
18440
|
try {
|
|
18405
|
-
const response = await fetch('/admin/database-tools/
|
|
18441
|
+
const response = await fetch('/admin/settings/api/database-tools/truncate', {
|
|
18406
18442
|
method: 'POST',
|
|
18407
18443
|
headers: {
|
|
18408
18444
|
'Content-Type': 'application/json'
|
|
@@ -18433,7 +18469,7 @@ function renderSettingsPage(data) {
|
|
|
18433
18469
|
|
|
18434
18470
|
window.validateDatabase = async function() {
|
|
18435
18471
|
try {
|
|
18436
|
-
const response = await fetch('/admin/database-tools/
|
|
18472
|
+
const response = await fetch('/admin/settings/api/database-tools/validate');
|
|
18437
18473
|
const result = await response.json();
|
|
18438
18474
|
|
|
18439
18475
|
if (result.success) {
|
|
@@ -18524,7 +18560,7 @@ function renderSettingsPage(data) {
|
|
|
18524
18560
|
version: data.version,
|
|
18525
18561
|
content: pageContent
|
|
18526
18562
|
};
|
|
18527
|
-
return
|
|
18563
|
+
return chunk3SPQ3J4N_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
18528
18564
|
}
|
|
18529
18565
|
function renderTabButton(tabId, label, iconPath, activeTab) {
|
|
18530
18566
|
const isActive = activeTab === tabId;
|
|
@@ -19287,7 +19323,7 @@ function renderMigrationSettings(settings) {
|
|
|
19287
19323
|
if (typeof refreshMigrationStatus === 'undefined') {
|
|
19288
19324
|
window.refreshMigrationStatus = async function() {
|
|
19289
19325
|
try {
|
|
19290
|
-
const response = await fetch('/admin/api/migrations/status');
|
|
19326
|
+
const response = await fetch('/admin/settings/api/migrations/status');
|
|
19291
19327
|
const result = await response.json();
|
|
19292
19328
|
|
|
19293
19329
|
if (result.success) {
|
|
@@ -19541,6 +19577,7 @@ function renderDatabaseToolsSettings(settings) {
|
|
|
19541
19577
|
|
|
19542
19578
|
// src/routes/admin-settings.ts
|
|
19543
19579
|
var adminSettingsRoutes = new hono.Hono();
|
|
19580
|
+
adminSettingsRoutes.use("*", chunk4BJGEGX5_cjs.requireAuth());
|
|
19544
19581
|
function getMockSettings(user) {
|
|
19545
19582
|
return {
|
|
19546
19583
|
general: {
|
|
@@ -19599,10 +19636,10 @@ function getMockSettings(user) {
|
|
|
19599
19636
|
}
|
|
19600
19637
|
};
|
|
19601
19638
|
}
|
|
19602
|
-
adminSettingsRoutes.get("/
|
|
19639
|
+
adminSettingsRoutes.get("/", (c) => {
|
|
19603
19640
|
return c.redirect("/admin/settings/general");
|
|
19604
19641
|
});
|
|
19605
|
-
adminSettingsRoutes.get("/
|
|
19642
|
+
adminSettingsRoutes.get("/general", (c) => {
|
|
19606
19643
|
const user = c.get("user");
|
|
19607
19644
|
const pageData = {
|
|
19608
19645
|
user: user ? {
|
|
@@ -19616,7 +19653,7 @@ adminSettingsRoutes.get("/settings/general", (c) => {
|
|
|
19616
19653
|
};
|
|
19617
19654
|
return c.html(renderSettingsPage(pageData));
|
|
19618
19655
|
});
|
|
19619
|
-
adminSettingsRoutes.get("/
|
|
19656
|
+
adminSettingsRoutes.get("/appearance", (c) => {
|
|
19620
19657
|
const user = c.get("user");
|
|
19621
19658
|
const pageData = {
|
|
19622
19659
|
user: user ? {
|
|
@@ -19630,7 +19667,7 @@ adminSettingsRoutes.get("/settings/appearance", (c) => {
|
|
|
19630
19667
|
};
|
|
19631
19668
|
return c.html(renderSettingsPage(pageData));
|
|
19632
19669
|
});
|
|
19633
|
-
adminSettingsRoutes.get("/
|
|
19670
|
+
adminSettingsRoutes.get("/security", (c) => {
|
|
19634
19671
|
const user = c.get("user");
|
|
19635
19672
|
const pageData = {
|
|
19636
19673
|
user: user ? {
|
|
@@ -19644,7 +19681,7 @@ adminSettingsRoutes.get("/settings/security", (c) => {
|
|
|
19644
19681
|
};
|
|
19645
19682
|
return c.html(renderSettingsPage(pageData));
|
|
19646
19683
|
});
|
|
19647
|
-
adminSettingsRoutes.get("/
|
|
19684
|
+
adminSettingsRoutes.get("/notifications", (c) => {
|
|
19648
19685
|
const user = c.get("user");
|
|
19649
19686
|
const pageData = {
|
|
19650
19687
|
user: user ? {
|
|
@@ -19658,7 +19695,7 @@ adminSettingsRoutes.get("/settings/notifications", (c) => {
|
|
|
19658
19695
|
};
|
|
19659
19696
|
return c.html(renderSettingsPage(pageData));
|
|
19660
19697
|
});
|
|
19661
|
-
adminSettingsRoutes.get("/
|
|
19698
|
+
adminSettingsRoutes.get("/storage", (c) => {
|
|
19662
19699
|
const user = c.get("user");
|
|
19663
19700
|
const pageData = {
|
|
19664
19701
|
user: user ? {
|
|
@@ -19672,7 +19709,7 @@ adminSettingsRoutes.get("/settings/storage", (c) => {
|
|
|
19672
19709
|
};
|
|
19673
19710
|
return c.html(renderSettingsPage(pageData));
|
|
19674
19711
|
});
|
|
19675
|
-
adminSettingsRoutes.get("/
|
|
19712
|
+
adminSettingsRoutes.get("/migrations", (c) => {
|
|
19676
19713
|
const user = c.get("user");
|
|
19677
19714
|
const pageData = {
|
|
19678
19715
|
user: user ? {
|
|
@@ -19686,7 +19723,7 @@ adminSettingsRoutes.get("/settings/migrations", (c) => {
|
|
|
19686
19723
|
};
|
|
19687
19724
|
return c.html(renderSettingsPage(pageData));
|
|
19688
19725
|
});
|
|
19689
|
-
adminSettingsRoutes.get("/
|
|
19726
|
+
adminSettingsRoutes.get("/database-tools", (c) => {
|
|
19690
19727
|
const user = c.get("user");
|
|
19691
19728
|
const pageData = {
|
|
19692
19729
|
user: user ? {
|
|
@@ -19759,7 +19796,139 @@ adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
|
19759
19796
|
}, 500);
|
|
19760
19797
|
}
|
|
19761
19798
|
});
|
|
19762
|
-
adminSettingsRoutes.
|
|
19799
|
+
adminSettingsRoutes.get("/api/database-tools/stats", async (c) => {
|
|
19800
|
+
try {
|
|
19801
|
+
const db = c.env.DB;
|
|
19802
|
+
const tablesQuery = await db.prepare(`
|
|
19803
|
+
SELECT name FROM sqlite_master
|
|
19804
|
+
WHERE type='table'
|
|
19805
|
+
AND name NOT LIKE 'sqlite_%'
|
|
19806
|
+
AND name NOT LIKE '_cf_%'
|
|
19807
|
+
ORDER BY name
|
|
19808
|
+
`).all();
|
|
19809
|
+
const tables = tablesQuery.results || [];
|
|
19810
|
+
let totalRows = 0;
|
|
19811
|
+
const tableStats = await Promise.all(
|
|
19812
|
+
tables.map(async (table) => {
|
|
19813
|
+
try {
|
|
19814
|
+
const countResult = await db.prepare(`SELECT COUNT(*) as count FROM ${table.name}`).first();
|
|
19815
|
+
const rowCount = countResult?.count || 0;
|
|
19816
|
+
totalRows += rowCount;
|
|
19817
|
+
return {
|
|
19818
|
+
name: table.name,
|
|
19819
|
+
rowCount
|
|
19820
|
+
};
|
|
19821
|
+
} catch (error) {
|
|
19822
|
+
console.error(`Error counting rows in ${table.name}:`, error);
|
|
19823
|
+
return {
|
|
19824
|
+
name: table.name,
|
|
19825
|
+
rowCount: 0
|
|
19826
|
+
};
|
|
19827
|
+
}
|
|
19828
|
+
})
|
|
19829
|
+
);
|
|
19830
|
+
const estimatedSizeBytes = totalRows * 1024;
|
|
19831
|
+
const databaseSizeMB = (estimatedSizeBytes / (1024 * 1024)).toFixed(2);
|
|
19832
|
+
return c.json({
|
|
19833
|
+
success: true,
|
|
19834
|
+
data: {
|
|
19835
|
+
totalTables: tables.length,
|
|
19836
|
+
totalRows,
|
|
19837
|
+
databaseSize: `${databaseSizeMB} MB (estimated)`,
|
|
19838
|
+
tables: tableStats
|
|
19839
|
+
}
|
|
19840
|
+
});
|
|
19841
|
+
} catch (error) {
|
|
19842
|
+
console.error("Error fetching database stats:", error);
|
|
19843
|
+
return c.json({
|
|
19844
|
+
success: false,
|
|
19845
|
+
error: "Failed to fetch database statistics"
|
|
19846
|
+
}, 500);
|
|
19847
|
+
}
|
|
19848
|
+
});
|
|
19849
|
+
adminSettingsRoutes.get("/api/database-tools/validate", async (c) => {
|
|
19850
|
+
try {
|
|
19851
|
+
const db = c.env.DB;
|
|
19852
|
+
const integrityResult = await db.prepare("PRAGMA integrity_check").first();
|
|
19853
|
+
const isValid = integrityResult?.integrity_check === "ok";
|
|
19854
|
+
return c.json({
|
|
19855
|
+
success: true,
|
|
19856
|
+
data: {
|
|
19857
|
+
valid: isValid,
|
|
19858
|
+
message: isValid ? "Database integrity check passed" : "Database integrity check failed"
|
|
19859
|
+
}
|
|
19860
|
+
});
|
|
19861
|
+
} catch (error) {
|
|
19862
|
+
console.error("Error validating database:", error);
|
|
19863
|
+
return c.json({
|
|
19864
|
+
success: false,
|
|
19865
|
+
error: "Failed to validate database"
|
|
19866
|
+
}, 500);
|
|
19867
|
+
}
|
|
19868
|
+
});
|
|
19869
|
+
adminSettingsRoutes.post("/api/database-tools/backup", async (c) => {
|
|
19870
|
+
try {
|
|
19871
|
+
const user = c.get("user");
|
|
19872
|
+
if (!user || user.role !== "admin") {
|
|
19873
|
+
return c.json({
|
|
19874
|
+
success: false,
|
|
19875
|
+
error: "Unauthorized. Admin access required."
|
|
19876
|
+
}, 403);
|
|
19877
|
+
}
|
|
19878
|
+
return c.json({
|
|
19879
|
+
success: true,
|
|
19880
|
+
message: "Database backup feature coming soon. Use Cloudflare Dashboard for backups."
|
|
19881
|
+
});
|
|
19882
|
+
} catch (error) {
|
|
19883
|
+
console.error("Error creating backup:", error);
|
|
19884
|
+
return c.json({
|
|
19885
|
+
success: false,
|
|
19886
|
+
error: "Failed to create backup"
|
|
19887
|
+
}, 500);
|
|
19888
|
+
}
|
|
19889
|
+
});
|
|
19890
|
+
adminSettingsRoutes.post("/api/database-tools/truncate", async (c) => {
|
|
19891
|
+
try {
|
|
19892
|
+
const user = c.get("user");
|
|
19893
|
+
if (!user || user.role !== "admin") {
|
|
19894
|
+
return c.json({
|
|
19895
|
+
success: false,
|
|
19896
|
+
error: "Unauthorized. Admin access required."
|
|
19897
|
+
}, 403);
|
|
19898
|
+
}
|
|
19899
|
+
const body = await c.req.json();
|
|
19900
|
+
const tablesToTruncate = body.tables || [];
|
|
19901
|
+
if (!Array.isArray(tablesToTruncate) || tablesToTruncate.length === 0) {
|
|
19902
|
+
return c.json({
|
|
19903
|
+
success: false,
|
|
19904
|
+
error: "No tables specified for truncation"
|
|
19905
|
+
}, 400);
|
|
19906
|
+
}
|
|
19907
|
+
const db = c.env.DB;
|
|
19908
|
+
const results = [];
|
|
19909
|
+
for (const tableName of tablesToTruncate) {
|
|
19910
|
+
try {
|
|
19911
|
+
await db.prepare(`DELETE FROM ${tableName}`).run();
|
|
19912
|
+
results.push({ table: tableName, success: true });
|
|
19913
|
+
} catch (error) {
|
|
19914
|
+
console.error(`Error truncating ${tableName}:`, error);
|
|
19915
|
+
results.push({ table: tableName, success: false, error: String(error) });
|
|
19916
|
+
}
|
|
19917
|
+
}
|
|
19918
|
+
return c.json({
|
|
19919
|
+
success: true,
|
|
19920
|
+
message: `Truncated ${results.filter((r) => r.success).length} of ${tablesToTruncate.length} tables`,
|
|
19921
|
+
results
|
|
19922
|
+
});
|
|
19923
|
+
} catch (error) {
|
|
19924
|
+
console.error("Error truncating tables:", error);
|
|
19925
|
+
return c.json({
|
|
19926
|
+
success: false,
|
|
19927
|
+
error: "Failed to truncate tables"
|
|
19928
|
+
}, 500);
|
|
19929
|
+
}
|
|
19930
|
+
});
|
|
19931
|
+
adminSettingsRoutes.post("/", async (c) => {
|
|
19763
19932
|
try {
|
|
19764
19933
|
const formData = await c.req.formData();
|
|
19765
19934
|
return c.html(html.html`
|
|
@@ -19830,5 +19999,5 @@ exports.api_system_default = api_system_default;
|
|
|
19830
19999
|
exports.auth_default = auth_default;
|
|
19831
20000
|
exports.router = router;
|
|
19832
20001
|
exports.userRoutes = userRoutes;
|
|
19833
|
-
//# sourceMappingURL=chunk-
|
|
19834
|
-
//# sourceMappingURL=chunk-
|
|
20002
|
+
//# sourceMappingURL=chunk-5B3VMVEX.cjs.map
|
|
20003
|
+
//# sourceMappingURL=chunk-5B3VMVEX.cjs.map
|