mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
feat(uploads): size one upload against the account's own quota
The per-file ceiling was a flat 5 GiB from the environment, which is both too small for a paying account with 200 GB of storage and unaware of what an upload actually costs. The provider derives its own renditions from the file (1080p, 720p and down) and bills them to the same account, so a file allowed to fill the quota exactly is over it by the time it finishes processing. The ceiling is now 80% of whatever limit the account is held to: 160 GB on the plan, 2.4 GB on a cardless trial, and it moves on its own when either number changes. OPENFRAME_MAX_VIDEO_UPLOAD_BYTES keeps working as an absolute cap for a host that wants one, where the lower of the two applies, and an instance running without billing has no quota to divide and falls back to the flat 5 GiB. The refusal now names the ceiling, which the old one left the client to guess. Finalize re-checks only the host cap. Re-deriving the account's ceiling there would delete a finished upload over a plan that lapsed while the bytes were in flight, and an upload larger than what was declared is already caught by the declared-size check beside it.
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
PLAN_STORAGE_LIMIT_BYTES,
|
||||
UPLOAD_RESERVATION_PURPOSES,
|
||||
enforceStorageQuota,
|
||||
getMaxVideoUploadBytesForUser,
|
||||
getUserStorageInfo,
|
||||
getUserTotalStorageBytes,
|
||||
releaseStorageReservation,
|
||||
@@ -107,6 +108,48 @@ describe('the trial ceiling', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// One upload may take 80% of whatever ceiling the account is held to. The fifth
|
||||
// left free is for what the upload turns into: the provider derives its own
|
||||
// renditions (1080p, 720p and down) from the file and bills them to the same
|
||||
// account, so a file that filled the quota exactly would put the account over it
|
||||
// once processing finished.
|
||||
describe('getMaxVideoUploadBytesForUser', () => {
|
||||
it('is 80% of the plan ceiling for a paying account', async () => {
|
||||
const user = await createSubscribedUser();
|
||||
|
||||
expect(await getMaxVideoUploadBytesForUser(user.id)).toBe(BigInt(160) * GIB);
|
||||
});
|
||||
|
||||
it('is 80% of the trial ceiling for an unpaid one', async () => {
|
||||
const user = await createUser();
|
||||
|
||||
expect(await getMaxVideoUploadBytesForUser(user.id)).toBe(
|
||||
(BigInt(3) * GIB * BigInt(80)) / BigInt(100)
|
||||
);
|
||||
});
|
||||
|
||||
it('drops to a host ceiling that is stricter than the account share', async () => {
|
||||
vi.stubEnv('OPENFRAME_MAX_VIDEO_UPLOAD_BYTES', (BigInt(5) * GIB).toString());
|
||||
const user = await createSubscribedUser();
|
||||
|
||||
expect(await getMaxVideoUploadBytesForUser(user.id)).toBe(BigInt(5) * GIB);
|
||||
});
|
||||
|
||||
it('ignores a host ceiling looser than the account share, which the quota would refuse anyway', async () => {
|
||||
vi.stubEnv('OPENFRAME_MAX_VIDEO_UPLOAD_BYTES', (BigInt(500) * GIB).toString());
|
||||
const user = await createSubscribedUser();
|
||||
|
||||
expect(await getMaxVideoUploadBytesForUser(user.id)).toBe(BigInt(160) * GIB);
|
||||
});
|
||||
|
||||
it('falls back to the flat default where there is no billing, and so no quota to divide', async () => {
|
||||
vi.stubEnv('OPENFRAME_ENABLE_STRIPE', 'false');
|
||||
const user = await createUser();
|
||||
|
||||
expect(await getMaxVideoUploadBytesForUser(user.id)).toBe(BigInt(5) * GIB);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUserTotalStorageBytes', () => {
|
||||
it('is zero for a user with nothing stored', async () => {
|
||||
const user = await createSubscribedUser();
|
||||
|
||||
Reference in New Issue
Block a user