@intranefr/superbackend 1.5.2 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cookies.txt +6 -0
- package/cookies1.txt +6 -0
- package/cookies2.txt +6 -0
- package/cookies3.txt +6 -0
- package/cookies4.txt +5 -0
- package/cookies_old.txt +5 -0
- package/cookies_old_test.txt +6 -0
- package/cookies_super.txt +5 -0
- package/cookies_super_test.txt +6 -0
- package/cookies_test.txt +6 -0
- package/index.js +9 -0
- package/manage.js +745 -0
- package/package.json +6 -2
- package/plugins/core-waiting-list-migration/README.md +118 -0
- package/plugins/core-waiting-list-migration/index.js +438 -0
- package/plugins/global-settings-presets/index.js +20 -0
- package/plugins/hello-cli/index.js +17 -0
- package/plugins/ui-components-seeder/components/suiAlert.js +212 -0
- package/plugins/ui-components-seeder/components/suiToast.js +186 -0
- package/plugins/ui-components-seeder/index.js +31 -0
- package/public/js/admin-ui-components-preview.js +281 -0
- package/public/js/admin-ui-components.js +408 -0
- package/public/js/llm-provider-model-picker.js +193 -0
- package/public/test-iframe-fix.html +63 -0
- package/public/test-iframe.html +14 -0
- package/src/admin/endpointRegistry.js +68 -0
- package/src/controllers/admin.controller.js +36 -10
- package/src/controllers/adminAgents.controller.js +37 -0
- package/src/controllers/adminDataCleanup.controller.js +45 -0
- package/src/controllers/adminLlm.controller.js +19 -8
- package/src/controllers/adminLogin.controller.js +269 -0
- package/src/controllers/adminMarkdowns.controller.js +157 -0
- package/src/controllers/adminPlugins.controller.js +55 -0
- package/src/controllers/adminRegistry.controller.js +106 -0
- package/src/controllers/adminScripts.controller.js +138 -0
- package/src/controllers/adminStats.controller.js +4 -4
- package/src/controllers/adminTelegram.controller.js +72 -0
- package/src/controllers/markdowns.controller.js +42 -0
- package/src/controllers/registry.controller.js +32 -0
- package/src/controllers/waitingList.controller.js +52 -74
- package/src/helpers/mongooseHelper.js +6 -6
- package/src/helpers/scriptBase.js +2 -2
- package/src/middleware/auth.js +71 -1
- package/src/middleware/rbac.js +62 -0
- package/src/middleware.js +584 -176
- package/src/models/Agent.js +105 -0
- package/src/models/AgentMessage.js +82 -0
- package/src/models/GlobalSetting.js +11 -1
- package/src/models/Markdown.js +75 -0
- package/src/models/ScriptRun.js +8 -0
- package/src/models/TelegramBot.js +42 -0
- package/src/models/UiComponent.js +2 -0
- package/src/models/User.js +1 -1
- package/src/routes/admin.routes.js +3 -3
- package/src/routes/adminAgents.routes.js +13 -0
- package/src/routes/adminAssets.routes.js +11 -11
- package/src/routes/adminBlog.routes.js +2 -2
- package/src/routes/adminBlogAi.routes.js +2 -2
- package/src/routes/adminBlogAutomation.routes.js +2 -2
- package/src/routes/adminCache.routes.js +2 -2
- package/src/routes/adminConsoleManager.routes.js +2 -2
- package/src/routes/adminCrons.routes.js +2 -2
- package/src/routes/adminDataCleanup.routes.js +26 -0
- package/src/routes/adminDbBrowser.routes.js +2 -2
- package/src/routes/adminEjsVirtual.routes.js +2 -2
- package/src/routes/adminFeatureFlags.routes.js +6 -6
- package/src/routes/adminHeadless.routes.js +2 -2
- package/src/routes/adminHealthChecks.routes.js +2 -2
- package/src/routes/adminI18n.routes.js +2 -2
- package/src/routes/adminJsonConfigs.routes.js +8 -8
- package/src/routes/adminLlm.routes.js +8 -7
- package/src/routes/adminLogin.routes.js +23 -0
- package/src/routes/adminMarkdowns.routes.js +10 -0
- package/src/routes/adminMigration.routes.js +12 -12
- package/src/routes/adminPages.routes.js +2 -2
- package/src/routes/adminPlugins.routes.js +15 -0
- package/src/routes/adminProxy.routes.js +2 -2
- package/src/routes/adminRateLimits.routes.js +8 -8
- package/src/routes/adminRbac.routes.js +2 -2
- package/src/routes/adminRegistry.routes.js +24 -0
- package/src/routes/adminScripts.routes.js +6 -3
- package/src/routes/adminSeoConfig.routes.js +10 -10
- package/src/routes/adminTelegram.routes.js +14 -0
- package/src/routes/adminTerminals.routes.js +2 -2
- package/src/routes/adminUiComponents.routes.js +2 -2
- package/src/routes/adminUploadNamespaces.routes.js +7 -7
- package/src/routes/blogInternal.routes.js +2 -2
- package/src/routes/experiments.routes.js +2 -2
- package/src/routes/formsAdmin.routes.js +6 -6
- package/src/routes/globalSettings.routes.js +8 -8
- package/src/routes/internalExperiments.routes.js +2 -2
- package/src/routes/markdowns.routes.js +16 -0
- package/src/routes/notificationAdmin.routes.js +7 -7
- package/src/routes/orgAdmin.routes.js +16 -16
- package/src/routes/pages.routes.js +3 -3
- package/src/routes/registry.routes.js +11 -0
- package/src/routes/stripeAdmin.routes.js +12 -12
- package/src/routes/userAdmin.routes.js +7 -7
- package/src/routes/waitingListAdmin.routes.js +2 -2
- package/src/routes/workflows.routes.js +3 -3
- package/src/services/agent.service.js +546 -0
- package/src/services/agentHistory.service.js +345 -0
- package/src/services/agentTools.service.js +578 -0
- package/src/services/dataCleanup.service.js +286 -0
- package/src/services/jsonConfigs.service.js +284 -10
- package/src/services/llm.service.js +219 -6
- package/src/services/markdowns.service.js +522 -0
- package/src/services/plugins.service.js +348 -0
- package/src/services/registry.service.js +452 -0
- package/src/services/scriptsRunner.service.js +328 -37
- package/src/services/telegram.service.js +130 -0
- package/src/services/uiComponents.service.js +180 -0
- package/src/services/waitingListJson.service.js +401 -0
- package/src/utils/rbac/rightsRegistry.js +118 -0
- package/test-access.js +63 -0
- package/test-iframe-fix.html +63 -0
- package/test-iframe.html +14 -0
- package/views/admin-403.ejs +92 -0
- package/views/admin-agents.ejs +273 -0
- package/views/admin-coolify-deploy.ejs +8 -8
- package/views/admin-dashboard-home.ejs +52 -2
- package/views/admin-dashboard.ejs +179 -7
- package/views/admin-data-cleanup.ejs +357 -0
- package/views/admin-experiments.ejs +1 -1
- package/views/admin-login.ejs +286 -0
- package/views/admin-markdowns.ejs +905 -0
- package/views/admin-plugins-system.ejs +223 -0
- package/views/admin-scripts.ejs +221 -4
- package/views/admin-telegram.ejs +269 -0
- package/views/admin-ui-components.ejs +82 -402
- package/views/admin-users.ejs +207 -11
- package/views/partials/dashboard/nav-items.ejs +5 -0
- package/views/partials/llm-provider-model-picker.ejs +0 -161
- package/analysis-only.skill +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const waitingListService = require('../services/waitingListJson.service');
|
|
2
2
|
const { validateEmail, sanitizeString } = require('../utils/validation');
|
|
3
3
|
|
|
4
4
|
// Subscribe to waiting list
|
|
@@ -31,36 +31,51 @@ exports.subscribe = async (req, res) => {
|
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// Check if email already exists
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
// Check if email already exists and create new entry using JSON Configs service
|
|
35
|
+
try {
|
|
36
|
+
const waitingListEntry = await waitingListService.addWaitingListEntry({
|
|
37
|
+
email: sanitizedEmail.toLowerCase(),
|
|
38
|
+
type: sanitizedType.trim(),
|
|
39
|
+
referralSource: sanitizeString(referralSource) || 'website'
|
|
40
40
|
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Create new waiting list entry
|
|
44
|
-
const waitingListEntry = new WaitingList({
|
|
45
|
-
email: sanitizedEmail.toLowerCase(),
|
|
46
|
-
type: sanitizedType.trim(),
|
|
47
|
-
referralSource: sanitizeString(referralSource) || 'website'
|
|
48
|
-
});
|
|
49
41
|
|
|
50
|
-
|
|
42
|
+
// Return success response without sensitive data
|
|
43
|
+
const response = { ...waitingListEntry };
|
|
44
|
+
delete response.email; // Don't return email in response for privacy
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
46
|
+
res.status(201).json({
|
|
47
|
+
message: 'Successfully joined the waiting list!',
|
|
48
|
+
data: response
|
|
49
|
+
});
|
|
50
|
+
} catch (serviceError) {
|
|
51
|
+
// Handle validation and duplicate errors from service
|
|
52
|
+
if (serviceError.code === 'VALIDATION') {
|
|
53
|
+
return res.status(400).json({
|
|
54
|
+
error: serviceError.message,
|
|
55
|
+
field: 'general'
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (serviceError.code === 'DUPLICATE_EMAIL' || serviceError.code === 'DUPLICATE' || serviceError.message.includes('already exists')) {
|
|
60
|
+
return res.status(409).json({
|
|
61
|
+
error: 'This email is already on our waiting list',
|
|
62
|
+
field: 'email'
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (serviceError.code === 'INITIALIZATION_FAILED') {
|
|
67
|
+
return res.status(500).json({
|
|
68
|
+
error: 'Service temporarily unavailable - please try again',
|
|
69
|
+
field: 'general'
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
throw serviceError; // Re-throw for general error handling
|
|
74
|
+
}
|
|
60
75
|
} catch (error) {
|
|
61
76
|
console.error('Waiting list subscription error:', error);
|
|
62
77
|
|
|
63
|
-
// Handle specific
|
|
78
|
+
// Handle specific errors
|
|
64
79
|
if (error.code === 11000) {
|
|
65
80
|
return res.status(409).json({
|
|
66
81
|
error: 'This email is already on our waiting list',
|
|
@@ -86,35 +101,10 @@ exports.subscribe = async (req, res) => {
|
|
|
86
101
|
// Get waiting list stats (public)
|
|
87
102
|
exports.getStats = async (req, res) => {
|
|
88
103
|
try {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const typeAgg = await WaitingList.aggregate([
|
|
92
|
-
{ $match: { status: 'active' } },
|
|
93
|
-
{ $group: { _id: '$type', count: { $sum: 1 } } },
|
|
94
|
-
{ $sort: { count: -1, _id: 1 } },
|
|
95
|
-
]);
|
|
96
|
-
|
|
97
|
-
const typeCounts = (typeAgg || []).reduce((acc, row) => {
|
|
98
|
-
if (!row?._id) return acc;
|
|
99
|
-
acc[String(row._id)] = row.count || 0;
|
|
100
|
-
return acc;
|
|
101
|
-
}, {});
|
|
102
|
-
|
|
103
|
-
// Backward compatibility fields (legacy UI/tests)
|
|
104
|
-
const buyerCount = (typeCounts.buyer || 0) + (typeCounts.both || 0);
|
|
105
|
-
const sellerCount = (typeCounts.seller || 0) + (typeCounts.both || 0);
|
|
106
|
-
|
|
107
|
-
// Add some mock growth data for demonstration
|
|
108
|
-
const growthThisWeek = Math.floor(totalSubscribers * 0.05); // 5% growth
|
|
104
|
+
// Use JSON Configs service for cached statistics
|
|
105
|
+
const stats = await waitingListService.getWaitingListStats();
|
|
109
106
|
|
|
110
|
-
res.json(
|
|
111
|
-
totalSubscribers,
|
|
112
|
-
buyerCount,
|
|
113
|
-
sellerCount,
|
|
114
|
-
typeCounts,
|
|
115
|
-
growthThisWeek,
|
|
116
|
-
lastUpdated: new Date().toISOString()
|
|
117
|
-
});
|
|
107
|
+
res.json(stats);
|
|
118
108
|
} catch (error) {
|
|
119
109
|
console.error('Waiting list stats error:', error);
|
|
120
110
|
res.status(500).json({
|
|
@@ -135,31 +125,19 @@ exports.adminList = async (req, res) => {
|
|
|
135
125
|
offset = 0,
|
|
136
126
|
} = req.query;
|
|
137
127
|
|
|
138
|
-
const query = {};
|
|
139
|
-
if (status) query.status = String(status);
|
|
140
|
-
if (type) query.type = String(type);
|
|
141
|
-
if (email) query.email = String(email).trim().toLowerCase();
|
|
142
|
-
|
|
143
128
|
const parsedLimit = Math.min(500, Math.max(1, parseInt(limit, 10) || 50));
|
|
144
129
|
const parsedOffset = Math.max(0, parseInt(offset, 10) || 0);
|
|
145
130
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const total = await WaitingList.countDocuments(query);
|
|
154
|
-
|
|
155
|
-
return res.json({
|
|
156
|
-
entries,
|
|
157
|
-
pagination: {
|
|
158
|
-
total,
|
|
159
|
-
limit: parsedLimit,
|
|
160
|
-
offset: parsedOffset,
|
|
161
|
-
},
|
|
131
|
+
// Use JSON Configs service for admin data with filtering and pagination
|
|
132
|
+
const result = await waitingListService.getWaitingListEntriesAdmin({
|
|
133
|
+
status,
|
|
134
|
+
type,
|
|
135
|
+
email,
|
|
136
|
+
limit: parsedLimit,
|
|
137
|
+
offset: parsedOffset
|
|
162
138
|
});
|
|
139
|
+
|
|
140
|
+
return res.json(result);
|
|
163
141
|
} catch (error) {
|
|
164
142
|
console.error('Waiting list admin list error:', error);
|
|
165
143
|
return res.status(500).json({ error: 'Failed to list entries' });
|
|
@@ -83,7 +83,7 @@ class MongooseHelper {
|
|
|
83
83
|
const uri = this.getMongoUri();
|
|
84
84
|
const options = this.getConnectionOptions();
|
|
85
85
|
|
|
86
|
-
console.log(`[MongooseHelper] Connecting to MongoDB...`);
|
|
86
|
+
if (!process.env.TUI_MODE) console.log(`[MongooseHelper] Connecting to MongoDB...`);
|
|
87
87
|
|
|
88
88
|
// Clear any existing connection
|
|
89
89
|
if (mongoose.connection.readyState !== 0) {
|
|
@@ -94,7 +94,7 @@ class MongooseHelper {
|
|
|
94
94
|
|
|
95
95
|
this.isConnected = true;
|
|
96
96
|
|
|
97
|
-
console.log(`[MongooseHelper] ✅ Connected to MongoDB`);
|
|
97
|
+
if (!process.env.TUI_MODE) console.log(`[MongooseHelper] ✅ Connected to MongoDB`);
|
|
98
98
|
|
|
99
99
|
// Setup connection error handling
|
|
100
100
|
mongoose.connection.on('error', (error) => {
|
|
@@ -104,13 +104,13 @@ class MongooseHelper {
|
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
mongoose.connection.on('disconnected', () => {
|
|
107
|
-
console.log('[MongooseHelper] Disconnected from MongoDB');
|
|
107
|
+
if (!process.env.TUI_MODE) console.log('[MongooseHelper] Disconnected from MongoDB');
|
|
108
108
|
this.isConnected = false;
|
|
109
109
|
this.connectionPromise = null;
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
mongoose.connection.on('reconnected', () => {
|
|
113
|
-
console.log('[MongooseHelper] Reconnected to MongoDB');
|
|
113
|
+
if (!process.env.TUI_MODE) console.log('[MongooseHelper] Reconnected to MongoDB');
|
|
114
114
|
this.isConnected = true;
|
|
115
115
|
});
|
|
116
116
|
|
|
@@ -136,7 +136,7 @@ class MongooseHelper {
|
|
|
136
136
|
if (this.connectionCount <= 0) {
|
|
137
137
|
try {
|
|
138
138
|
await mongoose.disconnect();
|
|
139
|
-
console.log('[MongooseHelper] ✅ Disconnected from MongoDB');
|
|
139
|
+
if (!process.env.TUI_MODE) console.log('[MongooseHelper] ✅ Disconnected from MongoDB');
|
|
140
140
|
} catch (error) {
|
|
141
141
|
console.error('[MongooseHelper] Disconnect error:', error);
|
|
142
142
|
} finally {
|
|
@@ -155,7 +155,7 @@ class MongooseHelper {
|
|
|
155
155
|
try {
|
|
156
156
|
if (mongoose.connection.readyState !== 0) {
|
|
157
157
|
await mongoose.disconnect();
|
|
158
|
-
console.log('[MongooseHelper] ✅ Force disconnected from MongoDB');
|
|
158
|
+
if (!process.env.TUI_MODE) console.log('[MongooseHelper] ✅ Force disconnected from MongoDB');
|
|
159
159
|
}
|
|
160
160
|
} catch (error) {
|
|
161
161
|
console.error('[MongooseHelper] Force disconnect error:', error);
|
|
@@ -55,13 +55,13 @@ class ScriptBase {
|
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
|
-
console.log(`[${this.name}] Starting script execution...`);
|
|
58
|
+
if (!process.env.TUI_MODE) console.log(`[${this.name}] Starting script execution...`);
|
|
59
59
|
|
|
60
60
|
const executionPromise = this._executeWithConnection();
|
|
61
61
|
const result = await Promise.race([executionPromise, timeoutPromise]);
|
|
62
62
|
|
|
63
63
|
const duration = Date.now() - this.startTime;
|
|
64
|
-
console.log(`[${this.name}] ✅ Completed in ${duration}ms`);
|
|
64
|
+
if (!process.env.TUI_MODE) console.log(`[${this.name}] ✅ Completed in ${duration}ms`);
|
|
65
65
|
|
|
66
66
|
return result;
|
|
67
67
|
} catch (error) {
|
package/src/middleware/auth.js
CHANGED
|
@@ -70,4 +70,74 @@ const requireAdmin = (req, res, next) => {
|
|
|
70
70
|
next();
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
// Admin session authentication middleware - checks session for authenticated admin user
|
|
74
|
+
const adminSessionAuth = (req, res, next) => {
|
|
75
|
+
// Check if session exists and user is authenticated
|
|
76
|
+
if (!req.session || !req.session.authenticated) {
|
|
77
|
+
// Store the originally requested URL for redirect after login
|
|
78
|
+
req.session = req.session || {};
|
|
79
|
+
req.session.returnTo = req.originalUrl;
|
|
80
|
+
|
|
81
|
+
// For API routes, return JSON error
|
|
82
|
+
if (req.xhr || req.headers.accept?.includes('application/json')) {
|
|
83
|
+
return res.status(401).json({
|
|
84
|
+
error: "Authentication required",
|
|
85
|
+
redirectTo: `${req.adminPath || '/admin'}/login`
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// For web routes, redirect to login page
|
|
90
|
+
return res.redirect(`${req.adminPath || '/admin'}/login`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Verify session is still valid (check login time)
|
|
94
|
+
const loginTime = new Date(req.session.loginTime);
|
|
95
|
+
const now = new Date();
|
|
96
|
+
const sessionAge = (now - loginTime) / (1000 * 60 * 60); // hours
|
|
97
|
+
|
|
98
|
+
// Session expires after 24 hours
|
|
99
|
+
if (sessionAge > 24) {
|
|
100
|
+
req.session.destroy((err) => {
|
|
101
|
+
if (err) console.error('Error destroying expired session:', err);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (req.xhr || req.headers.accept?.includes('application/json')) {
|
|
105
|
+
return res.status(401).json({
|
|
106
|
+
error: "Session expired",
|
|
107
|
+
redirectTo: `${req.adminPath || '/admin'}/login`
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return res.redirect(`${req.adminPath || '/admin'}/login?error=Session expired`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Attach user info to request for consistency with other auth middleware
|
|
115
|
+
req.user = {
|
|
116
|
+
authenticated: true,
|
|
117
|
+
authType: req.session.authType,
|
|
118
|
+
role: req.session.role
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
if (req.session.authType === 'iam') {
|
|
122
|
+
req.user.id = req.session.userId;
|
|
123
|
+
req.user.email = req.session.email;
|
|
124
|
+
req.user.name = req.session.name;
|
|
125
|
+
} else {
|
|
126
|
+
req.user.username = req.session.username;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
next();
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Admin authentication middleware that supports both session and basic auth
|
|
133
|
+
const adminAuth = (req, res, next) => {
|
|
134
|
+
// First try session authentication
|
|
135
|
+
if (req.session && req.session.authenticated) {
|
|
136
|
+
return adminSessionAuth(req, res, next);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Fallback to basic auth for backward compatibility
|
|
140
|
+
return basicAuth(req, res, next);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
module.exports = { authenticate, basicAuth, requireAdmin, adminSessionAuth, adminAuth };
|
package/src/middleware/rbac.js
CHANGED
|
@@ -56,7 +56,69 @@ function requireRight(requiredRight, options = {}) {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Middleware for module-level access control in admin panel
|
|
61
|
+
* Checks specific permissions for admin modules like audit, users, etc.
|
|
62
|
+
*/
|
|
63
|
+
function requireModuleAccess(moduleId, action = 'read') {
|
|
64
|
+
return async (req, res, next) => {
|
|
65
|
+
try {
|
|
66
|
+
// Check for basic auth superadmin bypass
|
|
67
|
+
if (isBasicAuthSuperAdmin(req)) {
|
|
68
|
+
return next();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Get user ID from session
|
|
72
|
+
const userId = req.session?.authData?.userId;
|
|
73
|
+
if (!userId) {
|
|
74
|
+
return res.redirect(`${req.adminPath || '/admin'}/login`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check RBAC permission for specific module
|
|
78
|
+
const hasAccess = await rbacService.checkRight({
|
|
79
|
+
userId,
|
|
80
|
+
orgId: null, // Global admin permissions
|
|
81
|
+
right: `admin_panel__${moduleId}:${action}`
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (!hasAccess.allowed) {
|
|
85
|
+
// For API routes, return JSON error
|
|
86
|
+
if (req.path.startsWith('/api/')) {
|
|
87
|
+
return res.status(403).json({
|
|
88
|
+
error: 'Access denied',
|
|
89
|
+
reason: hasAccess.reason,
|
|
90
|
+
required: `admin_panel__${moduleId}:${action}`,
|
|
91
|
+
moduleId,
|
|
92
|
+
action
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// For page routes, render 403 page
|
|
97
|
+
return res.status(403).render('admin-403', {
|
|
98
|
+
moduleId,
|
|
99
|
+
action,
|
|
100
|
+
required: `admin_panel__${moduleId}:${action}`,
|
|
101
|
+
reason: hasAccess.reason,
|
|
102
|
+
user: req.session.authData,
|
|
103
|
+
adminPath: req.adminPath || '/admin'
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
next();
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('Module access check error:', error);
|
|
110
|
+
|
|
111
|
+
if (req.path.startsWith('/api/')) {
|
|
112
|
+
return res.status(500).json({ error: 'Access check failed' });
|
|
113
|
+
} else {
|
|
114
|
+
return res.status(500).send('Access check failed');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
59
120
|
module.exports = {
|
|
60
121
|
requireRight,
|
|
122
|
+
requireModuleAccess,
|
|
61
123
|
isBasicAuthSuperAdmin,
|
|
62
124
|
};
|