Align capacity units and scope administrator network edits
This commit is contained in:
@@ -68,11 +68,31 @@ const fields = {
|
||||
uploadsPaused: z.boolean(),
|
||||
maxConcurrentUploads: z.number().int().min(1).max(16),
|
||||
totalStorageLimitMb: z.number().int().min(1024).max(1048576),
|
||||
accountBytes: z.number().int().min(1).max(1e12),
|
||||
deviceBytes: z.number().int().min(1).max(1e12),
|
||||
devicesTotalBytes: z.number().int().min(1).max(1e12),
|
||||
perFileBytes: z.number().int().min(1).max(1e12),
|
||||
minDiskFreeBytes: z.number().int().min(0).max(1e12),
|
||||
accountBytes: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.max(1024 ** 4),
|
||||
deviceBytes: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.max(1024 ** 4),
|
||||
devicesTotalBytes: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.max(1024 ** 4),
|
||||
perFileBytes: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.max(1024 ** 4),
|
||||
minDiskFreeBytes: z
|
||||
.number()
|
||||
.int()
|
||||
.min(0)
|
||||
.max(1024 ** 4),
|
||||
blockedCountries: z
|
||||
.array(
|
||||
z
|
||||
@@ -101,7 +121,11 @@ const fields = {
|
||||
autoLoginFailures: z.number().int().min(3).max(1000),
|
||||
autoRateViolations: z.number().int().min(3).max(1000),
|
||||
autoUploadRequests: z.number().int().min(3).max(10000),
|
||||
autoUploadBytes: z.number().int().min(1000000).max(1e12),
|
||||
autoUploadBytes: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1000000)
|
||||
.max(1024 ** 4),
|
||||
autoBlockMinutes: z.number().int().min(1).max(10080),
|
||||
};
|
||||
const networkDefaults = {
|
||||
@@ -113,7 +137,7 @@ const networkDefaults = {
|
||||
autoLoginFailures: 10,
|
||||
autoRateViolations: 20,
|
||||
autoUploadRequests: 30,
|
||||
autoUploadBytes: 10e9,
|
||||
autoUploadBytes: 10 * 1024 ** 3,
|
||||
autoBlockMinutes: 30,
|
||||
};
|
||||
const stateSchema = z.object({ revision: z.number().int().min(0), ...fields }).strict();
|
||||
@@ -154,19 +178,20 @@ export class Administration {
|
||||
.where(eq(s.adminSettings.name, 'controls'))
|
||||
.get();
|
||||
const capacityDefaults = {
|
||||
maxConcurrentUploads: service.cfg.maxConcurrentUploads,
|
||||
totalStorageLimitMb: service.cfg.totalStorageQuota / 1048576,
|
||||
accountBytes: service.cfg.userQuota,
|
||||
deviceBytes: service.cfg.guestQuota,
|
||||
devicesTotalBytes: service.cfg.totalGuestQuota,
|
||||
perFileBytes: service.cfg.maxFileBytes,
|
||||
minDiskFreeBytes: service.cfg.minFreeBytes,
|
||||
};
|
||||
this.capacityDefaults = Object.freeze(capacityDefaults);
|
||||
this.state = row
|
||||
? stateSchema.parse({ ...networkDefaults, ...capacityDefaults, ...JSON.parse(row.value) })
|
||||
: {
|
||||
revision: 0,
|
||||
uploadsPaused: false,
|
||||
maxConcurrentUploads: service.cfg.maxConcurrentUploads,
|
||||
totalStorageLimitMb: service.cfg.totalStorageQuota / 1048576,
|
||||
blockedCountries: [],
|
||||
blockedIps: [],
|
||||
...networkDefaults,
|
||||
@@ -371,6 +396,7 @@ export class Administration {
|
||||
const disk = statfsSync(this.service.cfg.uploadDir, { bigint: true });
|
||||
return {
|
||||
settings: { ...this.state },
|
||||
capacityDefaults: { ...this.capacityDefaults },
|
||||
limits: {
|
||||
perFileBytes: this.state.perFileBytes,
|
||||
accountBytes: this.state.accountBytes,
|
||||
|
||||
@@ -102,6 +102,10 @@ test('administrator limits persist, report to clients, reject invalid updates an
|
||||
a = await f.create(),
|
||||
b = await f.create();
|
||||
await f.space(a, b);
|
||||
const defaults = (await f.call(admin, '/admin/summary')).json().capacityDefaults;
|
||||
assert.equal(defaults.perFileBytes, 4);
|
||||
assert.equal(defaults.accountBytes, f.cfg.userQuota);
|
||||
assert.equal(defaults.totalStorageLimitMb, f.cfg.totalStorageQuota / 1048576);
|
||||
assert.equal((await request(f, a, b)).json().code, 'TRANSFER_LIMIT');
|
||||
assert.equal((await own(f, user)).json().code, 'TRANSFER_LIMIT');
|
||||
const updated = await patch(f, admin, {
|
||||
@@ -112,6 +116,8 @@ test('administrator limits persist, report to clients, reject invalid updates an
|
||||
minDiskFreeBytes: 0,
|
||||
});
|
||||
const restored = new Administration(f.service);
|
||||
assert.deepEqual(restored.capacityDefaults, defaults);
|
||||
assert.deepEqual((await f.call(admin, '/admin/summary')).json().capacityDefaults, defaults);
|
||||
for (const key of [
|
||||
'perFileBytes',
|
||||
'accountBytes',
|
||||
@@ -151,7 +157,7 @@ test('administrator limits persist, report to clients, reject invalid updates an
|
||||
{ perFileBytes: 0 },
|
||||
{ accountBytes: -1 },
|
||||
{ deviceBytes: 1.2 },
|
||||
{ devicesTotalBytes: 1e12 + 1 },
|
||||
{ devicesTotalBytes: 1024 ** 4 + 1 },
|
||||
{ minDiskFreeBytes: -1 },
|
||||
]) {
|
||||
assert.equal(
|
||||
@@ -169,6 +175,13 @@ test('administrator limits persist, report to clients, reject invalid updates an
|
||||
),
|
||||
),
|
||||
);
|
||||
await patch(f, admin, { uploadsPaused: true, autoLoginFailures: 7 });
|
||||
await patch(f, admin, defaults);
|
||||
for (const [key, value] of Object.entries(defaults))
|
||||
assert.equal(f.service.admin.state[key], value, key);
|
||||
assert.equal(f.service.admin.state.uploadsPaused, true);
|
||||
assert.equal(f.service.admin.state.autoLoginFailures, 7);
|
||||
assert.equal(f.service.admin.summary().storedFiles, list.length);
|
||||
} finally {
|
||||
await f.close();
|
||||
}
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { formatSize, formatAdminDate } from '../../web/src/displayFormat.js';
|
||||
import {
|
||||
formatSize,
|
||||
formatAdminDate,
|
||||
SIZE_KB,
|
||||
SIZE_MB,
|
||||
SIZE_GB,
|
||||
} from '../../web/src/displayFormat.js';
|
||||
|
||||
test('shared display sizes use decimal KB below 1MB and switch only at MB/GB boundaries', () => {
|
||||
test('shared display uses familiar 1024-based KB/MB/GB with comma grouping and readable whole-GB quotas', () => {
|
||||
for (const [bytes, expected] of [
|
||||
[0, '0KB'],
|
||||
[10, '1KB 미만'],
|
||||
[1000, '1KB'],
|
||||
[938000, '938KB'],
|
||||
[999000, '999KB'],
|
||||
[1000000, '1.0MB'],
|
||||
[1100000, '1.1MB'],
|
||||
[1000000000, '1.0GB'],
|
||||
[1700000000, '1.7GB'],
|
||||
[7687e9, '7,687.0GB'],
|
||||
[1234567e9, '1,234,567.0GB'],
|
||||
[SIZE_KB, '1KB'],
|
||||
[938 * SIZE_KB, '938KB'],
|
||||
[1023 * SIZE_KB, '1,023KB'],
|
||||
[SIZE_MB, '1.0MB'],
|
||||
[1.1 * SIZE_MB, '1.1MB'],
|
||||
[SIZE_GB, '1.0GB'],
|
||||
[1.7 * SIZE_GB, '1.7GB'],
|
||||
[20 * SIZE_GB, '20.0GB'],
|
||||
[7687 * SIZE_GB, '7,687.0GB'],
|
||||
[1234567 * SIZE_GB, '1,234,567.0GB'],
|
||||
])
|
||||
assert.equal(formatSize(bytes), expected);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user