mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
feat: adding photo & video storage space to server stats (#14125)
* expose detailed user storage stats + display them in the storage per user table * chore: openapi & sql * fix: fix test stubs * fix: formatting errors, e2e test and server test * fix: upper lower case typo in spec file --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
parent
24ae4ecff1
commit
f5c4af73aa
12 changed files with 138 additions and 7 deletions
|
|
@ -86,6 +86,10 @@ export class UsageByUserDto {
|
|||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
usage!: number;
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
usagePhotos!: number;
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
usageVideos!: number;
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
quotaSizeInBytes!: number | null;
|
||||
}
|
||||
|
||||
|
|
@ -99,6 +103,12 @@ export class ServerStatsResponseDto {
|
|||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
usage = 0;
|
||||
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
usagePhotos = 0;
|
||||
|
||||
@ApiProperty({ type: 'integer', format: 'int64' })
|
||||
usageVideos = 0;
|
||||
|
||||
@ApiProperty({
|
||||
isArray: true,
|
||||
type: UsageByUserDto,
|
||||
|
|
@ -107,7 +117,9 @@ export class ServerStatsResponseDto {
|
|||
{
|
||||
photos: 1,
|
||||
videos: 1,
|
||||
diskUsageRaw: 1,
|
||||
diskUsageRaw: 2,
|
||||
usagePhotos: 1,
|
||||
usageVideos: 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ export interface UserStatsQueryResponse {
|
|||
photos: number;
|
||||
videos: number;
|
||||
usage: number;
|
||||
usagePhotos: number;
|
||||
usageVideos: number;
|
||||
quotaSizeInBytes: number | null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,23 @@ SELECT
|
|||
"assets"."libraryId" IS NULL
|
||||
),
|
||||
0
|
||||
) AS "usage"
|
||||
) AS "usage",
|
||||
COALESCE(
|
||||
SUM("exif"."fileSizeInByte") FILTER (
|
||||
WHERE
|
||||
"assets"."libraryId" IS NULL
|
||||
AND "assets"."type" = 'IMAGE'
|
||||
),
|
||||
0
|
||||
) AS "usagePhotos",
|
||||
COALESCE(
|
||||
SUM("exif"."fileSizeInByte") FILTER (
|
||||
WHERE
|
||||
"assets"."libraryId" IS NULL
|
||||
AND "assets"."type" = 'VIDEO'
|
||||
),
|
||||
0
|
||||
) AS "usageVideos"
|
||||
FROM
|
||||
"users" "users"
|
||||
LEFT JOIN "assets" "assets" ON "assets"."ownerId" = "users"."id"
|
||||
|
|
|
|||
|
|
@ -108,6 +108,14 @@ export class UserRepository implements IUserRepository {
|
|||
.addSelect(`COUNT(assets.id) FILTER (WHERE assets.type = 'IMAGE' AND assets.isVisible)`, 'photos')
|
||||
.addSelect(`COUNT(assets.id) FILTER (WHERE assets.type = 'VIDEO' AND assets.isVisible)`, 'videos')
|
||||
.addSelect('COALESCE(SUM(exif.fileSizeInByte) FILTER (WHERE assets.libraryId IS NULL), 0)', 'usage')
|
||||
.addSelect(
|
||||
`COALESCE(SUM(exif.fileSizeInByte) FILTER (WHERE assets.libraryId IS NULL AND assets.type = 'IMAGE'), 0)`,
|
||||
'usagePhotos',
|
||||
)
|
||||
.addSelect(
|
||||
`COALESCE(SUM(exif.fileSizeInByte) FILTER (WHERE assets.libraryId IS NULL AND assets.type = 'VIDEO'), 0)`,
|
||||
'usageVideos',
|
||||
)
|
||||
.addSelect('users.quotaSizeInBytes', 'quotaSizeInBytes')
|
||||
.leftJoin('users.assets', 'assets')
|
||||
.leftJoin('assets.exifInfo', 'exif')
|
||||
|
|
@ -119,6 +127,8 @@ export class UserRepository implements IUserRepository {
|
|||
stat.photos = Number(stat.photos);
|
||||
stat.videos = Number(stat.videos);
|
||||
stat.usage = Number(stat.usage);
|
||||
stat.usagePhotos = Number(stat.usagePhotos);
|
||||
stat.usageVideos = Number(stat.usageVideos);
|
||||
stat.quotaSizeInBytes = stat.quotaSizeInBytes;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -185,6 +185,8 @@ describe(ServerService.name, () => {
|
|||
photos: 10,
|
||||
videos: 11,
|
||||
usage: 12_345,
|
||||
usagePhotos: 1,
|
||||
usageVideos: 11_345,
|
||||
quotaSizeInBytes: 0,
|
||||
},
|
||||
{
|
||||
|
|
@ -193,6 +195,8 @@ describe(ServerService.name, () => {
|
|||
photos: 10,
|
||||
videos: 20,
|
||||
usage: 123_456,
|
||||
usagePhotos: 100,
|
||||
usageVideos: 23_456,
|
||||
quotaSizeInBytes: 0,
|
||||
},
|
||||
{
|
||||
|
|
@ -201,6 +205,8 @@ describe(ServerService.name, () => {
|
|||
photos: 100,
|
||||
videos: 0,
|
||||
usage: 987_654,
|
||||
usagePhotos: 900,
|
||||
usageVideos: 87_654,
|
||||
quotaSizeInBytes: 0,
|
||||
},
|
||||
]);
|
||||
|
|
@ -209,11 +215,15 @@ describe(ServerService.name, () => {
|
|||
photos: 120,
|
||||
videos: 31,
|
||||
usage: 1_123_455,
|
||||
usagePhotos: 1001,
|
||||
usageVideos: 122_455,
|
||||
usageByUser: [
|
||||
{
|
||||
photos: 10,
|
||||
quotaSizeInBytes: 0,
|
||||
usage: 12_345,
|
||||
usagePhotos: 1,
|
||||
usageVideos: 11_345,
|
||||
userName: '1 User',
|
||||
userId: 'user1',
|
||||
videos: 11,
|
||||
|
|
@ -222,6 +232,8 @@ describe(ServerService.name, () => {
|
|||
photos: 10,
|
||||
quotaSizeInBytes: 0,
|
||||
usage: 123_456,
|
||||
usagePhotos: 100,
|
||||
usageVideos: 23_456,
|
||||
userName: '2 User',
|
||||
userId: 'user2',
|
||||
videos: 20,
|
||||
|
|
@ -230,6 +242,8 @@ describe(ServerService.name, () => {
|
|||
photos: 100,
|
||||
quotaSizeInBytes: 0,
|
||||
usage: 987_654,
|
||||
usagePhotos: 900,
|
||||
usageVideos: 87_654,
|
||||
userName: '3 User',
|
||||
userId: 'user3',
|
||||
videos: 0,
|
||||
|
|
|
|||
|
|
@ -126,11 +126,16 @@ export class ServerService extends BaseService {
|
|||
usage.photos = user.photos;
|
||||
usage.videos = user.videos;
|
||||
usage.usage = user.usage;
|
||||
usage.usagePhotos = user.usagePhotos;
|
||||
usage.usageVideos = user.usageVideos;
|
||||
usage.quotaSizeInBytes = user.quotaSizeInBytes;
|
||||
|
||||
serverStats.photos += usage.photos;
|
||||
serverStats.videos += usage.videos;
|
||||
serverStats.usage += usage.usage;
|
||||
serverStats.usagePhotos += usage.usagePhotos;
|
||||
serverStats.usageVideos += usage.usageVideos;
|
||||
|
||||
serverStats.usageByUser.push(usage);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue