@intranefr/superbackend 1.5.0 → 1.5.2
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 +15 -0
- package/README.md +11 -0
- package/analysis-only.skill +0 -0
- package/index.js +23 -0
- package/package.json +8 -2
- package/src/admin/endpointRegistry.js +120 -0
- package/src/controllers/admin.controller.js +90 -6
- 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/adminExperiments.controller.js +200 -0
- 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 +126 -4
- 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/experiments.controller.js +85 -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/internalExperiments.controller.js +17 -0
- package/src/controllers/metrics.controller.js +64 -4
- package/src/controllers/orgAdmin.controller.js +80 -0
- package/src/helpers/mongooseHelper.js +258 -0
- package/src/helpers/scriptBase.js +230 -0
- package/src/helpers/scriptRunner.js +335 -0
- package/src/middleware/rbac.js +62 -0
- package/src/middleware.js +810 -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/Experiment.js +75 -0
- package/src/models/ExperimentAssignment.js +23 -0
- package/src/models/ExperimentEvent.js +26 -0
- package/src/models/ExperimentMetricBucket.js +30 -0
- package/src/models/ExternalDbConnection.js +49 -0
- package/src/models/FileEntry.js +22 -0
- package/src/models/GlobalSetting.js +1 -2
- 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/models/ScriptDefinition.js +1 -0
- package/src/models/Webhook.js +2 -0
- package/src/routes/admin.routes.js +2 -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/adminExperiments.routes.js +29 -0
- 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/experiments.routes.js +30 -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/internalExperiments.routes.js +15 -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 +185 -0
- package/src/services/blogPublishing.service.js +58 -0
- package/src/services/cacheLayer.service.js +696 -0
- package/src/services/consoleManager.service.js +738 -0
- package/src/services/consoleOverride.service.js +7 -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/experiments.service.js +273 -0
- package/src/services/experimentsAggregation.service.js +308 -0
- package/src/services/experimentsCronsBootstrap.service.js +118 -0
- package/src/services/experimentsRetention.service.js +43 -0
- package/src/services/experimentsWs.service.js +134 -0
- package/src/services/fileManager.service.js +475 -0
- package/src/services/fileManagerStoragePolicy.service.js +285 -0
- package/src/services/globalSettings.service.js +15 -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/jsonConfigs.service.js +2 -2
- 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 +215 -15
- 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 +33 -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-dashboard.ejs +28 -8
- package/views/admin-db-browser.ejs +445 -0
- package/views/admin-ejs-virtual.ejs +16 -10
- package/views/admin-experiments.ejs +91 -0
- 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 +597 -3
- 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 +12 -0
- package/views/partials/dashboard/palette.ejs +5 -3
- 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,22 @@
|
|
|
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
|
+
// Initialize console manager after a short delay to ensure consoleOverride is fully set up
|
|
10
|
+
setTimeout(() => {
|
|
11
|
+
// Set module prefix for this middleware
|
|
12
|
+
consoleManager.setModulePrefix('middleware');
|
|
13
|
+
|
|
14
|
+
// Initialize console manager early to enable prefixing for all subsequent logs
|
|
15
|
+
consoleManager.init();
|
|
16
|
+
console.log("[Console Manager] Initialized - prefixing enabled");
|
|
17
|
+
}, 20);
|
|
18
|
+
}
|
|
19
|
+
|
|
1
20
|
const express = require("express");
|
|
2
21
|
const path = require("path");
|
|
3
22
|
const mongoose = require("mongoose");
|
|
@@ -6,17 +25,54 @@ const fs = require("fs");
|
|
|
6
25
|
const ejs = require("ejs");
|
|
7
26
|
const { basicAuth } = require("./middleware/auth");
|
|
8
27
|
const endpointRegistry = require("./admin/endpointRegistry");
|
|
9
|
-
const {
|
|
10
|
-
|
|
28
|
+
const {
|
|
29
|
+
createFeatureFlagsEjsMiddleware,
|
|
30
|
+
} = require("./services/featureFlags.service");
|
|
31
|
+
const globalSettingsService = require("./services/globalSettings.service");
|
|
32
|
+
const cronScheduler = require("./services/cronScheduler.service");
|
|
33
|
+
const healthChecksScheduler = require("./services/healthChecksScheduler.service");
|
|
34
|
+
const healthChecksBootstrap = require("./services/healthChecksBootstrap.service");
|
|
35
|
+
const blogCronsBootstrap = require("./services/blogCronsBootstrap.service");
|
|
11
36
|
const {
|
|
12
37
|
hookConsoleError,
|
|
13
38
|
setupProcessHandlers,
|
|
14
39
|
expressErrorMiddleware,
|
|
15
40
|
requestIdMiddleware,
|
|
16
41
|
} = require("./middleware/errorCapture");
|
|
42
|
+
const rateLimiter = require("./services/rateLimiter.service");
|
|
17
43
|
|
|
18
44
|
let errorCaptureInitialized = false;
|
|
19
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Check if console manager should be enabled based on environment variable and global settings
|
|
48
|
+
* Priority: Environment Variable > Global Settings > Default (true)
|
|
49
|
+
* @returns {Promise<boolean>} Whether console manager should be enabled
|
|
50
|
+
*/
|
|
51
|
+
async function isConsoleManagerEnabled() {
|
|
52
|
+
// Environment variable takes highest priority
|
|
53
|
+
const envEnabled = process.env.CONSOLE_MANAGER_ENABLED;
|
|
54
|
+
if (envEnabled !== undefined) {
|
|
55
|
+
const enabled = String(envEnabled).toLowerCase() !== 'false';
|
|
56
|
+
console.log(`[Console Manager] Environment variable CONSOLE_MANAGER_ENABLED=${envEnabled}, ${enabled ? 'enabled' : 'disabled'}`);
|
|
57
|
+
return enabled;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check global settings if environment variable not set
|
|
61
|
+
try {
|
|
62
|
+
const enabledRaw = await globalSettingsService.getSettingValue(
|
|
63
|
+
"CONSOLE_MANAGER_ENABLED",
|
|
64
|
+
"true"
|
|
65
|
+
);
|
|
66
|
+
const enabled = String(enabledRaw) === "true";
|
|
67
|
+
console.log(`[Console Manager] Global setting CONSOLE_MANAGER_ENABLED=${enabledRaw}, ${enabled ? 'enabled' : 'disabled'}`);
|
|
68
|
+
return enabled;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error("[Console Manager] Error loading global setting:", error);
|
|
71
|
+
console.log("[Console Manager] Fallback to enabled due to error");
|
|
72
|
+
return true; // Fallback to enabled on error
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
20
76
|
/**
|
|
21
77
|
* Creates and configures the SaaS backend middleware
|
|
22
78
|
* @param {Object} options - Configuration options
|
|
@@ -30,16 +86,55 @@ let errorCaptureInitialized = false;
|
|
|
30
86
|
function createMiddleware(options = {}) {
|
|
31
87
|
const router = express.Router();
|
|
32
88
|
const adminPath = options.adminPath || "/admin";
|
|
89
|
+
const pagesPrefix = options.pagesPrefix || "/";
|
|
90
|
+
|
|
91
|
+
const normalizeBasePath = (value) => {
|
|
92
|
+
const v = String(value || "").trim();
|
|
93
|
+
if (!v) return "/files";
|
|
94
|
+
return v.startsWith("/") ? v : `/${v}`;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const fileManagerPublicConfig = {
|
|
98
|
+
enabled: false,
|
|
99
|
+
basePath: "/files",
|
|
100
|
+
loaded: false,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Restart-required behavior: we load settings once and keep the values in memory.
|
|
104
|
+
(async () => {
|
|
105
|
+
try {
|
|
106
|
+
const enabledRaw = await globalSettingsService.getSettingValue(
|
|
107
|
+
"FILE_MANAGER_ENABLED",
|
|
108
|
+
"false",
|
|
109
|
+
);
|
|
110
|
+
const basePathRaw = await globalSettingsService.getSettingValue(
|
|
111
|
+
"FILE_MANAGER_BASE_PATH",
|
|
112
|
+
"/files",
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
fileManagerPublicConfig.enabled = String(enabledRaw) === "true";
|
|
116
|
+
fileManagerPublicConfig.basePath = normalizeBasePath(basePathRaw);
|
|
117
|
+
fileManagerPublicConfig.loaded = true;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error("Error loading File Manager public config:", error);
|
|
120
|
+
fileManagerPublicConfig.loaded = true;
|
|
121
|
+
}
|
|
122
|
+
})();
|
|
33
123
|
|
|
34
|
-
// Expose adminPath and WS attachment helper
|
|
124
|
+
// Expose adminPath, pagesPrefix and WS attachment helper
|
|
35
125
|
router.adminPath = adminPath;
|
|
126
|
+
router.pagesPrefix = pagesPrefix;
|
|
36
127
|
router.attachWs = (server) => {
|
|
37
|
-
const {
|
|
128
|
+
const {
|
|
129
|
+
attachTerminalWebsocketServer,
|
|
130
|
+
} = require("./services/terminalsWs.service");
|
|
38
131
|
attachTerminalWebsocketServer(server, { basePathPrefix: adminPath });
|
|
39
|
-
};
|
|
40
132
|
|
|
41
|
-
|
|
42
|
-
|
|
133
|
+
const {
|
|
134
|
+
attachExperimentsWebsocketServer,
|
|
135
|
+
} = require("./services/experimentsWs.service");
|
|
136
|
+
attachExperimentsWebsocketServer(server);
|
|
137
|
+
};
|
|
43
138
|
|
|
44
139
|
if (!errorCaptureInitialized) {
|
|
45
140
|
errorCaptureInitialized = true;
|
|
@@ -47,9 +142,14 @@ function createMiddleware(options = {}) {
|
|
|
47
142
|
setupProcessHandlers();
|
|
48
143
|
}
|
|
49
144
|
|
|
145
|
+
// Console manager will be initialized after database connection
|
|
146
|
+
|
|
50
147
|
// Database connection
|
|
51
148
|
const mongoUri =
|
|
52
|
-
options.mongodbUri ||
|
|
149
|
+
options.mongodbUri ||
|
|
150
|
+
options.dbConnection ||
|
|
151
|
+
process.env.MONGODB_URI ||
|
|
152
|
+
process.env.MONGO_URI;
|
|
53
153
|
|
|
54
154
|
if (!mongoUri && mongoose.connection.readyState !== 1) {
|
|
55
155
|
console.warn(
|
|
@@ -60,23 +160,135 @@ function createMiddleware(options = {}) {
|
|
|
60
160
|
serverSelectionTimeoutMS: 5000,
|
|
61
161
|
maxPoolSize: 10,
|
|
62
162
|
};
|
|
63
|
-
|
|
163
|
+
|
|
64
164
|
// Return a promise that resolves when connection is established
|
|
65
165
|
const connectionPromise = mongoose
|
|
66
166
|
.connect(mongoUri, connectionOptions)
|
|
67
|
-
.then(() => {
|
|
167
|
+
.then(async () => {
|
|
68
168
|
console.log("✅ Middleware: Connected to MongoDB");
|
|
169
|
+
// Start cron scheduler after DB connection
|
|
170
|
+
await cronScheduler.start();
|
|
171
|
+
await healthChecksScheduler.start();
|
|
172
|
+
await healthChecksBootstrap.bootstrap();
|
|
173
|
+
await blogCronsBootstrap.bootstrap();
|
|
174
|
+
await require("./services/experimentsCronsBootstrap.service").bootstrap();
|
|
175
|
+
|
|
176
|
+
// Console manager is already initialized early in the middleware
|
|
177
|
+
console.log("[Console Manager] MongoDB connection established");
|
|
178
|
+
|
|
69
179
|
return true;
|
|
70
180
|
})
|
|
71
181
|
.catch((err) => {
|
|
72
182
|
console.error("❌ Middleware: MongoDB connection error:", err);
|
|
73
183
|
return false;
|
|
74
184
|
});
|
|
75
|
-
|
|
185
|
+
|
|
186
|
+
router.get(`${adminPath}/health-checks`, basicAuth, (req, res) => {
|
|
187
|
+
const templatePath = path.join(
|
|
188
|
+
__dirname,
|
|
189
|
+
"..",
|
|
190
|
+
"views",
|
|
191
|
+
"admin-health-checks.ejs",
|
|
192
|
+
);
|
|
193
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
194
|
+
if (err) {
|
|
195
|
+
console.error("Error reading template:", err);
|
|
196
|
+
return res.status(500).send("Error loading page");
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const html = ejs.render(
|
|
200
|
+
template,
|
|
201
|
+
{
|
|
202
|
+
baseUrl: req.baseUrl,
|
|
203
|
+
adminPath,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
filename: templatePath,
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
res.send(html);
|
|
210
|
+
} catch (renderErr) {
|
|
211
|
+
console.error("Error rendering template:", renderErr);
|
|
212
|
+
res.status(500).send("Error rendering page");
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
router.get(`${adminPath}/console-manager`, basicAuth, (req, res) => {
|
|
218
|
+
const templatePath = path.join(
|
|
219
|
+
__dirname,
|
|
220
|
+
"..",
|
|
221
|
+
"views",
|
|
222
|
+
"admin-console-manager.ejs",
|
|
223
|
+
);
|
|
224
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
225
|
+
if (err) {
|
|
226
|
+
console.error("Error reading template:", err);
|
|
227
|
+
return res.status(500).send("Error loading page");
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
const html = ejs.render(
|
|
231
|
+
template,
|
|
232
|
+
{
|
|
233
|
+
baseUrl: req.baseUrl,
|
|
234
|
+
adminPath,
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
filename: templatePath,
|
|
238
|
+
},
|
|
239
|
+
);
|
|
240
|
+
res.send(html);
|
|
241
|
+
} catch (renderErr) {
|
|
242
|
+
console.error("Error rendering template:", renderErr);
|
|
243
|
+
res.status(500).send("Error rendering page");
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
76
248
|
// Store the promise so it can be awaited if needed
|
|
77
249
|
router.connectionPromise = connectionPromise;
|
|
78
250
|
} else if (mongoose.connection.readyState === 1) {
|
|
79
251
|
console.log("✅ Middleware: Using existing MongoDB connection");
|
|
252
|
+
// Start cron scheduler for existing connection
|
|
253
|
+
cronScheduler.start().catch((err) => {
|
|
254
|
+
console.error("Failed to start cron scheduler:", err);
|
|
255
|
+
});
|
|
256
|
+
healthChecksScheduler.start().catch((err) => {
|
|
257
|
+
console.error("Failed to start health checks scheduler:", err);
|
|
258
|
+
});
|
|
259
|
+
healthChecksBootstrap.bootstrap().catch((err) => {
|
|
260
|
+
console.error("Failed to bootstrap health checks:", err);
|
|
261
|
+
});
|
|
262
|
+
blogCronsBootstrap.bootstrap().catch((err) => {
|
|
263
|
+
console.error("Failed to bootstrap blog crons:", err);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
require("./services/experimentsCronsBootstrap.service")
|
|
267
|
+
.bootstrap()
|
|
268
|
+
.catch((err) => {
|
|
269
|
+
console.error("Failed to bootstrap experiments crons:", err);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Initialize console manager AFTER database is already connected
|
|
273
|
+
if (process.env.NODE_ENV !== "test" && !process.env.JEST_WORKER_ID) {
|
|
274
|
+
isConsoleManagerEnabled().then(consoleManagerEnabled => {
|
|
275
|
+
if (consoleManagerEnabled) {
|
|
276
|
+
consoleManager.init();
|
|
277
|
+
// Set module prefix after initialization
|
|
278
|
+
consoleManager.setModulePrefix('middleware');
|
|
279
|
+
console.log("[Console Manager] Initialized");
|
|
280
|
+
} else {
|
|
281
|
+
console.log("[Console Manager] Disabled - console methods not overridden");
|
|
282
|
+
}
|
|
283
|
+
}).catch(error => {
|
|
284
|
+
console.error("[Console Manager] Error checking enabled status:", error);
|
|
285
|
+
console.log("[Console Manager] Fallback to enabled due to error");
|
|
286
|
+
consoleManager.init();
|
|
287
|
+
// Set module prefix after initialization
|
|
288
|
+
consoleManager.setModulePrefix('middleware');
|
|
289
|
+
console.log("[Console Manager] Initialized (fallback)");
|
|
290
|
+
});
|
|
291
|
+
}
|
|
80
292
|
}
|
|
81
293
|
|
|
82
294
|
// CORS configuration
|
|
@@ -138,6 +350,12 @@ function createMiddleware(options = {}) {
|
|
|
138
350
|
webhookHandler,
|
|
139
351
|
);
|
|
140
352
|
|
|
353
|
+
router.use(
|
|
354
|
+
"/proxy",
|
|
355
|
+
express.raw({ type: "*/*", limit: "10mb" }),
|
|
356
|
+
require("./routes/proxy.routes"),
|
|
357
|
+
);
|
|
358
|
+
|
|
141
359
|
// Regular JSON parsing for other routes (skip if parent app already handles it)
|
|
142
360
|
if (!options.skipBodyParser) {
|
|
143
361
|
router.use(express.json());
|
|
@@ -146,6 +364,8 @@ function createMiddleware(options = {}) {
|
|
|
146
364
|
|
|
147
365
|
router.use(requestIdMiddleware);
|
|
148
366
|
|
|
367
|
+
router.use("/api", rateLimiter.limit("globalApiLimiter"));
|
|
368
|
+
|
|
149
369
|
// Serve public static files (e.g. /og/og-default.png)
|
|
150
370
|
router.use(express.static(path.join(__dirname, "..", "public")));
|
|
151
371
|
|
|
@@ -164,6 +384,53 @@ function createMiddleware(options = {}) {
|
|
|
164
384
|
// EJS locals: feature flags for server-rendered pages
|
|
165
385
|
router.use(createFeatureFlagsEjsMiddleware());
|
|
166
386
|
|
|
387
|
+
// Public File Manager SPA (gated by global settings; restart required)
|
|
388
|
+
router.get("*", (req, res, next) => {
|
|
389
|
+
try {
|
|
390
|
+
if (!fileManagerPublicConfig.enabled) return next();
|
|
391
|
+
|
|
392
|
+
const basePath = fileManagerPublicConfig.basePath || "/files";
|
|
393
|
+
const reqPath = req.path;
|
|
394
|
+
const matches =
|
|
395
|
+
reqPath === basePath ||
|
|
396
|
+
reqPath === `${basePath}/` ||
|
|
397
|
+
reqPath.startsWith(`${basePath}/`);
|
|
398
|
+
|
|
399
|
+
if (!matches) return next();
|
|
400
|
+
if (req.method !== "GET") return next();
|
|
401
|
+
|
|
402
|
+
const templatePath = path.join(
|
|
403
|
+
__dirname,
|
|
404
|
+
"..",
|
|
405
|
+
"views",
|
|
406
|
+
"file-manager.ejs",
|
|
407
|
+
);
|
|
408
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
409
|
+
if (err) {
|
|
410
|
+
console.error("Error reading template:", err);
|
|
411
|
+
return res.status(500).send("Error loading page");
|
|
412
|
+
}
|
|
413
|
+
try {
|
|
414
|
+
const html = ejs.render(
|
|
415
|
+
template,
|
|
416
|
+
{
|
|
417
|
+
baseUrl: req.baseUrl,
|
|
418
|
+
fileManagerBasePath: basePath,
|
|
419
|
+
},
|
|
420
|
+
{ filename: templatePath },
|
|
421
|
+
);
|
|
422
|
+
res.send(html);
|
|
423
|
+
} catch (renderErr) {
|
|
424
|
+
console.error("Error rendering template:", renderErr);
|
|
425
|
+
res.status(500).send("Error rendering page");
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
} catch (error) {
|
|
429
|
+
console.error("Error serving File Manager SPA:", error);
|
|
430
|
+
next();
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
|
|
167
434
|
// API Routes
|
|
168
435
|
router.use("/api/auth", require("./routes/auth.routes"));
|
|
169
436
|
router.use("/api/billing", require("./routes/billing.routes"));
|
|
@@ -177,22 +444,96 @@ function createMiddleware(options = {}) {
|
|
|
177
444
|
);
|
|
178
445
|
router.use("/api/admin/orgs", require("./routes/orgAdmin.routes"));
|
|
179
446
|
router.use("/api/admin/users", require("./routes/userAdmin.routes"));
|
|
180
|
-
router.use("/api/admin/
|
|
447
|
+
router.use("/api/admin/rbac", require("./routes/adminRbac.routes"));
|
|
448
|
+
router.use(
|
|
449
|
+
"/api/admin/notifications",
|
|
450
|
+
require("./routes/notificationAdmin.routes"),
|
|
451
|
+
);
|
|
181
452
|
router.use("/api/admin/stripe", require("./routes/stripeAdmin.routes"));
|
|
182
|
-
|
|
453
|
+
|
|
183
454
|
// Stats Routes
|
|
184
455
|
const adminStatsController = require("./controllers/adminStats.controller");
|
|
185
|
-
router.get(
|
|
186
|
-
|
|
456
|
+
router.get(
|
|
457
|
+
"/api/admin/stats/overview",
|
|
458
|
+
basicAuth,
|
|
459
|
+
adminStatsController.getOverviewStats,
|
|
460
|
+
);
|
|
461
|
+
|
|
187
462
|
router.get(`${adminPath}/stats/dashboard-home`, basicAuth, (req, res) => {
|
|
188
|
-
const templatePath = path.join(
|
|
463
|
+
const templatePath = path.join(
|
|
464
|
+
__dirname,
|
|
465
|
+
"..",
|
|
466
|
+
"views",
|
|
467
|
+
"admin-dashboard-home.ejs",
|
|
468
|
+
);
|
|
189
469
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
190
470
|
if (err) {
|
|
191
471
|
console.error("Error reading template:", err);
|
|
192
472
|
return res.status(500).send("Error loading page");
|
|
193
473
|
}
|
|
194
474
|
try {
|
|
195
|
-
const html = ejs.render(
|
|
475
|
+
const html = ejs.render(
|
|
476
|
+
template,
|
|
477
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
478
|
+
{ filename: templatePath },
|
|
479
|
+
);
|
|
480
|
+
res.send(html);
|
|
481
|
+
} catch (renderErr) {
|
|
482
|
+
console.error("Error rendering template:", renderErr);
|
|
483
|
+
res.status(500).send("Error rendering page");
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
router.get(`${adminPath}/experiments`, basicAuth, (req, res) => {
|
|
489
|
+
const templatePath = path.join(
|
|
490
|
+
__dirname,
|
|
491
|
+
"..",
|
|
492
|
+
"views",
|
|
493
|
+
"admin-experiments.ejs",
|
|
494
|
+
);
|
|
495
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
496
|
+
if (err) {
|
|
497
|
+
console.error("Error reading template:", err);
|
|
498
|
+
return res.status(500).send("Error loading page");
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
const html = ejs.render(
|
|
502
|
+
template,
|
|
503
|
+
{
|
|
504
|
+
baseUrl: req.baseUrl,
|
|
505
|
+
adminPath,
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
filename: templatePath,
|
|
509
|
+
},
|
|
510
|
+
);
|
|
511
|
+
res.send(html);
|
|
512
|
+
} catch (renderErr) {
|
|
513
|
+
console.error("Error rendering template:", renderErr);
|
|
514
|
+
res.status(500).send("Error rendering page");
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
router.get(`${adminPath}/rbac`, basicAuth, (req, res) => {
|
|
520
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-rbac.ejs");
|
|
521
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
522
|
+
if (err) {
|
|
523
|
+
console.error("Error reading template:", err);
|
|
524
|
+
return res.status(500).send("Error loading page");
|
|
525
|
+
}
|
|
526
|
+
try {
|
|
527
|
+
const html = ejs.render(
|
|
528
|
+
template,
|
|
529
|
+
{
|
|
530
|
+
baseUrl: req.baseUrl,
|
|
531
|
+
adminPath,
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
filename: templatePath,
|
|
535
|
+
},
|
|
536
|
+
);
|
|
196
537
|
res.send(html);
|
|
197
538
|
} catch (renderErr) {
|
|
198
539
|
console.error("Error rendering template:", renderErr);
|
|
@@ -265,6 +606,89 @@ function createMiddleware(options = {}) {
|
|
|
265
606
|
});
|
|
266
607
|
});
|
|
267
608
|
|
|
609
|
+
router.get(`${adminPath}/crons`, basicAuth, (req, res) => {
|
|
610
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-crons.ejs");
|
|
611
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
612
|
+
if (err) {
|
|
613
|
+
console.error("Error reading template:", err);
|
|
614
|
+
return res.status(500).send("Error loading page");
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
const html = ejs.render(
|
|
618
|
+
template,
|
|
619
|
+
{
|
|
620
|
+
baseUrl: req.baseUrl,
|
|
621
|
+
adminPath,
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
filename: templatePath,
|
|
625
|
+
},
|
|
626
|
+
);
|
|
627
|
+
res.send(html);
|
|
628
|
+
} catch (renderErr) {
|
|
629
|
+
console.error("Error rendering template:", renderErr);
|
|
630
|
+
res.status(500).send("Error rendering page");
|
|
631
|
+
}
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
router.get(`${adminPath}/cache`, basicAuth, (req, res) => {
|
|
636
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-cache.ejs");
|
|
637
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
638
|
+
if (err) {
|
|
639
|
+
console.error("Error reading template:", err);
|
|
640
|
+
return res.status(500).send("Error loading page");
|
|
641
|
+
}
|
|
642
|
+
try {
|
|
643
|
+
const html = ejs.render(
|
|
644
|
+
template,
|
|
645
|
+
{
|
|
646
|
+
baseUrl: req.baseUrl,
|
|
647
|
+
adminPath,
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
filename: templatePath,
|
|
651
|
+
},
|
|
652
|
+
);
|
|
653
|
+
res.send(html);
|
|
654
|
+
} catch (renderErr) {
|
|
655
|
+
console.error("Error rendering template:", renderErr);
|
|
656
|
+
res.status(500).send("Error rendering page");
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
router.get(`${adminPath}/db-browser`, basicAuth, (req, res) => {
|
|
662
|
+
const templatePath = path.join(
|
|
663
|
+
__dirname,
|
|
664
|
+
"..",
|
|
665
|
+
"views",
|
|
666
|
+
"admin-db-browser.ejs",
|
|
667
|
+
);
|
|
668
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
669
|
+
if (err) {
|
|
670
|
+
console.error("Error reading template:", err);
|
|
671
|
+
return res.status(500).send("Error loading page");
|
|
672
|
+
}
|
|
673
|
+
try {
|
|
674
|
+
const html = ejs.render(
|
|
675
|
+
template,
|
|
676
|
+
{
|
|
677
|
+
baseUrl: req.baseUrl,
|
|
678
|
+
adminPath,
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
filename: templatePath,
|
|
682
|
+
},
|
|
683
|
+
);
|
|
684
|
+
res.send(html);
|
|
685
|
+
} catch (renderErr) {
|
|
686
|
+
console.error("Error rendering template:", renderErr);
|
|
687
|
+
res.status(500).send("Error rendering page");
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
|
|
268
692
|
router.use("/api/admin", require("./routes/admin.routes"));
|
|
269
693
|
router.use("/api/admin/settings", require("./routes/globalSettings.routes"));
|
|
270
694
|
router.use(
|
|
@@ -275,6 +699,11 @@ function createMiddleware(options = {}) {
|
|
|
275
699
|
"/api/admin/json-configs",
|
|
276
700
|
require("./routes/adminJsonConfigs.routes"),
|
|
277
701
|
);
|
|
702
|
+
router.use(
|
|
703
|
+
"/api/admin/rate-limits",
|
|
704
|
+
require("./routes/adminRateLimits.routes"),
|
|
705
|
+
);
|
|
706
|
+
router.use("/api/admin/proxy", require("./routes/adminProxy.routes"));
|
|
278
707
|
router.use(
|
|
279
708
|
"/api/admin/seo-config",
|
|
280
709
|
require("./routes/adminSeoConfig.routes"),
|
|
@@ -282,19 +711,52 @@ function createMiddleware(options = {}) {
|
|
|
282
711
|
router.use("/api/admin/i18n", require("./routes/adminI18n.routes"));
|
|
283
712
|
router.use("/api/admin/headless", require("./routes/adminHeadless.routes"));
|
|
284
713
|
router.use("/api/admin/scripts", require("./routes/adminScripts.routes"));
|
|
714
|
+
router.use("/api/admin/crons", require("./routes/adminCrons.routes"));
|
|
715
|
+
router.use(
|
|
716
|
+
"/api/admin/health-checks",
|
|
717
|
+
require("./routes/adminHealthChecks.routes"),
|
|
718
|
+
);
|
|
719
|
+
router.use("/api/admin/cache", require("./routes/adminCache.routes"));
|
|
720
|
+
router.use(
|
|
721
|
+
"/api/admin/console-manager",
|
|
722
|
+
require("./routes/adminConsoleManager.routes"),
|
|
723
|
+
);
|
|
724
|
+
router.use(
|
|
725
|
+
"/api/admin/db-browser",
|
|
726
|
+
require("./routes/adminDbBrowser.routes"),
|
|
727
|
+
);
|
|
285
728
|
router.use("/api/admin/terminals", require("./routes/adminTerminals.routes"));
|
|
729
|
+
router.use("/api/admin/experiments", require("./routes/adminExperiments.routes"));
|
|
286
730
|
router.use("/api/admin/assets", require("./routes/adminAssets.routes"));
|
|
287
731
|
router.use(
|
|
288
732
|
"/api/admin/upload-namespaces",
|
|
289
733
|
require("./routes/adminUploadNamespaces.routes"),
|
|
290
734
|
);
|
|
291
|
-
router.use(
|
|
735
|
+
router.use(
|
|
736
|
+
"/api/admin/ui-components",
|
|
737
|
+
require("./routes/adminUiComponents.routes"),
|
|
738
|
+
);
|
|
292
739
|
router.use("/api/admin/migration", require("./routes/adminMigration.routes"));
|
|
293
|
-
router.use(
|
|
294
|
-
|
|
740
|
+
router.use(
|
|
741
|
+
"/api/admin/errors",
|
|
742
|
+
basicAuth,
|
|
743
|
+
require("./routes/adminErrors.routes"),
|
|
744
|
+
);
|
|
745
|
+
router.use(
|
|
746
|
+
"/api/admin/audit",
|
|
747
|
+
basicAuth,
|
|
748
|
+
require("./routes/adminAudit.routes"),
|
|
749
|
+
);
|
|
295
750
|
router.use("/api/admin/llm", require("./routes/adminLlm.routes"));
|
|
296
|
-
router.use(
|
|
297
|
-
|
|
751
|
+
router.use(
|
|
752
|
+
"/api/admin/ejs-virtual",
|
|
753
|
+
require("./routes/adminEjsVirtual.routes"),
|
|
754
|
+
);
|
|
755
|
+
router.use("/api/admin/pages", require("./routes/adminPages.routes"));
|
|
756
|
+
router.use("/api/admin", require("./routes/adminBlog.routes"));
|
|
757
|
+
router.use("/api/admin", require("./routes/adminBlogAi.routes"));
|
|
758
|
+
router.use("/api/admin", require("./routes/adminBlogAutomation.routes"));
|
|
759
|
+
router.use("/api/admin/workflows", basicAuth, require("./routes/workflows.routes"));
|
|
298
760
|
router.use("/w", require("./routes/workflowWebhook.routes"));
|
|
299
761
|
router.use("/api/webhooks", require("./routes/webhook.routes"));
|
|
300
762
|
router.use("/api/settings", require("./routes/globalSettings.routes"));
|
|
@@ -310,21 +772,47 @@ function createMiddleware(options = {}) {
|
|
|
310
772
|
router.use("/api/log", require("./routes/log.routes"));
|
|
311
773
|
router.use("/api/error-tracking", require("./routes/errorTracking.routes"));
|
|
312
774
|
router.use("/api/ui-components", require("./routes/uiComponentsPublic.routes"));
|
|
313
|
-
router.use("/api/
|
|
775
|
+
router.use("/api/rbac", require("./routes/rbac.routes"));
|
|
776
|
+
router.use("/api/file-manager", require("./routes/fileManager.routes"));
|
|
777
|
+
router.use("/api/experiments", require("./routes/experiments.routes"));
|
|
778
|
+
|
|
779
|
+
// Public blog APIs (headless)
|
|
780
|
+
router.use("/api", require("./routes/blogPublic.routes"));
|
|
781
|
+
|
|
782
|
+
// Internal blog endpoints (used by HTTP CronJobs)
|
|
783
|
+
router.use("/api/internal", require("./routes/blogInternal.routes"));
|
|
784
|
+
|
|
785
|
+
// Internal experiments endpoints (used by HTTP CronJobs)
|
|
786
|
+
router.use("/api/internal", require("./routes/internalExperiments.routes"));
|
|
787
|
+
|
|
788
|
+
// Public health checks status (gated by global setting)
|
|
789
|
+
router.use(
|
|
790
|
+
"/api/health-checks",
|
|
791
|
+
require("./routes/healthChecksPublic.routes"),
|
|
792
|
+
);
|
|
314
793
|
|
|
315
794
|
// Public assets proxy
|
|
316
795
|
router.use("/public/assets", require("./routes/publicAssets.routes"));
|
|
317
796
|
|
|
318
797
|
// Admin dashboard (polished view)
|
|
319
798
|
router.get(adminPath, basicAuth, (req, res) => {
|
|
320
|
-
const templatePath = path.join(
|
|
799
|
+
const templatePath = path.join(
|
|
800
|
+
__dirname,
|
|
801
|
+
"..",
|
|
802
|
+
"views",
|
|
803
|
+
"admin-dashboard.ejs",
|
|
804
|
+
);
|
|
321
805
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
322
806
|
if (err) {
|
|
323
807
|
console.error("Error reading template:", err);
|
|
324
808
|
return res.status(500).send("Error loading page");
|
|
325
809
|
}
|
|
326
810
|
try {
|
|
327
|
-
const html = ejs.render(
|
|
811
|
+
const html = ejs.render(
|
|
812
|
+
template,
|
|
813
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
814
|
+
{ filename: templatePath },
|
|
815
|
+
);
|
|
328
816
|
res.send(html);
|
|
329
817
|
} catch (renderErr) {
|
|
330
818
|
console.error("Error rendering template:", renderErr);
|
|
@@ -362,7 +850,12 @@ function createMiddleware(options = {}) {
|
|
|
362
850
|
});
|
|
363
851
|
|
|
364
852
|
router.get(`${adminPath}/migration`, basicAuth, (req, res) => {
|
|
365
|
-
const templatePath = path.join(
|
|
853
|
+
const templatePath = path.join(
|
|
854
|
+
__dirname,
|
|
855
|
+
"..",
|
|
856
|
+
"views",
|
|
857
|
+
"admin-migration.ejs",
|
|
858
|
+
);
|
|
366
859
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
367
860
|
if (err) {
|
|
368
861
|
console.error("Error reading template:", err);
|
|
@@ -390,12 +883,59 @@ function createMiddleware(options = {}) {
|
|
|
390
883
|
|
|
391
884
|
// Admin LLM/AI page (protected by basic auth)
|
|
392
885
|
router.get(`${adminPath}/admin-llm`, basicAuth, (req, res) => {
|
|
886
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-llm.ejs");
|
|
887
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
888
|
+
if (err) {
|
|
889
|
+
console.error("Error reading template:", err);
|
|
890
|
+
return res.status(500).send("Error loading page");
|
|
891
|
+
}
|
|
892
|
+
try {
|
|
893
|
+
const html = ejs.render(
|
|
894
|
+
template,
|
|
895
|
+
{
|
|
896
|
+
baseUrl: req.baseUrl,
|
|
897
|
+
adminPath,
|
|
898
|
+
},
|
|
899
|
+
{
|
|
900
|
+
filename: templatePath,
|
|
901
|
+
},
|
|
902
|
+
);
|
|
903
|
+
res.send(html);
|
|
904
|
+
} catch (renderErr) {
|
|
905
|
+
console.error("Error rendering template:", renderErr);
|
|
906
|
+
res.status(500).send("Error rendering page");
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
router.get(`${adminPath}/workflows/:id`, basicAuth, (req, res) => {
|
|
393
912
|
const templatePath = path.join(
|
|
394
913
|
__dirname,
|
|
395
914
|
"..",
|
|
396
915
|
"views",
|
|
397
|
-
"admin-
|
|
916
|
+
"admin-workflows.ejs",
|
|
398
917
|
);
|
|
918
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
919
|
+
if (err) {
|
|
920
|
+
console.error("Error reading template:", err);
|
|
921
|
+
return res.status(500).send("Error loading page");
|
|
922
|
+
}
|
|
923
|
+
try {
|
|
924
|
+
const html = ejs.render(
|
|
925
|
+
template,
|
|
926
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
927
|
+
{ filename: templatePath },
|
|
928
|
+
);
|
|
929
|
+
res.send(html);
|
|
930
|
+
} catch (renderErr) {
|
|
931
|
+
console.error("Error rendering template:", renderErr);
|
|
932
|
+
res.status(500).send("Error rendering page");
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
router.get(`${adminPath}/pages`, basicAuth, (req, res) => {
|
|
938
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-pages.ejs");
|
|
399
939
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
400
940
|
if (err) {
|
|
401
941
|
console.error("Error reading template:", err);
|
|
@@ -420,15 +960,133 @@ function createMiddleware(options = {}) {
|
|
|
420
960
|
});
|
|
421
961
|
});
|
|
422
962
|
|
|
423
|
-
router.get(`${adminPath}/
|
|
424
|
-
const templatePath = path.join(__dirname, "..", "views", "admin-
|
|
963
|
+
router.get(`${adminPath}/blog`, basicAuth, (req, res) => {
|
|
964
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-blog.ejs");
|
|
425
965
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
426
966
|
if (err) {
|
|
427
967
|
console.error("Error reading template:", err);
|
|
428
968
|
return res.status(500).send("Error loading page");
|
|
429
969
|
}
|
|
430
970
|
try {
|
|
431
|
-
const html = ejs.render(
|
|
971
|
+
const html = ejs.render(
|
|
972
|
+
template,
|
|
973
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
974
|
+
{ filename: templatePath },
|
|
975
|
+
);
|
|
976
|
+
res.send(html);
|
|
977
|
+
} catch (renderErr) {
|
|
978
|
+
console.error("Error rendering template:", renderErr);
|
|
979
|
+
res.status(500).send("Error rendering page");
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
router.get(`${adminPath}/blog-automation`, basicAuth, (req, res) => {
|
|
985
|
+
const templatePath = path.join(
|
|
986
|
+
__dirname,
|
|
987
|
+
"..",
|
|
988
|
+
"views",
|
|
989
|
+
"admin-blog-automation.ejs",
|
|
990
|
+
);
|
|
991
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
992
|
+
if (err) {
|
|
993
|
+
console.error("Error reading template:", err);
|
|
994
|
+
return res.status(500).send("Error loading page");
|
|
995
|
+
}
|
|
996
|
+
try {
|
|
997
|
+
const html = ejs.render(
|
|
998
|
+
template,
|
|
999
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1000
|
+
{ filename: templatePath },
|
|
1001
|
+
);
|
|
1002
|
+
res.send(html);
|
|
1003
|
+
} catch (renderErr) {
|
|
1004
|
+
console.error("Error rendering template:", renderErr);
|
|
1005
|
+
res.status(500).send("Error rendering page");
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
router.get(`${adminPath}/blog/new`, basicAuth, (req, res) => {
|
|
1011
|
+
const templatePath = path.join(
|
|
1012
|
+
__dirname,
|
|
1013
|
+
"..",
|
|
1014
|
+
"views",
|
|
1015
|
+
"admin-blog-edit.ejs",
|
|
1016
|
+
);
|
|
1017
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1018
|
+
if (err) {
|
|
1019
|
+
console.error("Error reading template:", err);
|
|
1020
|
+
return res.status(500).send("Error loading page");
|
|
1021
|
+
}
|
|
1022
|
+
try {
|
|
1023
|
+
const html = ejs.render(
|
|
1024
|
+
template,
|
|
1025
|
+
{ baseUrl: req.baseUrl, adminPath, postId: "", mode: "new" },
|
|
1026
|
+
{ filename: templatePath },
|
|
1027
|
+
);
|
|
1028
|
+
res.send(html);
|
|
1029
|
+
} catch (renderErr) {
|
|
1030
|
+
console.error("Error rendering template:", renderErr);
|
|
1031
|
+
res.status(500).send("Error rendering page");
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
router.get(`${adminPath}/blog/edit/:id`, basicAuth, (req, res) => {
|
|
1037
|
+
const templatePath = path.join(
|
|
1038
|
+
__dirname,
|
|
1039
|
+
"..",
|
|
1040
|
+
"views",
|
|
1041
|
+
"admin-blog-edit.ejs",
|
|
1042
|
+
);
|
|
1043
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1044
|
+
if (err) {
|
|
1045
|
+
console.error("Error reading template:", err);
|
|
1046
|
+
return res.status(500).send("Error loading page");
|
|
1047
|
+
}
|
|
1048
|
+
try {
|
|
1049
|
+
const html = ejs.render(
|
|
1050
|
+
template,
|
|
1051
|
+
{
|
|
1052
|
+
baseUrl: req.baseUrl,
|
|
1053
|
+
adminPath,
|
|
1054
|
+
postId: String(req.params.id || ""),
|
|
1055
|
+
mode: "edit",
|
|
1056
|
+
},
|
|
1057
|
+
{ filename: templatePath },
|
|
1058
|
+
);
|
|
1059
|
+
res.send(html);
|
|
1060
|
+
} catch (renderErr) {
|
|
1061
|
+
console.error("Error rendering template:", renderErr);
|
|
1062
|
+
res.status(500).send("Error rendering page");
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
router.get(`${adminPath}/file-manager`, basicAuth, (req, res) => {
|
|
1068
|
+
const templatePath = path.join(
|
|
1069
|
+
__dirname,
|
|
1070
|
+
"..",
|
|
1071
|
+
"views",
|
|
1072
|
+
"admin-file-manager.ejs",
|
|
1073
|
+
);
|
|
1074
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1075
|
+
if (err) {
|
|
1076
|
+
console.error("Error reading template:", err);
|
|
1077
|
+
return res.status(500).send("Error loading page");
|
|
1078
|
+
}
|
|
1079
|
+
try {
|
|
1080
|
+
const html = ejs.render(
|
|
1081
|
+
template,
|
|
1082
|
+
{
|
|
1083
|
+
baseUrl: req.baseUrl,
|
|
1084
|
+
adminPath,
|
|
1085
|
+
},
|
|
1086
|
+
{
|
|
1087
|
+
filename: templatePath,
|
|
1088
|
+
},
|
|
1089
|
+
);
|
|
432
1090
|
res.send(html);
|
|
433
1091
|
} catch (renderErr) {
|
|
434
1092
|
console.error("Error rendering template:", renderErr);
|
|
@@ -438,7 +1096,12 @@ function createMiddleware(options = {}) {
|
|
|
438
1096
|
});
|
|
439
1097
|
|
|
440
1098
|
router.get(`${adminPath}/ejs-virtual`, basicAuth, (req, res) => {
|
|
441
|
-
const templatePath = path.join(
|
|
1099
|
+
const templatePath = path.join(
|
|
1100
|
+
__dirname,
|
|
1101
|
+
"..",
|
|
1102
|
+
"views",
|
|
1103
|
+
"admin-ejs-virtual.ejs",
|
|
1104
|
+
);
|
|
442
1105
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
443
1106
|
if (err) {
|
|
444
1107
|
console.error("Error reading template:", err);
|
|
@@ -464,7 +1127,12 @@ function createMiddleware(options = {}) {
|
|
|
464
1127
|
});
|
|
465
1128
|
|
|
466
1129
|
router.get(`${adminPath}/seo-config`, basicAuth, (req, res) => {
|
|
467
|
-
const templatePath = path.join(
|
|
1130
|
+
const templatePath = path.join(
|
|
1131
|
+
__dirname,
|
|
1132
|
+
"..",
|
|
1133
|
+
"views",
|
|
1134
|
+
"admin-seo-config.ejs",
|
|
1135
|
+
);
|
|
468
1136
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
469
1137
|
if (err) {
|
|
470
1138
|
console.error("Error reading template:", err);
|
|
@@ -498,7 +1166,11 @@ function createMiddleware(options = {}) {
|
|
|
498
1166
|
return res.status(500).send("Error loading page");
|
|
499
1167
|
}
|
|
500
1168
|
try {
|
|
501
|
-
const html = ejs.render(
|
|
1169
|
+
const html = ejs.render(
|
|
1170
|
+
template,
|
|
1171
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1172
|
+
{ filename: templatePath },
|
|
1173
|
+
);
|
|
502
1174
|
res.send(html);
|
|
503
1175
|
} catch (renderErr) {
|
|
504
1176
|
console.error("Error rendering template:", renderErr);
|
|
@@ -520,7 +1192,11 @@ function createMiddleware(options = {}) {
|
|
|
520
1192
|
return res.status(500).send("Error loading page");
|
|
521
1193
|
}
|
|
522
1194
|
try {
|
|
523
|
-
const html = ejs.render(
|
|
1195
|
+
const html = ejs.render(
|
|
1196
|
+
template,
|
|
1197
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1198
|
+
{ filename: templatePath },
|
|
1199
|
+
);
|
|
524
1200
|
res.send(html);
|
|
525
1201
|
} catch (renderErr) {
|
|
526
1202
|
console.error("Error rendering template:", renderErr);
|
|
@@ -784,12 +1460,7 @@ function createMiddleware(options = {}) {
|
|
|
784
1460
|
|
|
785
1461
|
// Admin users page (protected by basic auth)
|
|
786
1462
|
router.get(`${adminPath}/users`, basicAuth, (req, res) => {
|
|
787
|
-
const templatePath = path.join(
|
|
788
|
-
__dirname,
|
|
789
|
-
"..",
|
|
790
|
-
"views",
|
|
791
|
-
"admin-users.ejs",
|
|
792
|
-
);
|
|
1463
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-users.ejs");
|
|
793
1464
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
794
1465
|
if (err) {
|
|
795
1466
|
console.error("Error reading template:", err);
|
|
@@ -908,6 +1579,31 @@ function createMiddleware(options = {}) {
|
|
|
908
1579
|
});
|
|
909
1580
|
});
|
|
910
1581
|
|
|
1582
|
+
router.get(`${adminPath}/rate-limiter`, basicAuth, (req, res) => {
|
|
1583
|
+
const templatePath = path.join(
|
|
1584
|
+
__dirname,
|
|
1585
|
+
"..",
|
|
1586
|
+
"views",
|
|
1587
|
+
"admin-rate-limiter.ejs",
|
|
1588
|
+
);
|
|
1589
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1590
|
+
if (err) {
|
|
1591
|
+
console.error("Error reading template:", err);
|
|
1592
|
+
return res.status(500).send("Error loading page");
|
|
1593
|
+
}
|
|
1594
|
+
try {
|
|
1595
|
+
const html = ejs.render(template, {
|
|
1596
|
+
baseUrl: req.baseUrl,
|
|
1597
|
+
adminPath,
|
|
1598
|
+
});
|
|
1599
|
+
res.send(html);
|
|
1600
|
+
} catch (renderErr) {
|
|
1601
|
+
console.error("Error rendering template:", renderErr);
|
|
1602
|
+
res.status(500).send("Error rendering page");
|
|
1603
|
+
}
|
|
1604
|
+
});
|
|
1605
|
+
});
|
|
1606
|
+
|
|
911
1607
|
// Admin global settings page (protected by basic auth) - render manually
|
|
912
1608
|
router.get(`${adminPath}/global-settings`, basicAuth, (req, res) => {
|
|
913
1609
|
const templatePath = path.join(
|
|
@@ -932,14 +1628,23 @@ function createMiddleware(options = {}) {
|
|
|
932
1628
|
});
|
|
933
1629
|
|
|
934
1630
|
router.get(`${adminPath}/errors`, basicAuth, (req, res) => {
|
|
935
|
-
const templatePath = path.join(
|
|
1631
|
+
const templatePath = path.join(
|
|
1632
|
+
__dirname,
|
|
1633
|
+
"..",
|
|
1634
|
+
"views",
|
|
1635
|
+
"admin-errors.ejs",
|
|
1636
|
+
);
|
|
936
1637
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
937
1638
|
if (err) {
|
|
938
1639
|
console.error("Error reading template:", err);
|
|
939
1640
|
return res.status(500).send("Error loading page");
|
|
940
1641
|
}
|
|
941
1642
|
try {
|
|
942
|
-
const html = ejs.render(
|
|
1643
|
+
const html = ejs.render(
|
|
1644
|
+
template,
|
|
1645
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1646
|
+
{ filename: templatePath },
|
|
1647
|
+
);
|
|
943
1648
|
res.send(html);
|
|
944
1649
|
} catch (renderErr) {
|
|
945
1650
|
console.error("Error rendering template:", renderErr);
|
|
@@ -956,7 +1661,11 @@ function createMiddleware(options = {}) {
|
|
|
956
1661
|
return res.status(500).send("Error loading page");
|
|
957
1662
|
}
|
|
958
1663
|
try {
|
|
959
|
-
const html = ejs.render(
|
|
1664
|
+
const html = ejs.render(
|
|
1665
|
+
template,
|
|
1666
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1667
|
+
{ filename: templatePath },
|
|
1668
|
+
);
|
|
960
1669
|
res.send(html);
|
|
961
1670
|
} catch (renderErr) {
|
|
962
1671
|
console.error("Error rendering template:", renderErr);
|
|
@@ -966,14 +1675,44 @@ function createMiddleware(options = {}) {
|
|
|
966
1675
|
});
|
|
967
1676
|
|
|
968
1677
|
router.get(`${adminPath}/coolify-deploy`, basicAuth, (req, res) => {
|
|
969
|
-
const templatePath = path.join(
|
|
1678
|
+
const templatePath = path.join(
|
|
1679
|
+
__dirname,
|
|
1680
|
+
"..",
|
|
1681
|
+
"views",
|
|
1682
|
+
"admin-coolify-deploy.ejs",
|
|
1683
|
+
);
|
|
970
1684
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
971
1685
|
if (err) {
|
|
972
1686
|
console.error("Error reading template:", err);
|
|
973
1687
|
return res.status(500).send("Error loading page");
|
|
974
1688
|
}
|
|
975
1689
|
try {
|
|
976
|
-
const html = ejs.render(
|
|
1690
|
+
const html = ejs.render(
|
|
1691
|
+
template,
|
|
1692
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1693
|
+
{ filename: templatePath },
|
|
1694
|
+
);
|
|
1695
|
+
res.send(html);
|
|
1696
|
+
} catch (renderErr) {
|
|
1697
|
+
console.error("Error rendering template:", renderErr);
|
|
1698
|
+
res.status(500).send("Error rendering page");
|
|
1699
|
+
}
|
|
1700
|
+
});
|
|
1701
|
+
});
|
|
1702
|
+
|
|
1703
|
+
router.get(`${adminPath}/proxy`, basicAuth, (req, res) => {
|
|
1704
|
+
const templatePath = path.join(__dirname, "..", "views", "admin-proxy.ejs");
|
|
1705
|
+
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
1706
|
+
if (err) {
|
|
1707
|
+
console.error("Error reading template:", err);
|
|
1708
|
+
return res.status(500).send("Error loading page");
|
|
1709
|
+
}
|
|
1710
|
+
try {
|
|
1711
|
+
const html = ejs.render(
|
|
1712
|
+
template,
|
|
1713
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1714
|
+
{ filename: templatePath },
|
|
1715
|
+
);
|
|
977
1716
|
res.send(html);
|
|
978
1717
|
} catch (renderErr) {
|
|
979
1718
|
console.error("Error rendering template:", renderErr);
|
|
@@ -983,14 +1722,23 @@ function createMiddleware(options = {}) {
|
|
|
983
1722
|
});
|
|
984
1723
|
|
|
985
1724
|
router.get(`${adminPath}/webhooks`, basicAuth, (req, res) => {
|
|
986
|
-
const templatePath = path.join(
|
|
1725
|
+
const templatePath = path.join(
|
|
1726
|
+
__dirname,
|
|
1727
|
+
"..",
|
|
1728
|
+
"views",
|
|
1729
|
+
"admin-webhooks.ejs",
|
|
1730
|
+
);
|
|
987
1731
|
fs.readFile(templatePath, "utf8", (err, template) => {
|
|
988
1732
|
if (err) {
|
|
989
1733
|
console.error("Error reading template:", err);
|
|
990
1734
|
return res.status(500).send("Error loading page");
|
|
991
1735
|
}
|
|
992
1736
|
try {
|
|
993
|
-
const html = ejs.render(
|
|
1737
|
+
const html = ejs.render(
|
|
1738
|
+
template,
|
|
1739
|
+
{ baseUrl: req.baseUrl, adminPath },
|
|
1740
|
+
{ filename: templatePath },
|
|
1741
|
+
);
|
|
994
1742
|
res.send(html);
|
|
995
1743
|
} catch (renderErr) {
|
|
996
1744
|
console.error("Error rendering template:", renderErr);
|
|
@@ -999,7 +1747,7 @@ function createMiddleware(options = {}) {
|
|
|
999
1747
|
});
|
|
1000
1748
|
});
|
|
1001
1749
|
|
|
1002
|
-
router.get("/health", (req, res) => {
|
|
1750
|
+
router.get("/health", rateLimiter.limit("healthRateLimiter"), (req, res) => {
|
|
1003
1751
|
res.json({
|
|
1004
1752
|
status: "ok",
|
|
1005
1753
|
mode: "middleware",
|
|
@@ -1011,6 +1759,20 @@ function createMiddleware(options = {}) {
|
|
|
1011
1759
|
router.use("/api/ejs-virtual", require("./routes/adminEjsVirtual.routes"));
|
|
1012
1760
|
router.use("/api/webhooks", require("./routes/webhook.routes"));
|
|
1013
1761
|
|
|
1762
|
+
// Store pagesPrefix and adminPath on app for pages router
|
|
1763
|
+
router.use((req, res, next) => {
|
|
1764
|
+
if (!req.app.get("pagesPrefix")) {
|
|
1765
|
+
req.app.set("pagesPrefix", pagesPrefix);
|
|
1766
|
+
}
|
|
1767
|
+
if (!req.app.get("adminPath")) {
|
|
1768
|
+
req.app.set("adminPath", adminPath);
|
|
1769
|
+
}
|
|
1770
|
+
next();
|
|
1771
|
+
});
|
|
1772
|
+
|
|
1773
|
+
// Public pages router (catch-all, must be last before error handler)
|
|
1774
|
+
router.use(require("./routes/pages.routes"));
|
|
1775
|
+
|
|
1014
1776
|
// Error handling middleware
|
|
1015
1777
|
router.use(expressErrorMiddleware);
|
|
1016
1778
|
|