create-forgeon 0.3.20 → 0.3.21
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/package.json +1 -1
- package/src/modules/executor.test.mjs +550 -550
- package/src/modules/files-access.mjs +375 -375
- package/src/modules/files-image.mjs +512 -512
- package/src/modules/files-quotas.mjs +365 -365
- package/src/run-add-module.test.mjs +228 -228
- package/templates/module-presets/files-quotas/packages/files-quotas/package.json +20 -20
- package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas.service.ts +118 -118
- package/templates/module-presets/files-quotas/packages/files-quotas/src/forgeon-files-quotas.module.ts +18 -18
package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas.service.ts
CHANGED
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
import { ConflictException, Injectable } from '@nestjs/common';
|
|
2
|
-
import { FilesService } from '@forgeon/files';
|
|
3
|
-
import { FilesQuotasConfigService } from './files-quotas-config.service';
|
|
4
|
-
import type { FilesQuotaCheckInput, FilesQuotaCheckResult } from './files-quotas.types';
|
|
5
|
-
|
|
6
|
-
@Injectable()
|
|
7
|
-
export class FilesQuotasService {
|
|
8
|
-
constructor(
|
|
9
|
-
private readonly filesService: FilesService,
|
|
10
|
-
private readonly configService: FilesQuotasConfigService,
|
|
11
|
-
) {}
|
|
12
|
-
|
|
13
|
-
get enabled(): boolean {
|
|
14
|
-
return this.configService.enabled;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
get limits() {
|
|
18
|
-
return {
|
|
19
|
-
maxFilesPerOwner: this.configService.maxFilesPerOwner,
|
|
20
|
-
maxBytesPerOwner: this.configService.maxBytesPerOwner,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async evaluateUpload(input: FilesQuotaCheckInput): Promise<FilesQuotaCheckResult> {
|
|
25
|
-
const limits = this.limits;
|
|
26
|
-
const emptyUsage = {
|
|
27
|
-
filesCount: 0,
|
|
28
|
-
totalBytes: 0,
|
|
29
|
-
};
|
|
30
|
-
const baseResult = {
|
|
31
|
-
limits,
|
|
32
|
-
current: emptyUsage,
|
|
33
|
-
next: {
|
|
34
|
-
filesCount: emptyUsage.filesCount + 1,
|
|
35
|
-
totalBytes: emptyUsage.totalBytes + input.fileSize,
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
if (!this.enabled) {
|
|
40
|
-
return {
|
|
41
|
-
allowed: true,
|
|
42
|
-
reason: 'disabled',
|
|
43
|
-
...baseResult,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (!input.ownerId) {
|
|
48
|
-
return {
|
|
49
|
-
allowed: true,
|
|
50
|
-
reason: 'owner-missing',
|
|
51
|
-
...baseResult,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const usage = await this.filesService.getOwnerUsage(input.ownerType, input.ownerId);
|
|
56
|
-
const next = {
|
|
57
|
-
filesCount: usage.filesCount + 1,
|
|
58
|
-
totalBytes: usage.totalBytes + input.fileSize,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
if (next.filesCount > limits.maxFilesPerOwner) {
|
|
62
|
-
return {
|
|
63
|
-
allowed: false,
|
|
64
|
-
reason: 'max-files',
|
|
65
|
-
limits,
|
|
66
|
-
current: usage,
|
|
67
|
-
next,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
if (next.totalBytes > limits.maxBytesPerOwner) {
|
|
71
|
-
return {
|
|
72
|
-
allowed: false,
|
|
73
|
-
reason: 'max-bytes',
|
|
74
|
-
limits,
|
|
75
|
-
current: usage,
|
|
76
|
-
next,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
allowed: true,
|
|
82
|
-
reason: 'ok',
|
|
83
|
-
limits,
|
|
84
|
-
current: usage,
|
|
85
|
-
next,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async assertUploadAllowed(input: FilesQuotaCheckInput): Promise<void> {
|
|
90
|
-
const result = await this.evaluateUpload(input);
|
|
91
|
-
if (result.allowed) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
throw new ConflictException({
|
|
96
|
-
message: 'File quota exceeded for owner',
|
|
97
|
-
details: {
|
|
98
|
-
reason: result.reason,
|
|
99
|
-
limits: result.limits,
|
|
100
|
-
current: result.current,
|
|
101
|
-
next: result.next,
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async getProbeStatus(input: FilesQuotaCheckInput): Promise<{
|
|
107
|
-
status: 'ok';
|
|
108
|
-
feature: 'files-quotas';
|
|
109
|
-
result: FilesQuotaCheckResult;
|
|
110
|
-
}> {
|
|
111
|
-
const result = await this.evaluateUpload(input);
|
|
112
|
-
return {
|
|
113
|
-
status: 'ok',
|
|
114
|
-
feature: 'files-quotas',
|
|
115
|
-
result,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
1
|
+
import { ConflictException, Injectable } from '@nestjs/common';
|
|
2
|
+
import { FilesService } from '@forgeon/files';
|
|
3
|
+
import { FilesQuotasConfigService } from './files-quotas-config.service';
|
|
4
|
+
import type { FilesQuotaCheckInput, FilesQuotaCheckResult } from './files-quotas.types';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class FilesQuotasService {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly filesService: FilesService,
|
|
10
|
+
private readonly configService: FilesQuotasConfigService,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
get enabled(): boolean {
|
|
14
|
+
return this.configService.enabled;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get limits() {
|
|
18
|
+
return {
|
|
19
|
+
maxFilesPerOwner: this.configService.maxFilesPerOwner,
|
|
20
|
+
maxBytesPerOwner: this.configService.maxBytesPerOwner,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async evaluateUpload(input: FilesQuotaCheckInput): Promise<FilesQuotaCheckResult> {
|
|
25
|
+
const limits = this.limits;
|
|
26
|
+
const emptyUsage = {
|
|
27
|
+
filesCount: 0,
|
|
28
|
+
totalBytes: 0,
|
|
29
|
+
};
|
|
30
|
+
const baseResult = {
|
|
31
|
+
limits,
|
|
32
|
+
current: emptyUsage,
|
|
33
|
+
next: {
|
|
34
|
+
filesCount: emptyUsage.filesCount + 1,
|
|
35
|
+
totalBytes: emptyUsage.totalBytes + input.fileSize,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
if (!this.enabled) {
|
|
40
|
+
return {
|
|
41
|
+
allowed: true,
|
|
42
|
+
reason: 'disabled',
|
|
43
|
+
...baseResult,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!input.ownerId) {
|
|
48
|
+
return {
|
|
49
|
+
allowed: true,
|
|
50
|
+
reason: 'owner-missing',
|
|
51
|
+
...baseResult,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const usage = await this.filesService.getOwnerUsage(input.ownerType, input.ownerId);
|
|
56
|
+
const next = {
|
|
57
|
+
filesCount: usage.filesCount + 1,
|
|
58
|
+
totalBytes: usage.totalBytes + input.fileSize,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (next.filesCount > limits.maxFilesPerOwner) {
|
|
62
|
+
return {
|
|
63
|
+
allowed: false,
|
|
64
|
+
reason: 'max-files',
|
|
65
|
+
limits,
|
|
66
|
+
current: usage,
|
|
67
|
+
next,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (next.totalBytes > limits.maxBytesPerOwner) {
|
|
71
|
+
return {
|
|
72
|
+
allowed: false,
|
|
73
|
+
reason: 'max-bytes',
|
|
74
|
+
limits,
|
|
75
|
+
current: usage,
|
|
76
|
+
next,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
allowed: true,
|
|
82
|
+
reason: 'ok',
|
|
83
|
+
limits,
|
|
84
|
+
current: usage,
|
|
85
|
+
next,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async assertUploadAllowed(input: FilesQuotaCheckInput): Promise<void> {
|
|
90
|
+
const result = await this.evaluateUpload(input);
|
|
91
|
+
if (result.allowed) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
throw new ConflictException({
|
|
96
|
+
message: 'File quota exceeded for owner',
|
|
97
|
+
details: {
|
|
98
|
+
reason: result.reason,
|
|
99
|
+
limits: result.limits,
|
|
100
|
+
current: result.current,
|
|
101
|
+
next: result.next,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async getProbeStatus(input: FilesQuotaCheckInput): Promise<{
|
|
107
|
+
status: 'ok';
|
|
108
|
+
feature: 'files-quotas';
|
|
109
|
+
result: FilesQuotaCheckResult;
|
|
110
|
+
}> {
|
|
111
|
+
const result = await this.evaluateUpload(input);
|
|
112
|
+
return {
|
|
113
|
+
status: 'ok',
|
|
114
|
+
feature: 'files-quotas',
|
|
115
|
+
result,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
import { ForgeonFilesModule } from '@forgeon/files';
|
|
3
|
-
import { FilesQuotasConfigModule } from './files-quotas-config.module';
|
|
4
|
-
import { FilesQuotasService } from './files-quotas.service';
|
|
5
|
-
|
|
6
|
-
const FORGEON_FILES_UPLOAD_QUOTA_SERVICE = 'FORGEON_FILES_UPLOAD_QUOTA_SERVICE';
|
|
7
|
-
|
|
8
|
-
@Module({
|
|
9
|
-
imports: [ForgeonFilesModule, FilesQuotasConfigModule],
|
|
10
|
-
providers: [
|
|
11
|
-
FilesQuotasService,
|
|
12
|
-
{
|
|
13
|
-
provide: FORGEON_FILES_UPLOAD_QUOTA_SERVICE,
|
|
14
|
-
useExisting: FilesQuotasService,
|
|
15
|
-
},
|
|
16
|
-
],
|
|
17
|
-
exports: [FilesQuotasConfigModule, FilesQuotasService, FORGEON_FILES_UPLOAD_QUOTA_SERVICE],
|
|
18
|
-
})
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { ForgeonFilesModule } from '@forgeon/files';
|
|
3
|
+
import { FilesQuotasConfigModule } from './files-quotas-config.module';
|
|
4
|
+
import { FilesQuotasService } from './files-quotas.service';
|
|
5
|
+
|
|
6
|
+
const FORGEON_FILES_UPLOAD_QUOTA_SERVICE = 'FORGEON_FILES_UPLOAD_QUOTA_SERVICE';
|
|
7
|
+
|
|
8
|
+
@Module({
|
|
9
|
+
imports: [ForgeonFilesModule, FilesQuotasConfigModule],
|
|
10
|
+
providers: [
|
|
11
|
+
FilesQuotasService,
|
|
12
|
+
{
|
|
13
|
+
provide: FORGEON_FILES_UPLOAD_QUOTA_SERVICE,
|
|
14
|
+
useExisting: FilesQuotasService,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
exports: [FilesQuotasConfigModule, FilesQuotasService, FORGEON_FILES_UPLOAD_QUOTA_SERVICE],
|
|
18
|
+
})
|
|
19
19
|
export class ForgeonFilesQuotasModule {}
|