mirror of
https://github.com/immich-app/immich
synced 2025-10-17 18:19:27 +00:00
feat(server, web): quotas (#4471)
* feat: quotas * chore: open api * chore: update status box and upload error message --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
parent
f4edb6c4bd
commit
deb1f970a8
63 changed files with 646 additions and 118 deletions
|
|
@ -250,7 +250,7 @@ describe(`${AlbumController.name} (e2e)`, () => {
|
|||
.set('Authorization', `Bearer ${user1.accessToken}`);
|
||||
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual(user1Albums[0]);
|
||||
expect(body).toEqual({ ...user1Albums[0], assets: [expect.objectContaining(user1Albums[0].assets[0])] });
|
||||
});
|
||||
|
||||
it('should return album info for shared album', async () => {
|
||||
|
|
@ -259,7 +259,7 @@ describe(`${AlbumController.name} (e2e)`, () => {
|
|||
.set('Authorization', `Bearer ${user1.accessToken}`);
|
||||
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual(user2Albums[0]);
|
||||
expect(body).toEqual({ ...user2Albums[0], assets: [expect.objectContaining(user2Albums[0].assets[0])] });
|
||||
});
|
||||
|
||||
it('should return album info with assets when withoutAssets is undefined', async () => {
|
||||
|
|
@ -268,7 +268,7 @@ describe(`${AlbumController.name} (e2e)`, () => {
|
|||
.set('Authorization', `Bearer ${user1.accessToken}`);
|
||||
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual(user1Albums[0]);
|
||||
expect(body).toEqual({ ...user1Albums[0], assets: [expect.objectContaining(user1Albums[0].assets[0])] });
|
||||
});
|
||||
|
||||
it('should return album info without assets when withoutAssets is true', async () => {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ describe(`${AssetController.name} (e2e)`, () => {
|
|||
let assetRepository: IAssetRepository;
|
||||
let user1: LoginResponseDto;
|
||||
let user2: LoginResponseDto;
|
||||
let userWithQuota: LoginResponseDto;
|
||||
let libraries: LibraryResponseDto[];
|
||||
let asset1: AssetResponseDto;
|
||||
let asset2: AssetResponseDto;
|
||||
|
|
@ -75,11 +76,13 @@ describe(`${AssetController.name} (e2e)`, () => {
|
|||
await Promise.all([
|
||||
api.userApi.create(server, admin.accessToken, userDto.user1),
|
||||
api.userApi.create(server, admin.accessToken, userDto.user2),
|
||||
api.userApi.create(server, admin.accessToken, userDto.userWithQuota),
|
||||
]);
|
||||
|
||||
[user1, user2] = await Promise.all([
|
||||
[user1, user2, userWithQuota] = await Promise.all([
|
||||
api.authApi.login(server, userDto.user1),
|
||||
api.authApi.login(server, userDto.user2),
|
||||
api.authApi.login(server, userDto.userWithQuota),
|
||||
]);
|
||||
|
||||
const [user1Libraries, user2Libraries] = await Promise.all([
|
||||
|
|
@ -634,6 +637,46 @@ describe(`${AssetController.name} (e2e)`, () => {
|
|||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorStub.badRequest('Not found or no asset.upload access'));
|
||||
});
|
||||
|
||||
it('should update the used quota', async () => {
|
||||
const content = randomBytes(32);
|
||||
const { body, status } = await request(server)
|
||||
.post('/asset/upload')
|
||||
.set('Authorization', `Bearer ${userWithQuota.accessToken}`)
|
||||
.field('deviceAssetId', 'example-image')
|
||||
.field('deviceId', 'TEST')
|
||||
.field('fileCreatedAt', new Date().toISOString())
|
||||
.field('fileModifiedAt', new Date().toISOString())
|
||||
.field('isFavorite', 'true')
|
||||
.field('duration', '0:00:00.000000')
|
||||
.attach('assetData', content, 'example.jpg');
|
||||
|
||||
expect(status).toBe(201);
|
||||
expect(body).toEqual({ id: expect.any(String), duplicate: false });
|
||||
|
||||
const { body: user } = await request(server)
|
||||
.get('/user/me')
|
||||
.set('Authorization', `Bearer ${userWithQuota.accessToken}`);
|
||||
|
||||
expect(user).toEqual(expect.objectContaining({ quotaUsageInBytes: 32 }));
|
||||
});
|
||||
|
||||
it('should not upload an asset if it would exceed the quota', async () => {
|
||||
const content = randomBytes(420);
|
||||
const { body, status } = await request(server)
|
||||
.post('/asset/upload')
|
||||
.set('Authorization', `Bearer ${userWithQuota.accessToken}`)
|
||||
.field('deviceAssetId', 'example-image')
|
||||
.field('deviceId', 'TEST')
|
||||
.field('fileCreatedAt', new Date().toISOString())
|
||||
.field('fileModifiedAt', new Date().toISOString())
|
||||
.field('isFavorite', 'true')
|
||||
.field('duration', '0:00:00.000000')
|
||||
.attach('assetData', content, 'example.jpg');
|
||||
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorStub.badRequest('Quota has been exceeded!'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('PUT /asset/:id', () => {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ const adminSignupResponse = {
|
|||
deletedAt: null,
|
||||
oauthId: '',
|
||||
memoriesEnabled: true,
|
||||
quotaUsageInBytes: 0,
|
||||
quotaSizeInBytes: null,
|
||||
};
|
||||
|
||||
describe(`${AuthController.name} (e2e)`, () => {
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ describe(`${ServerInfoController.name} (e2e)`, () => {
|
|||
usage: 0,
|
||||
usageByUser: [
|
||||
{
|
||||
quotaSizeInBytes: null,
|
||||
photos: 0,
|
||||
usage: 0,
|
||||
userName: 'Immich Admin',
|
||||
|
|
@ -135,6 +136,7 @@ describe(`${ServerInfoController.name} (e2e)`, () => {
|
|||
videos: 0,
|
||||
},
|
||||
{
|
||||
quotaSizeInBytes: null,
|
||||
photos: 0,
|
||||
usage: 0,
|
||||
userName: 'User 1',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue