Merge branch 'fix/reject-zero-quota-tolerance'
This commit is contained in:
@@ -197,6 +197,23 @@ pub async fn patch_config(
|
|||||||
"Wert für {key} liegt außerhalb des zulässigen Bereichs ({min}–{max})."
|
"Wert für {key} liegt außerhalb des zulässigen Bereichs ({min}–{max})."
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
// Zero is in range and catastrophic. `quota_tolerance` is the multiplier in
|
||||||
|
// `free_disk * tolerance / active_uploaders`, so 0 makes every per-user limit 0 and
|
||||||
|
// refuses EVERY upload — mid-event, with "Du hast dein Upload-Limit für dieses Event
|
||||||
|
// erreicht", an error naming the wrong cause entirely. `storage_quota_enabled` is the
|
||||||
|
// intended off-switch.
|
||||||
|
//
|
||||||
|
// Rejecting the value rather than raising the floor: very small tolerances are
|
||||||
|
// legitimate (they are how a large disk is throttled down to a sensible per-guest
|
||||||
|
// ceiling, and how the e2e quota tests steer it — around 1e-5 on a 174 GB volume), so
|
||||||
|
// a floor of, say, 0.01 would forbid real configurations to prevent one typo.
|
||||||
|
if key_str == "quota_tolerance" && n == 0.0 {
|
||||||
|
return Err(AppError::BadRequest(
|
||||||
|
"quota_tolerance = 0 würde jeden Upload blockieren. Zum Abschalten der \
|
||||||
|
Speicher-Quote stattdessen „Speicher-Quote aktiv“ ausschalten."
|
||||||
|
.into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
} else if BOOL_KEYS.contains(&key_str) {
|
} else if BOOL_KEYS.contains(&key_str) {
|
||||||
match value.trim().to_ascii_lowercase().as_str() {
|
match value.trim().to_ascii_lowercase().as_str() {
|
||||||
"true" | "false" | "1" | "0" | "yes" | "no" | "on" | "off" => {}
|
"true" | "false" | "1" | "0" | "yes" | "no" | "on" | "off" => {}
|
||||||
|
|||||||
@@ -68,6 +68,40 @@ test.describe('Admin — config API', () => {
|
|||||||
expect(cfg.privacy_note).toBe(note);
|
expect(cfg.privacy_note).toBe(note);
|
||||||
await api.patchConfig(adminToken, { privacy_note: '' });
|
await api.patchConfig(adminToken, { privacy_note: '' });
|
||||||
});
|
});
|
||||||
|
test('quota_tolerance = 0 is rejected, with a pointer to the real off-switch', async ({
|
||||||
|
api,
|
||||||
|
adminToken,
|
||||||
|
}) => {
|
||||||
|
// Zero is inside the documented 0–1 range and catastrophic: the per-user limit is
|
||||||
|
// `free_disk * tolerance / active_uploaders`, so 0 refuses EVERY upload — mid-event, with
|
||||||
|
// "Du hast dein Upload-Limit für dieses Event erreicht", which names the wrong cause
|
||||||
|
// entirely. `storage_quota_enabled` is what an admin reaching for an off-switch wants.
|
||||||
|
const res = await fetch(
|
||||||
|
(process.env.E2E_FRONTEND_URL ?? 'http://localhost:3101') + '/api/v1/admin/config',
|
||||||
|
{
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { Authorization: `Bearer ${adminToken}`, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ quota_tolerance: '0' }),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(res.status).toBe(400);
|
||||||
|
expect(
|
||||||
|
(await res.text()).toLowerCase(),
|
||||||
|
'the error must name the switch the admin actually wanted'
|
||||||
|
).toContain('speicher-quote');
|
||||||
|
|
||||||
|
// The value is untouched — validation fully precedes any write.
|
||||||
|
expect((await api.getConfig(adminToken)).quota_tolerance).toBe('0.75');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a very small quota_tolerance is still accepted', async ({ api, adminToken }) => {
|
||||||
|
// The mirror. Rejecting 0 must not become a floor: small tolerances are how a large disk is
|
||||||
|
// throttled to a sensible per-guest ceiling, and how the quota specs steer it (~1e-5 on a
|
||||||
|
// 174 GB volume). A floor of 0.01 would forbid real configurations to prevent one typo.
|
||||||
|
await api.patchConfig(adminToken, { quota_tolerance: '0.00001' });
|
||||||
|
expect((await api.getConfig(adminToken)).quota_tolerance).toBe('0.00001');
|
||||||
|
await api.patchConfig(adminToken, { quota_tolerance: '0.75' });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Admin — stats', () => {
|
test.describe('Admin — stats', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user