A login's storage is counted, and can have a quota
MediaAttachment.Size was stored and never summed: nobody, the administrator included, could tell what media took, and nothing bounded it. Counted.Media and MediaOfRoot sum what is kept (not trashed). A login sees what its personas' uploads and pictures take at /clientapi/user/storage (ViewStorage), with its quota when the server sets one; Media:QuotaBytesPerRoot (0, no quota, by default) refuses an upload or a picture over it with 422, whichever persona sends it; the statistics overview gains the media totals, the proxy cache and the trash (ViewMediaTotals). Tests: a login's storage counts what its personas keep and forgets what is trashed; two uploads from two personas of one login are refused together past the quota. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
5252b8f320
commit
dc63fa57b8
11 files changed
+134
-3
No files matched your search
@@ -100,6 +100,31 @@ namespace PrivaPub.Tests.Domain
|
||||
Assert.Null(tampered);
|
||||
}
|
||||
|
||||
// a login over its quota uploads nothing more, whichever persona tries
|
||||
[Fact]
|
||||
public async Task A_login_over_its_quota_uploads_nothing_more()
|
||||
{
|
||||
var token = TestContext.Current.CancellationToken;
|
||||
var (root, alice) = await _harness.Persona("alice");
|
||||
var (_, sibling) = await _harness.Persona("sibling", root);
|
||||
var quota = new MediaService(new StaticOptions<MediaOptions>(new MediaOptions { Root = _harness.Media.Root, QuotaBytesPerRoot = 3000 }),
|
||||
_harness.Local, default, Microsoft.Extensions.Logging.Abstractions.NullLogger<MediaService>.Instance);
|
||||
// noise: its PNG is about as big as its pixels, so two of them are over the quota and one is not
|
||||
static byte[] Noise()
|
||||
{
|
||||
var pixels = new byte[30 * 20 * 3];
|
||||
Random.Shared.NextBytes(pixels);
|
||||
using var image = NetVips.Image.NewFromMemory(pixels, 30, 20, 3, NetVips.Enums.BandFormat.Uchar);
|
||||
return image.WriteToBuffer(".png");
|
||||
}
|
||||
|
||||
Assert.True((await quota.Upload(alice, Upload(Noise(), "image/png"), default, default, false, token)).Ok);
|
||||
var full = await quota.Upload(sibling, Upload(Noise(), "image/png"), default, default, false, token);
|
||||
|
||||
Assert.False(full.Ok);
|
||||
Assert.Contains("storage is full", full.Error);
|
||||
}
|
||||
|
||||
// nothing of a suspended server, or of one whose media are rejected, is proxied; blocking one purges what was cached
|
||||
[Fact]
|
||||
public async Task A_blocked_servers_media_are_not_proxied_and_their_cache_goes()
|
||||
|
||||
Reference in new issue
Block a user