@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
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
const mongoose = require('mongoose');
|
|
2
|
+
|
|
3
|
+
const Asset = require('../models/Asset');
|
|
4
|
+
const FileEntry = require('../models/FileEntry');
|
|
5
|
+
const RbacGroup = require('../models/RbacGroup');
|
|
6
|
+
const RbacGroupMember = require('../models/RbacGroupMember');
|
|
7
|
+
|
|
8
|
+
const globalSettingsService = require('./globalSettings.service');
|
|
9
|
+
|
|
10
|
+
const SETTING_POLICY_JSON = 'FILE_MANAGER_STORAGE_POLICY_JSON';
|
|
11
|
+
const SETTING_LEGACY_MAX_UPLOAD = 'FILE_MANAGER_MAX_UPLOAD_BYTES';
|
|
12
|
+
|
|
13
|
+
const DEFAULT_MAX_UPLOAD_BYTES = 1073741824;
|
|
14
|
+
const DEFAULT_MAX_STORAGE_BYTES = 104857600;
|
|
15
|
+
|
|
16
|
+
function normalizeObjectId(id, name) {
|
|
17
|
+
const str = String(id || '');
|
|
18
|
+
if (!mongoose.Types.ObjectId.isValid(str)) {
|
|
19
|
+
const err = new Error(`${name} must be a valid ObjectId`);
|
|
20
|
+
err.code = 'VALIDATION';
|
|
21
|
+
throw err;
|
|
22
|
+
}
|
|
23
|
+
return new mongoose.Types.ObjectId(str);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeDriveType(value) {
|
|
27
|
+
const t = String(value || '').trim();
|
|
28
|
+
if (t === 'user' || t === 'group' || t === 'org') return t;
|
|
29
|
+
const err = new Error('driveType must be one of: user, group, org');
|
|
30
|
+
err.code = 'VALIDATION';
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function toPositiveIntOrNull(value) {
|
|
35
|
+
const n = Number(value);
|
|
36
|
+
if (!Number.isFinite(n) || n <= 0) return null;
|
|
37
|
+
return Math.floor(n);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function loadPolicy() {
|
|
41
|
+
const raw = await globalSettingsService.getSettingValue(SETTING_POLICY_JSON, null);
|
|
42
|
+
if (!raw) return { version: 1, global: {}, orgs: {} };
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
46
|
+
if (!parsed || typeof parsed !== 'object') return { version: 1, global: {}, orgs: {} };
|
|
47
|
+
|
|
48
|
+
const version = toPositiveIntOrNull(parsed.version) || 1;
|
|
49
|
+
const global = parsed.global && typeof parsed.global === 'object' ? parsed.global : {};
|
|
50
|
+
const orgs = parsed.orgs && typeof parsed.orgs === 'object' ? parsed.orgs : {};
|
|
51
|
+
|
|
52
|
+
return { version, global, orgs };
|
|
53
|
+
} catch {
|
|
54
|
+
return { version: 1, global: {}, orgs: {} };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getEnvDefaultMaxUploadBytes() {
|
|
59
|
+
const fromEnv = toPositiveIntOrNull(process.env.FILE_MANAGER_DEFAULT_MAX_UPLOAD_BYTES);
|
|
60
|
+
return fromEnv || DEFAULT_MAX_UPLOAD_BYTES;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function getDefaultMaxUploadBytes() {
|
|
64
|
+
const legacy = await globalSettingsService.getSettingValue(SETTING_LEGACY_MAX_UPLOAD, null);
|
|
65
|
+
const legacyParsed = toPositiveIntOrNull(legacy);
|
|
66
|
+
return legacyParsed || getEnvDefaultMaxUploadBytes();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getDefaultMaxStorageBytes() {
|
|
70
|
+
const fromEnv = toPositiveIntOrNull(process.env.FILE_MANAGER_DEFAULT_MAX_STORAGE_BYTES);
|
|
71
|
+
return fromEnv || DEFAULT_MAX_STORAGE_BYTES;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function getUserOrgGroupIds({ userId, orgId }) {
|
|
75
|
+
const uid = normalizeObjectId(userId, 'userId');
|
|
76
|
+
const oid = normalizeObjectId(orgId, 'orgId');
|
|
77
|
+
|
|
78
|
+
const links = await RbacGroupMember.find({ userId: uid }).select('groupId').lean();
|
|
79
|
+
const groupIds = links.map((l) => l.groupId).filter(Boolean);
|
|
80
|
+
if (!groupIds.length) return [];
|
|
81
|
+
|
|
82
|
+
const groups = await RbacGroup.find({ _id: { $in: groupIds }, orgId: oid, status: 'active', isGlobal: false })
|
|
83
|
+
.select('_id')
|
|
84
|
+
.lean();
|
|
85
|
+
|
|
86
|
+
return groups.map((g) => String(g._id));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function pickMax(values) {
|
|
90
|
+
let best = null;
|
|
91
|
+
for (const v of values) {
|
|
92
|
+
const n = toPositiveIntOrNull(v);
|
|
93
|
+
if (n === null) continue;
|
|
94
|
+
if (best === null || n > best) best = n;
|
|
95
|
+
}
|
|
96
|
+
return best;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getOrgConfig(policy, orgId) {
|
|
100
|
+
const orgs = policy?.orgs || {};
|
|
101
|
+
const orgConfig = orgs[String(orgId)] || null;
|
|
102
|
+
return orgConfig && typeof orgConfig === 'object' ? orgConfig : null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function getGroupConfig(orgConfig, groupId) {
|
|
106
|
+
const groups = orgConfig?.groups || {};
|
|
107
|
+
const g = groups[String(groupId)] || null;
|
|
108
|
+
return g && typeof g === 'object' ? g : null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function getUserConfig(orgConfig, userId) {
|
|
112
|
+
const users = orgConfig?.users || {};
|
|
113
|
+
const u = users[String(userId)] || null;
|
|
114
|
+
return u && typeof u === 'object' ? u : null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function resolveEffectiveLimits({ userId, orgId, driveType, driveId }) {
|
|
118
|
+
const dt = normalizeDriveType(driveType);
|
|
119
|
+
const oid = normalizeObjectId(orgId, 'orgId');
|
|
120
|
+
const did = normalizeObjectId(driveId, 'driveId');
|
|
121
|
+
|
|
122
|
+
const policy = await loadPolicy();
|
|
123
|
+
const orgConfig = getOrgConfig(policy, String(oid));
|
|
124
|
+
|
|
125
|
+
const source = { maxUpload: 'default', maxStorage: 'default' };
|
|
126
|
+
|
|
127
|
+
const defaultMaxUpload = await getDefaultMaxUploadBytes();
|
|
128
|
+
const defaultMaxStorage = getDefaultMaxStorageBytes();
|
|
129
|
+
|
|
130
|
+
const globalMaxUpload = toPositiveIntOrNull(policy?.global?.maxUploadBytes);
|
|
131
|
+
const globalMaxStorage = toPositiveIntOrNull(policy?.global?.maxStorageBytes);
|
|
132
|
+
|
|
133
|
+
let maxUploadBytes = null;
|
|
134
|
+
let maxStorageBytes = null;
|
|
135
|
+
|
|
136
|
+
const orgMaxUpload = toPositiveIntOrNull(orgConfig?.maxUploadBytes);
|
|
137
|
+
const orgMaxStorage = toPositiveIntOrNull(orgConfig?.maxStorageBytes);
|
|
138
|
+
|
|
139
|
+
if (dt === 'org') {
|
|
140
|
+
maxUploadBytes = orgMaxUpload;
|
|
141
|
+
if (maxUploadBytes !== null) source.maxUpload = 'org';
|
|
142
|
+
|
|
143
|
+
maxStorageBytes = orgMaxStorage;
|
|
144
|
+
if (maxStorageBytes !== null) source.maxStorage = 'org';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (dt === 'group') {
|
|
148
|
+
const groupConfig = getGroupConfig(orgConfig, String(did));
|
|
149
|
+
const groupMaxUpload = toPositiveIntOrNull(groupConfig?.maxUploadBytes);
|
|
150
|
+
const groupMaxStorage = toPositiveIntOrNull(groupConfig?.maxStorageBytes);
|
|
151
|
+
|
|
152
|
+
maxUploadBytes = groupMaxUpload;
|
|
153
|
+
if (maxUploadBytes !== null) source.maxUpload = 'group';
|
|
154
|
+
|
|
155
|
+
maxStorageBytes = groupMaxStorage;
|
|
156
|
+
if (maxStorageBytes !== null) source.maxStorage = 'group';
|
|
157
|
+
|
|
158
|
+
if (maxUploadBytes === null) {
|
|
159
|
+
maxUploadBytes = orgMaxUpload;
|
|
160
|
+
if (maxUploadBytes !== null) source.maxUpload = 'org';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (maxStorageBytes === null) {
|
|
164
|
+
maxStorageBytes = orgMaxStorage;
|
|
165
|
+
if (maxStorageBytes !== null) source.maxStorage = 'org';
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (dt === 'user') {
|
|
170
|
+
const userConfig = getUserConfig(orgConfig, String(did));
|
|
171
|
+
const userMaxUpload = toPositiveIntOrNull(userConfig?.maxUploadBytes);
|
|
172
|
+
const userMaxStorage = toPositiveIntOrNull(userConfig?.maxStorageBytes);
|
|
173
|
+
|
|
174
|
+
maxUploadBytes = userMaxUpload;
|
|
175
|
+
if (maxUploadBytes !== null) source.maxUpload = 'user';
|
|
176
|
+
|
|
177
|
+
maxStorageBytes = userMaxStorage;
|
|
178
|
+
if (maxStorageBytes !== null) source.maxStorage = 'user';
|
|
179
|
+
|
|
180
|
+
const groupIds = await getUserOrgGroupIds({ userId, orgId: oid });
|
|
181
|
+
if (groupIds.length) {
|
|
182
|
+
const groupUploads = groupIds.map((gid) => getGroupConfig(orgConfig, gid)?.maxUploadBytes);
|
|
183
|
+
const groupStorages = groupIds.map((gid) => getGroupConfig(orgConfig, gid)?.maxStorageBytes);
|
|
184
|
+
|
|
185
|
+
if (maxUploadBytes === null) {
|
|
186
|
+
maxUploadBytes = pickMax(groupUploads);
|
|
187
|
+
if (maxUploadBytes !== null) source.maxUpload = 'group';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (maxStorageBytes === null) {
|
|
191
|
+
maxStorageBytes = pickMax(groupStorages);
|
|
192
|
+
if (maxStorageBytes !== null) source.maxStorage = 'group';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (maxUploadBytes === null) {
|
|
197
|
+
maxUploadBytes = orgMaxUpload;
|
|
198
|
+
if (maxUploadBytes !== null) source.maxUpload = 'org';
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (maxStorageBytes === null) {
|
|
202
|
+
maxStorageBytes = orgMaxStorage;
|
|
203
|
+
if (maxStorageBytes !== null) source.maxStorage = 'org';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (maxUploadBytes === null && globalMaxUpload !== null) {
|
|
208
|
+
maxUploadBytes = globalMaxUpload;
|
|
209
|
+
source.maxUpload = 'global';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (maxStorageBytes === null && globalMaxStorage !== null) {
|
|
213
|
+
maxStorageBytes = globalMaxStorage;
|
|
214
|
+
source.maxStorage = 'global';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (maxUploadBytes === null) {
|
|
218
|
+
maxUploadBytes = defaultMaxUpload;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (maxStorageBytes === null) {
|
|
222
|
+
maxStorageBytes = defaultMaxStorage;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
maxUploadBytes,
|
|
227
|
+
maxStorageBytes,
|
|
228
|
+
source,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async function computeDriveUsedBytes({ orgId, driveType, driveId }) {
|
|
233
|
+
const oid = normalizeObjectId(orgId, 'orgId');
|
|
234
|
+
const dt = normalizeDriveType(driveType);
|
|
235
|
+
const did = normalizeObjectId(driveId, 'driveId');
|
|
236
|
+
|
|
237
|
+
const rows = await FileEntry.aggregate([
|
|
238
|
+
{
|
|
239
|
+
$match: {
|
|
240
|
+
orgId: oid,
|
|
241
|
+
driveType: dt,
|
|
242
|
+
driveId: did,
|
|
243
|
+
deletedAt: null,
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
$lookup: {
|
|
248
|
+
from: 'assets',
|
|
249
|
+
localField: 'assetId',
|
|
250
|
+
foreignField: '_id',
|
|
251
|
+
as: 'asset',
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
{ $unwind: { path: '$asset', preserveNullAndEmptyArrays: false } },
|
|
255
|
+
{ $match: { 'asset.status': 'uploaded' } },
|
|
256
|
+
{
|
|
257
|
+
$group: {
|
|
258
|
+
_id: null,
|
|
259
|
+
usedBytes: { $sum: '$asset.sizeBytes' },
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
]);
|
|
263
|
+
|
|
264
|
+
const usedBytes = rows?.[0]?.usedBytes;
|
|
265
|
+
return Number.isFinite(usedBytes) ? usedBytes : 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function getEffectivePolicy({ userId, orgId, driveType, driveId }) {
|
|
269
|
+
const effective = await resolveEffectiveLimits({ userId, orgId, driveType, driveId });
|
|
270
|
+
const usedBytes = await computeDriveUsedBytes({ orgId, driveType, driveId });
|
|
271
|
+
const overageBytes = Math.max(0, usedBytes - effective.maxStorageBytes);
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
effective,
|
|
275
|
+
usage: { usedBytes, overageBytes },
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
module.exports = {
|
|
280
|
+
loadPolicy,
|
|
281
|
+
resolveEffectiveLimits,
|
|
282
|
+
computeDriveUsedBytes,
|
|
283
|
+
getEffectivePolicy,
|
|
284
|
+
getUserOrgGroupIds,
|
|
285
|
+
};
|
|
@@ -39,11 +39,26 @@ async function getSettingValue(key, defaultValue = null) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
async function deleteSetting(key) {
|
|
43
|
+
try {
|
|
44
|
+
const setting = await GlobalSetting.findOneAndDelete({ key });
|
|
45
|
+
|
|
46
|
+
// Clear cache for this key
|
|
47
|
+
settingsCache.delete(key);
|
|
48
|
+
|
|
49
|
+
return setting;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(`Error deleting setting ${key}:`, error);
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
42
56
|
function clearSettingsCache() {
|
|
43
57
|
settingsCache.clear();
|
|
44
58
|
}
|
|
45
59
|
|
|
46
60
|
module.exports = {
|
|
47
61
|
getSettingValue,
|
|
62
|
+
deleteSetting,
|
|
48
63
|
clearSettingsCache,
|
|
49
64
|
};
|