mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
refactor(server,web): time buckets for main timeline, archived, and favorites (1) (#3537)
* refactor: time buckets * feat(web): use new time bucket api * feat(web): use asset grid in archive/favorites * chore: open api * chore: clean up uuid validation * refactor(web): move memory lane to photos page * Update web/src/routes/(user)/archive/+page.svelte Co-authored-by: Sergey Kondrikov <sergey.kondrikov@gmail.com> * fix: hide archived photos on main timeline * fix: select exif info --------- Co-authored-by: Sergey Kondrikov <sergey.kondrikov@gmail.com>
This commit is contained in:
@@ -47,6 +47,23 @@ export enum WithProperty {
|
||||
SIDECAR = 'sidecar',
|
||||
}
|
||||
|
||||
export enum TimeBucketSize {
|
||||
DAY = 'DAY',
|
||||
MONTH = 'MONTH',
|
||||
}
|
||||
|
||||
export interface TimeBucketOptions {
|
||||
size: TimeBucketSize;
|
||||
isArchived?: boolean;
|
||||
isFavorite?: boolean;
|
||||
albumId?: string;
|
||||
}
|
||||
|
||||
export interface TimeBucketItem {
|
||||
timeBucket: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export const IAssetRepository = 'IAssetRepository';
|
||||
|
||||
export interface IAssetRepository {
|
||||
@@ -64,4 +81,6 @@ export interface IAssetRepository {
|
||||
findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null>;
|
||||
getMapMarkers(ownerId: string, options?: MapMarkerSearchOptions): Promise<MapMarker[]>;
|
||||
getStatistics(ownerId: string, options: AssetStatsOptions): Promise<AssetStats>;
|
||||
getTimeBuckets(userId: string, options: TimeBucketOptions): Promise<TimeBucketItem[]>;
|
||||
getByTimeBucket(userId: string, timeBucket: string, options: TimeBucketOptions): Promise<AssetEntity[]>;
|
||||
}
|
||||
|
||||
@@ -10,11 +10,20 @@ import { mimeTypes } from '../domain.constant';
|
||||
import { HumanReadableSize, usePagination } from '../domain.util';
|
||||
import { ImmichReadStream, IStorageRepository, StorageCore, StorageFolder } from '../storage';
|
||||
import { IAssetRepository } from './asset.repository';
|
||||
import { AssetIdsDto, DownloadArchiveInfo, DownloadDto, DownloadResponseDto, MemoryLaneDto } from './dto';
|
||||
import {
|
||||
AssetIdsDto,
|
||||
DownloadArchiveInfo,
|
||||
DownloadDto,
|
||||
DownloadResponseDto,
|
||||
MemoryLaneDto,
|
||||
TimeBucketAssetDto,
|
||||
TimeBucketDto,
|
||||
} from './dto';
|
||||
import { AssetStatsDto, mapStats } from './dto/asset-statistics.dto';
|
||||
import { MapMarkerDto } from './dto/map-marker.dto';
|
||||
import { mapAsset, MapMarkerResponseDto } from './response-dto';
|
||||
import { AssetResponseDto, mapAsset, MapMarkerResponseDto } from './response-dto';
|
||||
import { MemoryLaneResponseDto } from './response-dto/memory-lane-response.dto';
|
||||
import { TimeBucketResponseDto } from './response-dto/time-bucket-response.dto';
|
||||
|
||||
export enum UploadFieldName {
|
||||
ASSET_DATA = 'assetData',
|
||||
@@ -135,6 +144,21 @@ export class AssetService {
|
||||
return Promise.all(requests).then((results) => results.filter((result) => result.assets.length > 0));
|
||||
}
|
||||
|
||||
async getTimeBuckets(authUser: AuthUserDto, dto: TimeBucketDto): Promise<TimeBucketResponseDto[]> {
|
||||
const { userId, ...options } = dto;
|
||||
const targetId = userId || authUser.id;
|
||||
await this.access.requirePermission(authUser, Permission.LIBRARY_READ, [targetId]);
|
||||
return this.assetRepository.getTimeBuckets(targetId, options);
|
||||
}
|
||||
|
||||
async getByTimeBucket(authUser: AuthUserDto, dto: TimeBucketAssetDto): Promise<AssetResponseDto[]> {
|
||||
const { userId, timeBucket, ...options } = dto;
|
||||
const targetId = userId || authUser.id;
|
||||
await this.access.requirePermission(authUser, Permission.LIBRARY_READ, [targetId]);
|
||||
const assets = await this.assetRepository.getByTimeBucket(targetId, timeBucket, options);
|
||||
return assets.map(mapAsset);
|
||||
}
|
||||
|
||||
async downloadFile(authUser: AuthUserDto, id: string): Promise<ImmichReadStream> {
|
||||
await this.access.requirePermission(authUser, Permission.ASSET_DOWNLOAD, id);
|
||||
|
||||
|
||||
@@ -3,3 +3,4 @@ export * from './asset-statistics.dto';
|
||||
export * from './download.dto';
|
||||
export * from './map-marker.dto';
|
||||
export * from './memory-lane.dto';
|
||||
export * from './time-bucket.dto';
|
||||
|
||||
34
server/src/domain/asset/dto/time-bucket.dto.ts
Normal file
34
server/src/domain/asset/dto/time-bucket.dto.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
import { IsBoolean, IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
import { toBoolean, ValidateUUID } from '../../domain.util';
|
||||
import { TimeBucketSize } from '../asset.repository';
|
||||
|
||||
export class TimeBucketDto {
|
||||
@IsNotEmpty()
|
||||
@IsEnum(TimeBucketSize)
|
||||
@ApiProperty({ enum: TimeBucketSize, enumName: 'TimeBucketSize' })
|
||||
size!: TimeBucketSize;
|
||||
|
||||
@ValidateUUID({ optional: true })
|
||||
userId?: string;
|
||||
|
||||
@ValidateUUID({ optional: true })
|
||||
albumId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform(toBoolean)
|
||||
isArchived?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform(toBoolean)
|
||||
isFavorite?: boolean;
|
||||
}
|
||||
|
||||
export class TimeBucketAssetDto extends TimeBucketDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
timeBucket!: string;
|
||||
}
|
||||
@@ -3,3 +3,4 @@ export * from './asset-response.dto';
|
||||
export * from './exif-response.dto';
|
||||
export * from './map-marker-response.dto';
|
||||
export * from './smart-info-response.dto';
|
||||
export * from './time-bucket-response.dto';
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class TimeBucketResponseDto {
|
||||
@ApiProperty({ type: 'string' })
|
||||
timeBucket!: string;
|
||||
|
||||
@ApiProperty({ type: 'integer' })
|
||||
count!: number;
|
||||
}
|
||||
Reference in New Issue
Block a user