@intranefr/superbackend 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +5 -0
- package/README.md +11 -0
- package/index.js +23 -0
- package/package.json +7 -2
- package/src/admin/endpointRegistry.js +120 -0
- package/src/controllers/admin.controller.js +22 -5
- package/src/controllers/adminBlockDefinitions.controller.js +127 -0
- package/src/controllers/adminBlockDefinitionsAi.controller.js +54 -0
- package/src/controllers/adminCache.controller.js +342 -0
- package/src/controllers/adminContextBlockDefinitions.controller.js +141 -0
- package/src/controllers/adminCrons.controller.js +388 -0
- package/src/controllers/adminDbBrowser.controller.js +124 -0
- package/src/controllers/adminEjsVirtual.controller.js +13 -3
- package/src/controllers/adminHeadless.controller.js +9 -2
- package/src/controllers/adminHealthChecks.controller.js +570 -0
- package/src/controllers/adminI18n.controller.js +51 -29
- package/src/controllers/adminLlm.controller.js +126 -2
- package/src/controllers/adminPages.controller.js +720 -0
- package/src/controllers/adminPagesContextBlocksAi.controller.js +54 -0
- package/src/controllers/adminProxy.controller.js +113 -0
- package/src/controllers/adminRateLimits.controller.js +138 -0
- package/src/controllers/adminRbac.controller.js +803 -0
- package/src/controllers/adminScripts.controller.js +93 -2
- package/src/controllers/adminSeoConfig.controller.js +71 -48
- package/src/controllers/blogAdmin.controller.js +279 -0
- package/src/controllers/blogAiAdmin.controller.js +224 -0
- package/src/controllers/blogAutomationAdmin.controller.js +141 -0
- package/src/controllers/blogInternal.controller.js +26 -0
- package/src/controllers/blogPublic.controller.js +89 -0
- package/src/controllers/fileManager.controller.js +190 -0
- package/src/controllers/fileManagerStoragePolicy.controller.js +23 -0
- package/src/controllers/healthChecksPublic.controller.js +196 -0
- package/src/controllers/metrics.controller.js +64 -4
- package/src/controllers/orgAdmin.controller.js +80 -0
- package/src/middleware/internalCronAuth.js +29 -0
- package/src/middleware/rbac.js +62 -0
- package/src/middleware.js +756 -48
- package/src/models/BlockDefinition.js +27 -0
- package/src/models/BlogAutomationLock.js +14 -0
- package/src/models/BlogAutomationRun.js +39 -0
- package/src/models/BlogPost.js +42 -0
- package/src/models/CacheEntry.js +26 -0
- package/src/models/ConsoleEntry.js +32 -0
- package/src/models/ConsoleLog.js +23 -0
- package/src/models/ContextBlockDefinition.js +33 -0
- package/src/models/CronExecution.js +47 -0
- package/src/models/CronJob.js +70 -0
- package/src/models/ExternalDbConnection.js +49 -0
- package/src/models/FileEntry.js +22 -0
- package/src/models/HealthAutoHealAttempt.js +57 -0
- package/src/models/HealthCheck.js +132 -0
- package/src/models/HealthCheckRun.js +51 -0
- package/src/models/HealthIncident.js +49 -0
- package/src/models/Page.js +95 -0
- package/src/models/PageCollection.js +42 -0
- package/src/models/ProxyEntry.js +66 -0
- package/src/models/RateLimitCounter.js +19 -0
- package/src/models/RateLimitMetricBucket.js +20 -0
- package/src/models/RbacGrant.js +25 -0
- package/src/models/RbacGroup.js +16 -0
- package/src/models/RbacGroupMember.js +13 -0
- package/src/models/RbacGroupRole.js +13 -0
- package/src/models/RbacRole.js +25 -0
- package/src/models/RbacUserRole.js +13 -0
- package/src/routes/adminBlog.routes.js +21 -0
- package/src/routes/adminBlogAi.routes.js +16 -0
- package/src/routes/adminBlogAutomation.routes.js +27 -0
- package/src/routes/adminCache.routes.js +20 -0
- package/src/routes/adminConsoleManager.routes.js +302 -0
- package/src/routes/adminCrons.routes.js +25 -0
- package/src/routes/adminDbBrowser.routes.js +65 -0
- package/src/routes/adminEjsVirtual.routes.js +2 -1
- package/src/routes/adminHeadless.routes.js +2 -1
- package/src/routes/adminHealthChecks.routes.js +28 -0
- package/src/routes/adminI18n.routes.js +4 -3
- package/src/routes/adminLlm.routes.js +4 -2
- package/src/routes/adminPages.routes.js +55 -0
- package/src/routes/adminProxy.routes.js +15 -0
- package/src/routes/adminRateLimits.routes.js +17 -0
- package/src/routes/adminRbac.routes.js +38 -0
- package/src/routes/adminSeoConfig.routes.js +5 -4
- package/src/routes/adminUiComponents.routes.js +2 -1
- package/src/routes/blogInternal.routes.js +14 -0
- package/src/routes/blogPublic.routes.js +9 -0
- package/src/routes/fileManager.routes.js +62 -0
- package/src/routes/fileManagerStoragePolicy.routes.js +9 -0
- package/src/routes/healthChecksPublic.routes.js +9 -0
- package/src/routes/log.routes.js +43 -60
- package/src/routes/metrics.routes.js +4 -2
- package/src/routes/orgAdmin.routes.js +1 -0
- package/src/routes/pages.routes.js +123 -0
- package/src/routes/proxy.routes.js +46 -0
- package/src/routes/rbac.routes.js +47 -0
- package/src/routes/webhook.routes.js +2 -1
- package/src/routes/workflows.routes.js +4 -0
- package/src/services/blockDefinitionsAi.service.js +247 -0
- package/src/services/blog.service.js +99 -0
- package/src/services/blogAutomation.service.js +978 -0
- package/src/services/blogCronsBootstrap.service.js +184 -0
- package/src/services/blogPublishing.service.js +58 -0
- package/src/services/cacheLayer.service.js +696 -0
- package/src/services/consoleManager.service.js +700 -0
- package/src/services/consoleOverride.service.js +6 -1
- package/src/services/cronScheduler.service.js +350 -0
- package/src/services/dbBrowser.service.js +536 -0
- package/src/services/ejsVirtual.service.js +102 -32
- package/src/services/fileManager.service.js +475 -0
- package/src/services/fileManagerStoragePolicy.service.js +285 -0
- package/src/services/healthChecks.service.js +650 -0
- package/src/services/healthChecksBootstrap.service.js +109 -0
- package/src/services/healthChecksScheduler.service.js +106 -0
- package/src/services/llmDefaults.service.js +190 -0
- package/src/services/migrationAssets/s3.js +2 -2
- package/src/services/pages.service.js +602 -0
- package/src/services/pagesContext.service.js +331 -0
- package/src/services/pagesContextBlocksAi.service.js +349 -0
- package/src/services/proxy.service.js +535 -0
- package/src/services/rateLimiter.service.js +623 -0
- package/src/services/rbac.service.js +212 -0
- package/src/services/scriptsRunner.service.js +1 -1
- package/src/services/uiComponentsAi.service.js +6 -19
- package/src/services/workflow.service.js +23 -8
- package/src/utils/orgRoles.js +14 -0
- package/src/utils/rbac/engine.js +60 -0
- package/src/utils/rbac/rightsRegistry.js +29 -0
- package/views/admin-blog-automation.ejs +877 -0
- package/views/admin-blog-edit.ejs +542 -0
- package/views/admin-blog.ejs +399 -0
- package/views/admin-cache.ejs +681 -0
- package/views/admin-console-manager.ejs +680 -0
- package/views/admin-crons.ejs +645 -0
- package/views/admin-db-browser.ejs +445 -0
- package/views/admin-ejs-virtual.ejs +16 -10
- package/views/admin-file-manager.ejs +942 -0
- package/views/admin-health-checks.ejs +725 -0
- package/views/admin-i18n.ejs +59 -5
- package/views/admin-llm.ejs +99 -1
- package/views/admin-organizations.ejs +163 -1
- package/views/admin-pages.ejs +2424 -0
- package/views/admin-proxy.ejs +491 -0
- package/views/admin-rate-limiter.ejs +625 -0
- package/views/admin-rbac.ejs +1331 -0
- package/views/admin-scripts.ejs +1 -1
- package/views/admin-seo-config.ejs +61 -7
- package/views/admin-ui-components.ejs +57 -25
- package/views/admin-workflows.ejs +7 -7
- package/views/file-manager.ejs +866 -0
- package/views/pages/blocks/contact.ejs +27 -0
- package/views/pages/blocks/cta.ejs +18 -0
- package/views/pages/blocks/faq.ejs +20 -0
- package/views/pages/blocks/features.ejs +19 -0
- package/views/pages/blocks/hero.ejs +13 -0
- package/views/pages/blocks/html.ejs +5 -0
- package/views/pages/blocks/image.ejs +14 -0
- package/views/pages/blocks/testimonials.ejs +26 -0
- package/views/pages/blocks/text.ejs +10 -0
- package/views/pages/layouts/default.ejs +51 -0
- package/views/pages/layouts/minimal.ejs +42 -0
- package/views/pages/layouts/sidebar.ejs +54 -0
- package/views/pages/partials/footer.ejs +13 -0
- package/views/pages/partials/header.ejs +12 -0
- package/views/pages/partials/sidebar.ejs +8 -0
- package/views/pages/runtime/page.ejs +10 -0
- package/views/pages/templates/article.ejs +20 -0
- package/views/pages/templates/default.ejs +12 -0
- package/views/pages/templates/landing.ejs +14 -0
- package/views/pages/templates/listing.ejs +15 -0
- package/views/partials/admin-image-upload-modal.ejs +221 -0
- package/views/partials/dashboard/nav-items.ejs +11 -0
- package/views/partials/llm-provider-model-picker.ejs +183 -0
- package/src/routes/llmUi.routes.js +0 -26
package/src/middleware.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
const consoleOverride = require("./services/consoleOverride.service");
|
|
2
|
+
const consoleManager = require("./services/consoleManager.service");
|
|
3
|
+
|
|
4
|
+
// Initialize console override service early to capture all logs
|
|
5
|
+
// Avoid keeping timers/streams alive during Jest runs.
|
|
6
|
+
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
7
|
+
consoleOverride.init()
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
const express = require("express");
|
|
2
11
|
const path = require("path");
|
|
3
12
|
const mongoose = require("mongoose");
|
|
@@ -6,17 +15,54 @@ const fs = require("fs");
|
|
|
6
15
|
const ejs = require("ejs");
|
|
7
16
|
const { basicAuth } = require("./middleware/auth");
|
|
8
17
|
const endpointRegistry = require("./admin/endpointRegistry");
|
|
9
|
-
const {
|
|
10
|
-
|
|
18
|
+
const {
|
|
19
|
+
createFeatureFlagsEjsMiddleware,
|
|
20
|
+
} = require("./services/featureFlags.service");
|
|
21
|
+
const globalSettingsService = require("./services/globalSettings.service");
|
|
22
|
+
const cronScheduler = require("./services/cronScheduler.service");
|
|
23
|
+
const healthChecksScheduler = require("./services/healthChecksScheduler.service");
|
|
24
|
+
const healthChecksBootstrap = require("./services/healthChecksBootstrap.service");
|
|
25
|
+
const blogCronsBootstrap = require("./services/blogCronsBootstrap.service");
|
|
11
26
|
const {
|
|
12
27
|
hookConsoleError,
|
|
13
28
|
setupProcessHandlers,
|
|
14
29
|
expressErrorMiddleware,
|
|
15
30
|
requestIdMiddleware,
|
|
16
31
|
} = require("./middleware/errorCapture");
|
|
32
|
+
const rateLimiter = require("./services/rateLimiter.service");
|
|
17
33
|
|
|
18
34
|
let errorCaptureInitialized = false;
|
|
19
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Check if console manager should be enabled based on environment variable and global settings
|
|
38
|
+
* Priority: Environment Variable > Global Settings > Default (true)
|
|
39
|
+
* @returns {Promise<boolean>} Whether console manager should be enabled
|
|
40
|
+
*/
|
|
41
|
+
async function isConsoleManagerEnabled() {
|
|
42
|
+
// Environment variable takes highest priority
|
|
43
|
+
const envEnabled = process.env.CONSOLE_MANAGER_ENABLED;
|
|
44
|
+
if (envEnabled !== undefined) {
|
|
45
|
+
const enabled = String(envEnabled).toLowerCase() !== 'false';
|
|
46
|
+
console.log(`[Console Manager] Environment variable CONSOLE_MANAGER_ENABLED=${envEnabled}, ${enabled ? 'enabled' : 'disabled'}`);
|
|
47
|
+
return enabled;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check global settings if environment variable not set
|
|
51
|
+
try {
|
|
52
|
+
const enabledRaw = await globalSettingsService.getSettingValue(
|
|
53
|
+
"CONSOLE_MANAGER_ENABLED",
|
|
54
|
+
"true"
|
|
55
|
+
);
|
|
56
|
+
const enabled = String(enabledRaw) === "true";
|
|
57
|
+
console.log(`[Console Manager] Global setting CONSOLE_MANAGER_ENABLED=${enabledRaw}, ${enabled ? 'enabled' : 'disabled'}`);
|
|
58
|
+
return enabled;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("[Console Manager] Error loading global setting:", error);
|
|
61
|
+
console.log("[Console Manager] Fallback to enabled due to error");
|
|
62
|
+
return true; // Fallback to enabled on error
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
20
66
|
/**
|
|
21
67
|
* Creates and configures the SaaS backend middleware
|
|
22
68
|
* @param {Object} options - Configuration options
|
|
@@ -30,26 +76,65 @@ let errorCaptureInitialized = false;
|
|
|
30
76
|
function createMiddleware(options = {}) {
|
|
31
77
|
const router = express.Router();
|
|
32
78
|
const adminPath = options.adminPath || "/admin";
|
|
79
|
+
const pagesPrefix = options.pagesPrefix || "/";
|
|
33
80
|
|
|
34
|
-
|
|
81
|
+
const normalizeBasePath = (value) => {
|
|
82
|
+
const v = String(value || "").trim();
|
|
83
|
+
if (!v) return "/files";
|
|
84
|
+
return v.startsWith("/") ? v : `/${v}`;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const fileManagerPublicConfig = {
|
|
88
|
+
enabled: false,
|
|
89
|
+
basePath: "/files",
|
|
90
|
+
loaded: false,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Restart-required behavior: we load settings once and keep the values in memory.
|
|
94
|
+
(async () => {
|
|
95
|
+
try {
|
|
96
|
+
const enabledRaw = await globalSettingsService.getSettingValue(
|
|
97
|
+
"FILE_MANAGER_ENABLED",
|
|
98
|
+
"false",
|
|
99
|
+
);
|
|
100
|
+
const basePathRaw = await globalSettingsService.getSettingValue(
|
|
101
|
+
"FILE_MANAGER_BASE_PATH",
|
|
102
|
+
"/files",
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
fileManagerPublicConfig.enabled = String(enabledRaw) === "true";
|
|
106
|
+
fileManagerPublicConfig.basePath = normalizeBasePath(basePathRaw);
|
|
107
|
+
fileManagerPublicConfig.loaded = true;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error("Error loading File Manager public config:", error);
|
|
110
|
+
fileManagerPublicConfig.loaded = true;
|
|
111
|
+
}
|
|
112
|
+
})();
|
|
113
|
+
|
|
114
|
+
// Expose adminPath, pagesPrefix and WS attachment helper
|
|
35
115
|
router.adminPath = adminPath;
|
|
116
|
+
router.pagesPrefix = pagesPrefix;
|
|
36
117
|
router.attachWs = (server) => {
|
|
37
|
-
const {
|
|
118
|
+
const {
|
|
119
|
+
attachTerminalWebsocketServer,
|
|
120
|
+
} = require("./services/terminalsWs.service");
|
|
38
121
|
attachTerminalWebsocketServer(server, { basePathPrefix: adminPath });
|
|
39
122
|
};
|
|
40
123
|
|
|
41
|
-
// Initialize console override service early to capture all logs
|
|
42
|
-
consoleOverride.init();
|
|
43
|
-
|
|
44
124
|
if (!errorCaptureInitialized) {
|
|
45
125
|
errorCaptureInitialized = true;
|
|
46
126
|
hookConsoleError();
|
|
47
127
|
setupProcessHandlers();
|
|
48
128
|
}
|
|
49
129
|
|
|
130
|
+
// Console manager will be initialized after database connection
|
|
131
|
+
|
|
50
132
|
// Database connection
|
|
51
133
|
const mongoUri =
|
|
52
|
-
options.mongodbUri ||
|
|
134
|
+
options.mongodbUri ||
|
|
135
|
+
options.dbConnection ||
|
|
136
|
+
process.env.MONGODB_URI ||
|
|
137
|
+
process.env.MONGO_URI;
|
|
53
138
|
|
|
54
139
|
if (!mongoUri && mongoose.connection.readyState !== 1) {
|
|
55
140
|
console.warn(
|
|
@@ -60,23 +145,132 @@ function createMiddleware(options = {}) {
|
|
|
60
145
|
serverSelectionTimeoutMS: 5000,
|
|
61
146
|
maxPoolSize: 10,
|
|
62
147
|
};
|
|
63
|
-
|
|
148
|
+
|
|
64
149
|
// Return a promise that resolves when connection is established
|
|
65
150
|
const connectionPromise = mongoose
|
|
66
151
|
.connect(mongoUri, connectionOptions)
|
|
67
|
-
.then(() => {
|
|
152
|
+
.then(async () => {
|
|
68
153
|
console.log("✅ Middleware: Connected to MongoDB");
|
|
154
|
+
// Start cron scheduler after DB connection
|
|
155
|
+
await cronScheduler.start();
|
|
156
|
+
await healthChecksScheduler.start();
|
|
157
|
+
await healthChecksBootstrap.bootstrap();
|
|
158
|
+
await blogCronsBootstrap.bootstrap();
|
|
159
|
+
|
|
160
|
+
// Initialize console manager AFTER database is connected
|
|
161
|
+
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
162
|
+
const consoleManagerEnabled = await isConsoleManagerEnabled();
|
|
163
|
+
if (consoleManagerEnabled) {
|
|
164
|
+
consoleManager.init();
|
|
165
|
+
console.log("[Console Manager] Initialized");
|
|
166
|
+
} else {
|
|
167
|
+
console.log("[Console Manager] Disabled - console methods not overridden");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
69
171
|
return true;
|
|
70
172
|
})
|
|
71
173
|
.catch((err) => {
|
|
72
174
|
console.error("❌ Middleware: MongoDB connection error:", err);
|
|
73
175
|
return false;
|
|
74
176
|
});
|
|
75
|
-
|
|
177
|
+
|
|
178
|
+
router.get(`${adminPath}/health-checks`, basicAuth, (req, res) => {
|
|
179
|
+
const templatePath = path.join(
|
|
180
|
+
__dirname,
|
|
181
|
+
"..",
|
|
182
|
+
"views",
|
|
183
|
+
"admin-health-checks.ejs",
|
|
184
|
+
);
|
|
185
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
186
|
+
if (err) {
|
|
187
|
+
console.error("Error reading template:", err);
|
|
188
|
+
return res.status(500).send("Error loading page");
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
const html = ejs.render(
|
|
192
|
+
template,
|
|
193
|
+
{
|
|
194
|
+
baseUrl: req.baseUrl,
|
|
195
|
+
adminPath,
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
filename: templatePath,
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
res.send(html);
|
|
202
|
+
} catch (renderErr) {
|
|
203
|
+
console.error("Error rendering template:", renderErr);
|
|
204
|
+
res.status(500).send("Error rendering page");
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
router.get(`${adminPath}/console-manager`, basicAuth, (req, res) => {
|
|
210
|
+
const templatePath = path.join(
|
|
211
|
+
__dirname,
|
|
212
|
+
"..",
|
|
213
|
+
"views",
|
|
214
|
+
"admin-console-manager.ejs",
|
|
215
|
+
);
|
|
216
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
217
|
+
if (err) {
|
|
218
|
+
console.error("Error reading template:", err);
|
|
219
|
+
return res.status(500).send("Error loading page");
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const html = ejs.render(
|
|
223
|
+
template,
|
|
224
|
+
{
|
|
225
|
+
baseUrl: req.baseUrl,
|
|
226
|
+
adminPath,
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
filename: templatePath,
|
|
230
|
+
},
|
|
231
|
+
);
|
|
232
|
+
res.send(html);
|
|
233
|
+
} catch (renderErr) {
|
|
234
|
+
console.error("Error rendering template:", renderErr);
|
|
235
|
+
res.status(500).send("Error rendering page");
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
76
240
|
// Store the promise so it can be awaited if needed
|
|
77
241
|
router.connectionPromise = connectionPromise;
|
|
78
242
|
} else if (mongoose.connection.readyState === 1) {
|
|
79
243
|
console.log("✅ Middleware: Using existing MongoDB connection");
|
|
244
|
+
// Start cron scheduler for existing connection
|
|
245
|
+
cronScheduler.start().catch((err) => {
|
|
246
|
+
console.error("Failed to start cron scheduler:", err);
|
|
247
|
+
});
|
|
248
|
+
healthChecksScheduler.start().catch((err) => {
|
|
249
|
+
console.error("Failed to start health checks scheduler:", err);
|
|
250
|
+
});
|
|
251
|
+
healthChecksBootstrap.bootstrap().catch((err) => {
|
|
252
|
+
console.error("Failed to bootstrap health checks:", err);
|
|
253
|
+
});
|
|
254
|
+
blogCronsBootstrap.bootstrap().catch((err) => {
|
|
255
|
+
console.error("Failed to bootstrap blog crons:", err);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Initialize console manager AFTER database is already connected
|
|
259
|
+
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
260
|
+
isConsoleManagerEnabled().then(consoleManagerEnabled => {
|
|
261
|
+
if (consoleManagerEnabled) {
|
|
262
|
+
consoleManager.init();
|
|
263
|
+
console.log("[Console Manager] Initialized");
|
|
264
|
+
} else {
|
|
265
|
+
console.log("[Console Manager] Disabled - console methods not overridden");
|
|
266
|
+
}
|
|
267
|
+
}).catch(error => {
|
|
268
|
+
console.error("[Console Manager] Error checking enabled status:", error);
|
|
269
|
+
console.log("[Console Manager] Fallback to enabled due to error");
|
|
270
|
+
consoleManager.init();
|
|
271
|
+
console.log("[Console Manager] Initialized (fallback)");
|
|
272
|
+
});
|
|
273
|
+
}
|
|
80
274
|
}
|
|
81
275
|
|
|
82
276
|
// CORS configuration
|
|
@@ -138,6 +332,12 @@ function createMiddleware(options = {}) {
|
|
|
138
332
|
webhookHandler,
|
|
139
333
|
);
|
|
140
334
|
|
|
335
|
+
router.use(
|
|
336
|
+
"/proxy",
|
|
337
|
+
express.raw({ type: "*/*", limit: "10mb" }),
|
|
338
|
+
require("./routes/proxy.routes"),
|
|
339
|
+
);
|
|
340
|
+
|
|
141
341
|
// Regular JSON parsing for other routes (skip if parent app already handles it)
|
|
142
342
|
if (!options.skipBodyParser) {
|
|
143
343
|
router.use(express.json());
|
|
@@ -146,6 +346,8 @@ function createMiddleware(options = {}) {
|
|
|
146
346
|
|
|
147
347
|
router.use(requestIdMiddleware);
|
|
148
348
|
|
|
349
|
+
router.use("/api", rateLimiter.limit("globalApiLimiter"));
|
|
350
|
+
|
|
149
351
|
// Serve public static files (e.g. /og/og-default.png)
|
|
150
352
|
router.use(express.static(path.join(__dirname, "..", "public")));
|
|
151
353
|
|
|
@@ -164,6 +366,53 @@ function createMiddleware(options = {}) {
|
|
|
164
366
|
// EJS locals: feature flags for server-rendered pages
|
|
165
367
|
router.use(createFeatureFlagsEjsMiddleware());
|
|
166
368
|
|
|
369
|
+
// Public File Manager SPA (gated by global settings; restart required)
|
|
370
|
+
router.get("*", (req, res, next) => {
|
|
371
|
+
try {
|
|
372
|
+
if (!fileManagerPublicConfig.enabled) return next();
|
|
373
|
+
|
|
374
|
+
const basePath = fileManagerPublicConfig.basePath || "/files";
|
|
375
|
+
const reqPath = req.path;
|
|
376
|
+
const matches =
|
|
377
|
+
reqPath === basePath ||
|
|
378
|
+
reqPath === `${basePath}/` ||
|
|
379
|
+
reqPath.startsWith(`${basePath}/`);
|
|
380
|
+
|
|
381
|
+
if (!matches) return next();
|
|
382
|
+
if (req.method !== "GET") return next();
|
|
383
|
+
|
|
384
|
+
const templatePath = path.join(
|
|
385
|
+
__dirname,
|
|
386
|
+
"..",
|
|
387
|
+
"views",
|
|
388
|
+
"file-manager.ejs",
|
|
389
|
+
);
|
|
390
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
391
|
+
if (err) {
|
|
392
|
+
console.error("Error reading template:", err);
|
|
393
|
+
return res.status(500).send("Error loading page");
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
const html = ejs.render(
|
|
397
|
+
template,
|
|
398
|
+
{
|
|
399
|
+
baseUrl: req.baseUrl,
|
|
400
|
+
fileManagerBasePath: basePath,
|
|
401
|
+
},
|
|
402
|
+
{ filename: templatePath },
|
|
403
|
+
);
|
|
404
|
+
res.send(html);
|
|
405
|
+
} catch (renderErr) {
|
|
406
|
+
console.error("Error rendering template:", renderErr);
|
|
407
|
+
res.status(500).send("Error rendering page");
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
} catch (error) {
|
|
411
|
+
console.error("Error serving File Manager SPA:", error);
|
|
412
|
+
next();
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
167
416
|
// API Routes
|
|
168
417
|
router.use("/api/auth", require("./routes/auth.routes"));
|
|
169
418
|
router.use("/api/billing", require("./routes/billing.routes"));
|
|
@@ -177,22 +426,65 @@ function createMiddleware(options = {}) {
|
|
|
177
426
|
);
|
|
178
427
|
router.use("/api/admin/orgs", require("./routes/orgAdmin.routes"));
|
|
179
428
|
router.use("/api/admin/users", require("./routes/userAdmin.routes"));
|
|
180
|
-
router.use("/api/admin/
|
|
429
|
+
router.use("/api/admin/rbac", require("./routes/adminRbac.routes"));
|
|
430
|
+
router.use(
|
|
431
|
+
"/api/admin/notifications",
|
|
432
|
+
require("./routes/notificationAdmin.routes"),
|
|
433
|
+
);
|
|
181
434
|
router.use("/api/admin/stripe", require("./routes/stripeAdmin.routes"));
|
|
182
|
-
|
|
435
|
+
|
|
183
436
|
// Stats Routes
|
|
184
437
|
const adminStatsController = require("./controllers/adminStats.controller");
|
|
185
|
-
router.get(
|
|
186
|
-
|
|
438
|
+
router.get(
|
|
439
|
+
"/api/admin/stats/overview",
|
|
440
|
+
basicAuth,
|
|
441
|
+
adminStatsController.getOverviewStats,
|
|
442
|
+
);
|
|
443
|
+
|
|
187
444
|
router.get(`${adminPath}/stats/dashboard-home`, basicAuth, (req, res) => {
|
|
188
|
-
const templatePath = path.join(
|
|
445
|
+
const templatePath = path.join(
|
|
446
|
+
__dirname,
|
|
447
|
+
"..",
|
|
448
|
+
"views",
|
|
449
|
+
"admin-dashboard-home.ejs",
|
|
450
|
+
);
|
|
189
451
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
190
452
|
if (err) {
|
|
191
453
|
console.error("Error reading template:", err);
|
|
192
454
|
return res.status(500).send("Error loading page");
|
|
193
455
|
}
|
|
194
456
|
try {
|
|
195
|
-
const html = ejs.render(
|
|
457
|
+
const html = ejs.render(
|
|
458
|
+
template,
|
|
459
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
460
|
+
{ filename: templatePath },
|
|
461
|
+
);
|
|
462
|
+
res.send(html);
|
|
463
|
+
} catch (renderErr) {
|
|
464
|
+
console.error("Error rendering template:", renderErr);
|
|
465
|
+
res.status(500).send("Error rendering page");
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
router.get(`${adminPath}/rbac`, basicAuth, (req, res) => {
|
|
471
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-rbac.ejs");
|
|
472
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
473
|
+
if (err) {
|
|
474
|
+
console.error("Error reading template:", err);
|
|
475
|
+
return res.status(500).send("Error loading page");
|
|
476
|
+
}
|
|
477
|
+
try {
|
|
478
|
+
const html = ejs.render(
|
|
479
|
+
template,
|
|
480
|
+
{
|
|
481
|
+
baseUrl: req.baseUrl,
|
|
482
|
+
adminPath,
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
filename: templatePath,
|
|
486
|
+
},
|
|
487
|
+
);
|
|
196
488
|
res.send(html);
|
|
197
489
|
} catch (renderErr) {
|
|
198
490
|
console.error("Error rendering template:", renderErr);
|
|
@@ -265,6 +557,89 @@ function createMiddleware(options = {}) {
|
|
|
265
557
|
});
|
|
266
558
|
});
|
|
267
559
|
|
|
560
|
+
router.get(`${adminPath}/crons`, basicAuth, (req, res) => {
|
|
561
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-crons.ejs");
|
|
562
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
563
|
+
if (err) {
|
|
564
|
+
console.error("Error reading template:", err);
|
|
565
|
+
return res.status(500).send("Error loading page");
|
|
566
|
+
}
|
|
567
|
+
try {
|
|
568
|
+
const html = ejs.render(
|
|
569
|
+
template,
|
|
570
|
+
{
|
|
571
|
+
baseUrl: req.baseUrl,
|
|
572
|
+
adminPath,
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
filename: templatePath,
|
|
576
|
+
},
|
|
577
|
+
);
|
|
578
|
+
res.send(html);
|
|
579
|
+
} catch (renderErr) {
|
|
580
|
+
console.error("Error rendering template:", renderErr);
|
|
581
|
+
res.status(500).send("Error rendering page");
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
router.get(`${adminPath}/cache`, basicAuth, (req, res) => {
|
|
587
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-cache.ejs");
|
|
588
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
589
|
+
if (err) {
|
|
590
|
+
console.error("Error reading template:", err);
|
|
591
|
+
return res.status(500).send("Error loading page");
|
|
592
|
+
}
|
|
593
|
+
try {
|
|
594
|
+
const html = ejs.render(
|
|
595
|
+
template,
|
|
596
|
+
{
|
|
597
|
+
baseUrl: req.baseUrl,
|
|
598
|
+
adminPath,
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
filename: templatePath,
|
|
602
|
+
},
|
|
603
|
+
);
|
|
604
|
+
res.send(html);
|
|
605
|
+
} catch (renderErr) {
|
|
606
|
+
console.error("Error rendering template:", renderErr);
|
|
607
|
+
res.status(500).send("Error rendering page");
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
router.get(`${adminPath}/db-browser`, basicAuth, (req, res) => {
|
|
613
|
+
const templatePath = path.join(
|
|
614
|
+
__dirname,
|
|
615
|
+
"..",
|
|
616
|
+
"views",
|
|
617
|
+
"admin-db-browser.ejs",
|
|
618
|
+
);
|
|
619
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
620
|
+
if (err) {
|
|
621
|
+
console.error("Error reading template:", err);
|
|
622
|
+
return res.status(500).send("Error loading page");
|
|
623
|
+
}
|
|
624
|
+
try {
|
|
625
|
+
const html = ejs.render(
|
|
626
|
+
template,
|
|
627
|
+
{
|
|
628
|
+
baseUrl: req.baseUrl,
|
|
629
|
+
adminPath,
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
filename: templatePath,
|
|
633
|
+
},
|
|
634
|
+
);
|
|
635
|
+
res.send(html);
|
|
636
|
+
} catch (renderErr) {
|
|
637
|
+
console.error("Error rendering template:", renderErr);
|
|
638
|
+
res.status(500).send("Error rendering page");
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
|
|
268
643
|
router.use("/api/admin", require("./routes/admin.routes"));
|
|
269
644
|
router.use("/api/admin/settings", require("./routes/globalSettings.routes"));
|
|
270
645
|
router.use(
|
|
@@ -275,6 +650,11 @@ function createMiddleware(options = {}) {
|
|
|
275
650
|
"/api/admin/json-configs",
|
|
276
651
|
require("./routes/adminJsonConfigs.routes"),
|
|
277
652
|
);
|
|
653
|
+
router.use(
|
|
654
|
+
"/api/admin/rate-limits",
|
|
655
|
+
require("./routes/adminRateLimits.routes"),
|
|
656
|
+
);
|
|
657
|
+
router.use("/api/admin/proxy", require("./routes/adminProxy.routes"));
|
|
278
658
|
router.use(
|
|
279
659
|
"/api/admin/seo-config",
|
|
280
660
|
require("./routes/adminSeoConfig.routes"),
|
|
@@ -282,19 +662,51 @@ function createMiddleware(options = {}) {
|
|
|
282
662
|
router.use("/api/admin/i18n", require("./routes/adminI18n.routes"));
|
|
283
663
|
router.use("/api/admin/headless", require("./routes/adminHeadless.routes"));
|
|
284
664
|
router.use("/api/admin/scripts", require("./routes/adminScripts.routes"));
|
|
665
|
+
router.use("/api/admin/crons", require("./routes/adminCrons.routes"));
|
|
666
|
+
router.use(
|
|
667
|
+
"/api/admin/health-checks",
|
|
668
|
+
require("./routes/adminHealthChecks.routes"),
|
|
669
|
+
);
|
|
670
|
+
router.use("/api/admin/cache", require("./routes/adminCache.routes"));
|
|
671
|
+
router.use(
|
|
672
|
+
"/api/admin/console-manager",
|
|
673
|
+
require("./routes/adminConsoleManager.routes"),
|
|
674
|
+
);
|
|
675
|
+
router.use(
|
|
676
|
+
"/api/admin/db-browser",
|
|
677
|
+
require("./routes/adminDbBrowser.routes"),
|
|
678
|
+
);
|
|
285
679
|
router.use("/api/admin/terminals", require("./routes/adminTerminals.routes"));
|
|
286
680
|
router.use("/api/admin/assets", require("./routes/adminAssets.routes"));
|
|
287
681
|
router.use(
|
|
288
682
|
"/api/admin/upload-namespaces",
|
|
289
683
|
require("./routes/adminUploadNamespaces.routes"),
|
|
290
684
|
);
|
|
291
|
-
router.use(
|
|
685
|
+
router.use(
|
|
686
|
+
"/api/admin/ui-components",
|
|
687
|
+
require("./routes/adminUiComponents.routes"),
|
|
688
|
+
);
|
|
292
689
|
router.use("/api/admin/migration", require("./routes/adminMigration.routes"));
|
|
293
|
-
router.use(
|
|
294
|
-
|
|
690
|
+
router.use(
|
|
691
|
+
"/api/admin/errors",
|
|
692
|
+
basicAuth,
|
|
693
|
+
require("./routes/adminErrors.routes"),
|
|
694
|
+
);
|
|
695
|
+
router.use(
|
|
696
|
+
"/api/admin/audit",
|
|
697
|
+
basicAuth,
|
|
698
|
+
require("./routes/adminAudit.routes"),
|
|
699
|
+
);
|
|
295
700
|
router.use("/api/admin/llm", require("./routes/adminLlm.routes"));
|
|
296
|
-
router.use(
|
|
297
|
-
|
|
701
|
+
router.use(
|
|
702
|
+
"/api/admin/ejs-virtual",
|
|
703
|
+
require("./routes/adminEjsVirtual.routes"),
|
|
704
|
+
);
|
|
705
|
+
router.use("/api/admin/pages", require("./routes/adminPages.routes"));
|
|
706
|
+
router.use("/api/admin", require("./routes/adminBlog.routes"));
|
|
707
|
+
router.use("/api/admin", require("./routes/adminBlogAi.routes"));
|
|
708
|
+
router.use("/api/admin", require("./routes/adminBlogAutomation.routes"));
|
|
709
|
+
router.use("/api/admin/workflows", basicAuth, require("./routes/workflows.routes"));
|
|
298
710
|
router.use("/w", require("./routes/workflowWebhook.routes"));
|
|
299
711
|
router.use("/api/webhooks", require("./routes/webhook.routes"));
|
|
300
712
|
router.use("/api/settings", require("./routes/globalSettings.routes"));
|
|
@@ -310,21 +722,43 @@ function createMiddleware(options = {}) {
|
|
|
310
722
|
router.use("/api/log", require("./routes/log.routes"));
|
|
311
723
|
router.use("/api/error-tracking", require("./routes/errorTracking.routes"));
|
|
312
724
|
router.use("/api/ui-components", require("./routes/uiComponentsPublic.routes"));
|
|
313
|
-
router.use("/api/
|
|
725
|
+
router.use("/api/rbac", require("./routes/rbac.routes"));
|
|
726
|
+
router.use("/api/file-manager", require("./routes/fileManager.routes"));
|
|
727
|
+
|
|
728
|
+
// Public blog APIs (headless)
|
|
729
|
+
router.use("/api", require("./routes/blogPublic.routes"));
|
|
730
|
+
|
|
731
|
+
// Internal blog endpoints (used by HTTP CronJobs)
|
|
732
|
+
router.use("/api/internal", require("./routes/blogInternal.routes"));
|
|
733
|
+
|
|
734
|
+
// Public health checks status (gated by global setting)
|
|
735
|
+
router.use(
|
|
736
|
+
"/api/health-checks",
|
|
737
|
+
require("./routes/healthChecksPublic.routes"),
|
|
738
|
+
);
|
|
314
739
|
|
|
315
740
|
// Public assets proxy
|
|
316
741
|
router.use("/public/assets", require("./routes/publicAssets.routes"));
|
|
317
742
|
|
|
318
743
|
// Admin dashboard (polished view)
|
|
319
744
|
router.get(adminPath, basicAuth, (req, res) => {
|
|
320
|
-
const templatePath = path.join(
|
|
745
|
+
const templatePath = path.join(
|
|
746
|
+
__dirname,
|
|
747
|
+
"..",
|
|
748
|
+
"views",
|
|
749
|
+
"admin-dashboard.ejs",
|
|
750
|
+
);
|
|
321
751
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
322
752
|
if (err) {
|
|
323
753
|
console.error("Error reading template:", err);
|
|
324
754
|
return res.status(500).send("Error loading page");
|
|
325
755
|
}
|
|
326
756
|
try {
|
|
327
|
-
const html = ejs.render(
|
|
757
|
+
const html = ejs.render(
|
|
758
|
+
template,
|
|
759
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
760
|
+
{ filename: templatePath },
|
|
761
|
+
);
|
|
328
762
|
res.send(html);
|
|
329
763
|
} catch (renderErr) {
|
|
330
764
|
console.error("Error rendering template:", renderErr);
|
|
@@ -362,7 +796,12 @@ function createMiddleware(options = {}) {
|
|
|
362
796
|
});
|
|
363
797
|
|
|
364
798
|
router.get(`${adminPath}/migration`, basicAuth, (req, res) => {
|
|
365
|
-
const templatePath = path.join(
|
|
799
|
+
const templatePath = path.join(
|
|
800
|
+
__dirname,
|
|
801
|
+
"..",
|
|
802
|
+
"views",
|
|
803
|
+
"admin-migration.ejs",
|
|
804
|
+
);
|
|
366
805
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
367
806
|
if (err) {
|
|
368
807
|
console.error("Error reading template:", err);
|
|
@@ -390,12 +829,59 @@ function createMiddleware(options = {}) {
|
|
|
390
829
|
|
|
391
830
|
// Admin LLM/AI page (protected by basic auth)
|
|
392
831
|
router.get(`${adminPath}/admin-llm`, basicAuth, (req, res) => {
|
|
832
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-llm.ejs");
|
|
833
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
834
|
+
if (err) {
|
|
835
|
+
console.error("Error reading template:", err);
|
|
836
|
+
return res.status(500).send("Error loading page");
|
|
837
|
+
}
|
|
838
|
+
try {
|
|
839
|
+
const html = ejs.render(
|
|
840
|
+
template,
|
|
841
|
+
{
|
|
842
|
+
baseUrl: req.baseUrl,
|
|
843
|
+
adminPath,
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
filename: templatePath,
|
|
847
|
+
},
|
|
848
|
+
);
|
|
849
|
+
res.send(html);
|
|
850
|
+
} catch (renderErr) {
|
|
851
|
+
console.error("Error rendering template:", renderErr);
|
|
852
|
+
res.status(500).send("Error rendering page");
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
router.get(`${adminPath}/workflows/:id`, basicAuth, (req, res) => {
|
|
393
858
|
const templatePath = path.join(
|
|
394
859
|
__dirname,
|
|
395
860
|
"..",
|
|
396
861
|
"views",
|
|
397
|
-
"admin-
|
|
862
|
+
"admin-workflows.ejs",
|
|
398
863
|
);
|
|
864
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
865
|
+
if (err) {
|
|
866
|
+
console.error("Error reading template:", err);
|
|
867
|
+
return res.status(500).send("Error loading page");
|
|
868
|
+
}
|
|
869
|
+
try {
|
|
870
|
+
const html = ejs.render(
|
|
871
|
+
template,
|
|
872
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
873
|
+
{ filename: templatePath },
|
|
874
|
+
);
|
|
875
|
+
res.send(html);
|
|
876
|
+
} catch (renderErr) {
|
|
877
|
+
console.error("Error rendering template:", renderErr);
|
|
878
|
+
res.status(500).send("Error rendering page");
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
router.get(`${adminPath}/pages`, basicAuth, (req, res) => {
|
|
884
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-pages.ejs");
|
|
399
885
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
400
886
|
if (err) {
|
|
401
887
|
console.error("Error reading template:", err);
|
|
@@ -420,15 +906,133 @@ function createMiddleware(options = {}) {
|
|
|
420
906
|
});
|
|
421
907
|
});
|
|
422
908
|
|
|
423
|
-
router.get(`${adminPath}/
|
|
424
|
-
const templatePath = path.join(__dirname, "..", "views", "admin-
|
|
909
|
+
router.get(`${adminPath}/blog`, basicAuth, (req, res) => {
|
|
910
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-blog.ejs");
|
|
911
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
912
|
+
if (err) {
|
|
913
|
+
console.error("Error reading template:", err);
|
|
914
|
+
return res.status(500).send("Error loading page");
|
|
915
|
+
}
|
|
916
|
+
try {
|
|
917
|
+
const html = ejs.render(
|
|
918
|
+
template,
|
|
919
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
920
|
+
{ filename: templatePath },
|
|
921
|
+
);
|
|
922
|
+
res.send(html);
|
|
923
|
+
} catch (renderErr) {
|
|
924
|
+
console.error("Error rendering template:", renderErr);
|
|
925
|
+
res.status(500).send("Error rendering page");
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
router.get(`${adminPath}/blog-automation`, basicAuth, (req, res) => {
|
|
931
|
+
const templatePath = path.join(
|
|
932
|
+
__dirname,
|
|
933
|
+
"..",
|
|
934
|
+
"views",
|
|
935
|
+
"admin-blog-automation.ejs",
|
|
936
|
+
);
|
|
937
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
938
|
+
if (err) {
|
|
939
|
+
console.error("Error reading template:", err);
|
|
940
|
+
return res.status(500).send("Error loading page");
|
|
941
|
+
}
|
|
942
|
+
try {
|
|
943
|
+
const html = ejs.render(
|
|
944
|
+
template,
|
|
945
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
946
|
+
{ filename: templatePath },
|
|
947
|
+
);
|
|
948
|
+
res.send(html);
|
|
949
|
+
} catch (renderErr) {
|
|
950
|
+
console.error("Error rendering template:", renderErr);
|
|
951
|
+
res.status(500).send("Error rendering page");
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
router.get(`${adminPath}/blog/new`, basicAuth, (req, res) => {
|
|
957
|
+
const templatePath = path.join(
|
|
958
|
+
__dirname,
|
|
959
|
+
"..",
|
|
960
|
+
"views",
|
|
961
|
+
"admin-blog-edit.ejs",
|
|
962
|
+
);
|
|
963
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
964
|
+
if (err) {
|
|
965
|
+
console.error("Error reading template:", err);
|
|
966
|
+
return res.status(500).send("Error loading page");
|
|
967
|
+
}
|
|
968
|
+
try {
|
|
969
|
+
const html = ejs.render(
|
|
970
|
+
template,
|
|
971
|
+
{ baseUrl: req.baseUrl, adminPath, postId: "", mode: "new" },
|
|
972
|
+
{ filename: templatePath },
|
|
973
|
+
);
|
|
974
|
+
res.send(html);
|
|
975
|
+
} catch (renderErr) {
|
|
976
|
+
console.error("Error rendering template:", renderErr);
|
|
977
|
+
res.status(500).send("Error rendering page");
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
router.get(`${adminPath}/blog/edit/:id`, basicAuth, (req, res) => {
|
|
983
|
+
const templatePath = path.join(
|
|
984
|
+
__dirname,
|
|
985
|
+
"..",
|
|
986
|
+
"views",
|
|
987
|
+
"admin-blog-edit.ejs",
|
|
988
|
+
);
|
|
989
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
990
|
+
if (err) {
|
|
991
|
+
console.error("Error reading template:", err);
|
|
992
|
+
return res.status(500).send("Error loading page");
|
|
993
|
+
}
|
|
994
|
+
try {
|
|
995
|
+
const html = ejs.render(
|
|
996
|
+
template,
|
|
997
|
+
{
|
|
998
|
+
baseUrl: req.baseUrl,
|
|
999
|
+
adminPath,
|
|
1000
|
+
postId: String(req.params.id || ""),
|
|
1001
|
+
mode: "edit",
|
|
1002
|
+
},
|
|
1003
|
+
{ filename: templatePath },
|
|
1004
|
+
);
|
|
1005
|
+
res.send(html);
|
|
1006
|
+
} catch (renderErr) {
|
|
1007
|
+
console.error("Error rendering template:", renderErr);
|
|
1008
|
+
res.status(500).send("Error rendering page");
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
router.get(`${adminPath}/file-manager`, basicAuth, (req, res) => {
|
|
1014
|
+
const templatePath = path.join(
|
|
1015
|
+
__dirname,
|
|
1016
|
+
"..",
|
|
1017
|
+
"views",
|
|
1018
|
+
"admin-file-manager.ejs",
|
|
1019
|
+
);
|
|
425
1020
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
426
1021
|
if (err) {
|
|
427
1022
|
console.error("Error reading template:", err);
|
|
428
1023
|
return res.status(500).send("Error loading page");
|
|
429
1024
|
}
|
|
430
1025
|
try {
|
|
431
|
-
const html = ejs.render(
|
|
1026
|
+
const html = ejs.render(
|
|
1027
|
+
template,
|
|
1028
|
+
{
|
|
1029
|
+
baseUrl: req.baseUrl,
|
|
1030
|
+
adminPath,
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
filename: templatePath,
|
|
1034
|
+
},
|
|
1035
|
+
);
|
|
432
1036
|
res.send(html);
|
|
433
1037
|
} catch (renderErr) {
|
|
434
1038
|
console.error("Error rendering template:", renderErr);
|
|
@@ -438,7 +1042,12 @@ function createMiddleware(options = {}) {
|
|
|
438
1042
|
});
|
|
439
1043
|
|
|
440
1044
|
router.get(`${adminPath}/ejs-virtual`, basicAuth, (req, res) => {
|
|
441
|
-
const templatePath = path.join(
|
|
1045
|
+
const templatePath = path.join(
|
|
1046
|
+
__dirname,
|
|
1047
|
+
"..",
|
|
1048
|
+
"views",
|
|
1049
|
+
"admin-ejs-virtual.ejs",
|
|
1050
|
+
);
|
|
442
1051
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
443
1052
|
if (err) {
|
|
444
1053
|
console.error("Error reading template:", err);
|
|
@@ -464,7 +1073,12 @@ function createMiddleware(options = {}) {
|
|
|
464
1073
|
});
|
|
465
1074
|
|
|
466
1075
|
router.get(`${adminPath}/seo-config`, basicAuth, (req, res) => {
|
|
467
|
-
const templatePath = path.join(
|
|
1076
|
+
const templatePath = path.join(
|
|
1077
|
+
__dirname,
|
|
1078
|
+
"..",
|
|
1079
|
+
"views",
|
|
1080
|
+
"admin-seo-config.ejs",
|
|
1081
|
+
);
|
|
468
1082
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
469
1083
|
if (err) {
|
|
470
1084
|
console.error("Error reading template:", err);
|
|
@@ -498,7 +1112,11 @@ function createMiddleware(options = {}) {
|
|
|
498
1112
|
return res.status(500).send("Error loading page");
|
|
499
1113
|
}
|
|
500
1114
|
try {
|
|
501
|
-
const html = ejs.render(
|
|
1115
|
+
const html = ejs.render(
|
|
1116
|
+
template,
|
|
1117
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1118
|
+
{ filename: templatePath },
|
|
1119
|
+
);
|
|
502
1120
|
res.send(html);
|
|
503
1121
|
} catch (renderErr) {
|
|
504
1122
|
console.error("Error rendering template:", renderErr);
|
|
@@ -520,7 +1138,11 @@ function createMiddleware(options = {}) {
|
|
|
520
1138
|
return res.status(500).send("Error loading page");
|
|
521
1139
|
}
|
|
522
1140
|
try {
|
|
523
|
-
const html = ejs.render(
|
|
1141
|
+
const html = ejs.render(
|
|
1142
|
+
template,
|
|
1143
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1144
|
+
{ filename: templatePath },
|
|
1145
|
+
);
|
|
524
1146
|
res.send(html);
|
|
525
1147
|
} catch (renderErr) {
|
|
526
1148
|
console.error("Error rendering template:", renderErr);
|
|
@@ -784,12 +1406,7 @@ function createMiddleware(options = {}) {
|
|
|
784
1406
|
|
|
785
1407
|
// Admin users page (protected by basic auth)
|
|
786
1408
|
router.get(`${adminPath}/users`, basicAuth, (req, res) => {
|
|
787
|
-
const templatePath = path.join(
|
|
788
|
-
__dirname,
|
|
789
|
-
"..",
|
|
790
|
-
"views",
|
|
791
|
-
"admin-users.ejs",
|
|
792
|
-
);
|
|
1409
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-users.ejs");
|
|
793
1410
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
794
1411
|
if (err) {
|
|
795
1412
|
console.error("Error reading template:", err);
|
|
@@ -908,6 +1525,31 @@ function createMiddleware(options = {}) {
|
|
|
908
1525
|
});
|
|
909
1526
|
});
|
|
910
1527
|
|
|
1528
|
+
router.get(`${adminPath}/rate-limiter`, basicAuth, (req, res) => {
|
|
1529
|
+
const templatePath = path.join(
|
|
1530
|
+
__dirname,
|
|
1531
|
+
"..",
|
|
1532
|
+
"views",
|
|
1533
|
+
"admin-rate-limiter.ejs",
|
|
1534
|
+
);
|
|
1535
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1536
|
+
if (err) {
|
|
1537
|
+
console.error("Error reading template:", err);
|
|
1538
|
+
return res.status(500).send("Error loading page");
|
|
1539
|
+
}
|
|
1540
|
+
try {
|
|
1541
|
+
const html = ejs.render(template, {
|
|
1542
|
+
baseUrl: req.baseUrl,
|
|
1543
|
+
adminPath,
|
|
1544
|
+
});
|
|
1545
|
+
res.send(html);
|
|
1546
|
+
} catch (renderErr) {
|
|
1547
|
+
console.error("Error rendering template:", renderErr);
|
|
1548
|
+
res.status(500).send("Error rendering page");
|
|
1549
|
+
}
|
|
1550
|
+
});
|
|
1551
|
+
});
|
|
1552
|
+
|
|
911
1553
|
// Admin global settings page (protected by basic auth) - render manually
|
|
912
1554
|
router.get(`${adminPath}/global-settings`, basicAuth, (req, res) => {
|
|
913
1555
|
const templatePath = path.join(
|
|
@@ -932,14 +1574,23 @@ function createMiddleware(options = {}) {
|
|
|
932
1574
|
});
|
|
933
1575
|
|
|
934
1576
|
router.get(`${adminPath}/errors`, basicAuth, (req, res) => {
|
|
935
|
-
const templatePath = path.join(
|
|
1577
|
+
const templatePath = path.join(
|
|
1578
|
+
__dirname,
|
|
1579
|
+
"..",
|
|
1580
|
+
"views",
|
|
1581
|
+
"admin-errors.ejs",
|
|
1582
|
+
);
|
|
936
1583
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
937
1584
|
if (err) {
|
|
938
1585
|
console.error("Error reading template:", err);
|
|
939
1586
|
return res.status(500).send("Error loading page");
|
|
940
1587
|
}
|
|
941
1588
|
try {
|
|
942
|
-
const html = ejs.render(
|
|
1589
|
+
const html = ejs.render(
|
|
1590
|
+
template,
|
|
1591
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1592
|
+
{ filename: templatePath },
|
|
1593
|
+
);
|
|
943
1594
|
res.send(html);
|
|
944
1595
|
} catch (renderErr) {
|
|
945
1596
|
console.error("Error rendering template:", renderErr);
|
|
@@ -956,7 +1607,11 @@ function createMiddleware(options = {}) {
|
|
|
956
1607
|
return res.status(500).send("Error loading page");
|
|
957
1608
|
}
|
|
958
1609
|
try {
|
|
959
|
-
const html = ejs.render(
|
|
1610
|
+
const html = ejs.render(
|
|
1611
|
+
template,
|
|
1612
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1613
|
+
{ filename: templatePath },
|
|
1614
|
+
);
|
|
960
1615
|
res.send(html);
|
|
961
1616
|
} catch (renderErr) {
|
|
962
1617
|
console.error("Error rendering template:", renderErr);
|
|
@@ -966,14 +1621,44 @@ function createMiddleware(options = {}) {
|
|
|
966
1621
|
});
|
|
967
1622
|
|
|
968
1623
|
router.get(`${adminPath}/coolify-deploy`, basicAuth, (req, res) => {
|
|
969
|
-
const templatePath = path.join(
|
|
1624
|
+
const templatePath = path.join(
|
|
1625
|
+
__dirname,
|
|
1626
|
+
"..",
|
|
1627
|
+
"views",
|
|
1628
|
+
"admin-coolify-deploy.ejs",
|
|
1629
|
+
);
|
|
1630
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1631
|
+
if (err) {
|
|
1632
|
+
console.error("Error reading template:", err);
|
|
1633
|
+
return res.status(500).send("Error loading page");
|
|
1634
|
+
}
|
|
1635
|
+
try {
|
|
1636
|
+
const html = ejs.render(
|
|
1637
|
+
template,
|
|
1638
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1639
|
+
{ filename: templatePath },
|
|
1640
|
+
);
|
|
1641
|
+
res.send(html);
|
|
1642
|
+
} catch (renderErr) {
|
|
1643
|
+
console.error("Error rendering template:", renderErr);
|
|
1644
|
+
res.status(500).send("Error rendering page");
|
|
1645
|
+
}
|
|
1646
|
+
});
|
|
1647
|
+
});
|
|
1648
|
+
|
|
1649
|
+
router.get(`${adminPath}/proxy`, basicAuth, (req, res) => {
|
|
1650
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-proxy.ejs");
|
|
970
1651
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
971
1652
|
if (err) {
|
|
972
1653
|
console.error("Error reading template:", err);
|
|
973
1654
|
return res.status(500).send("Error loading page");
|
|
974
1655
|
}
|
|
975
1656
|
try {
|
|
976
|
-
const html = ejs.render(
|
|
1657
|
+
const html = ejs.render(
|
|
1658
|
+
template,
|
|
1659
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1660
|
+
{ filename: templatePath },
|
|
1661
|
+
);
|
|
977
1662
|
res.send(html);
|
|
978
1663
|
} catch (renderErr) {
|
|
979
1664
|
console.error("Error rendering template:", renderErr);
|
|
@@ -983,14 +1668,23 @@ function createMiddleware(options = {}) {
|
|
|
983
1668
|
});
|
|
984
1669
|
|
|
985
1670
|
router.get(`${adminPath}/webhooks`, basicAuth, (req, res) => {
|
|
986
|
-
const templatePath = path.join(
|
|
1671
|
+
const templatePath = path.join(
|
|
1672
|
+
__dirname,
|
|
1673
|
+
"..",
|
|
1674
|
+
"views",
|
|
1675
|
+
"admin-webhooks.ejs",
|
|
1676
|
+
);
|
|
987
1677
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
988
1678
|
if (err) {
|
|
989
1679
|
console.error("Error reading template:", err);
|
|
990
1680
|
return res.status(500).send("Error loading page");
|
|
991
1681
|
}
|
|
992
1682
|
try {
|
|
993
|
-
const html = ejs.render(
|
|
1683
|
+
const html = ejs.render(
|
|
1684
|
+
template,
|
|
1685
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1686
|
+
{ filename: templatePath },
|
|
1687
|
+
);
|
|
994
1688
|
res.send(html);
|
|
995
1689
|
} catch (renderErr) {
|
|
996
1690
|
console.error("Error rendering template:", renderErr);
|
|
@@ -999,7 +1693,7 @@ function createMiddleware(options = {}) {
|
|
|
999
1693
|
});
|
|
1000
1694
|
});
|
|
1001
1695
|
|
|
1002
|
-
router.get("/health", (req, res) => {
|
|
1696
|
+
router.get("/health", rateLimiter.limit("healthRateLimiter"), (req, res) => {
|
|
1003
1697
|
res.json({
|
|
1004
1698
|
status: "ok",
|
|
1005
1699
|
mode: "middleware",
|
|
@@ -1011,6 +1705,20 @@ function createMiddleware(options = {}) {
|
|
|
1011
1705
|
router.use("/api/ejs-virtual", require("./routes/adminEjsVirtual.routes"));
|
|
1012
1706
|
router.use("/api/webhooks", require("./routes/webhook.routes"));
|
|
1013
1707
|
|
|
1708
|
+
// Store pagesPrefix and adminPath on app for pages router
|
|
1709
|
+
router.use((req, res, next) => {
|
|
1710
|
+
if (!req.app.get("pagesPrefix")) {
|
|
1711
|
+
req.app.set("pagesPrefix", pagesPrefix);
|
|
1712
|
+
}
|
|
1713
|
+
if (!req.app.get("adminPath")) {
|
|
1714
|
+
req.app.set("adminPath", adminPath);
|
|
1715
|
+
}
|
|
1716
|
+
next();
|
|
1717
|
+
});
|
|
1718
|
+
|
|
1719
|
+
// Public pages router (catch-all, must be last before error handler)
|
|
1720
|
+
router.use(require("./routes/pages.routes"));
|
|
1721
|
+
|
|
1014
1722
|
// Error handling middleware
|
|
1015
1723
|
router.use(expressErrorMiddleware);
|
|
1016
1724
|
|