diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index a4fbbf371a..7c8afb09e4 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -100,7 +100,6 @@ Class | Method | HTTP request | Description *AssetsApi* | [**getAllUserAssetsByDeviceId**](doc//AssetsApi.md#getalluserassetsbydeviceid) | **GET** /assets/device/{deviceId} | getAllUserAssetsByDeviceId *AssetsApi* | [**getAssetInfo**](doc//AssetsApi.md#getassetinfo) | **GET** /assets/{id} | *AssetsApi* | [**getAssetStatistics**](doc//AssetsApi.md#getassetstatistics) | **GET** /assets/statistics | -*AssetsApi* | [**getMemoryLane**](doc//AssetsApi.md#getmemorylane) | **GET** /assets/memory-lane | *AssetsApi* | [**getRandom**](doc//AssetsApi.md#getrandom) | **GET** /assets/random | *AssetsApi* | [**playAssetVideo**](doc//AssetsApi.md#playassetvideo) | **GET** /assets/{id}/video/playback | *AssetsApi* | [**replaceAsset**](doc//AssetsApi.md#replaceasset) | **PUT** /assets/{id}/original | replaceAsset @@ -353,7 +352,6 @@ Class | Method | HTTP request | Description - [MemoriesResponse](doc//MemoriesResponse.md) - [MemoriesUpdate](doc//MemoriesUpdate.md) - [MemoryCreateDto](doc//MemoryCreateDto.md) - - [MemoryLaneResponseDto](doc//MemoryLaneResponseDto.md) - [MemoryResponseDto](doc//MemoryResponseDto.md) - [MemoryType](doc//MemoryType.md) - [MemoryUpdateDto](doc//MemoryUpdateDto.md) diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 78fa31691d..ab9b251e01 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -156,7 +156,6 @@ part 'model/map_reverse_geocode_response_dto.dart'; part 'model/memories_response.dart'; part 'model/memories_update.dart'; part 'model/memory_create_dto.dart'; -part 'model/memory_lane_response_dto.dart'; part 'model/memory_response_dto.dart'; part 'model/memory_type.dart'; part 'model/memory_update_dto.dart'; diff --git a/mobile/openapi/lib/api/assets_api.dart b/mobile/openapi/lib/api/assets_api.dart index f52c70b37f..f744988449 100644 --- a/mobile/openapi/lib/api/assets_api.dart +++ b/mobile/openapi/lib/api/assets_api.dart @@ -404,63 +404,6 @@ class AssetsApi { return null; } - /// Performs an HTTP 'GET /assets/memory-lane' operation and returns the [Response]. - /// Parameters: - /// - /// * [int] day (required): - /// - /// * [int] month (required): - Future getMemoryLaneWithHttpInfo(int day, int month,) async { - // ignore: prefer_const_declarations - final apiPath = r'/assets/memory-lane'; - - // ignore: prefer_final_locals - Object? postBody; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - queryParams.addAll(_queryParams('', 'day', day)); - queryParams.addAll(_queryParams('', 'month', month)); - - const contentTypes = []; - - - return apiClient.invokeAPI( - apiPath, - 'GET', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Parameters: - /// - /// * [int] day (required): - /// - /// * [int] month (required): - Future?> getMemoryLane(int day, int month,) async { - final response = await getMemoryLaneWithHttpInfo(day, month,); - if (response.statusCode >= HttpStatus.badRequest) { - throw ApiException(response.statusCode, await _decodeBodyBytes(response)); - } - // When a remote server returns no body with a status of 204, we shall not decode it. - // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" - // FormatException when trying to decode an empty string. - if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { - final responseBody = await _decodeBodyBytes(response); - return (await apiClient.deserializeAsync(responseBody, 'List') as List) - .cast() - .toList(growable: false); - - } - return null; - } - /// This property was deprecated in v1.116.0 /// /// Note: This method returns the HTTP [Response]. diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 9d0e80e58b..ec5eb09729 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -368,8 +368,6 @@ class ApiClient { return MemoriesUpdate.fromJson(value); case 'MemoryCreateDto': return MemoryCreateDto.fromJson(value); - case 'MemoryLaneResponseDto': - return MemoryLaneResponseDto.fromJson(value); case 'MemoryResponseDto': return MemoryResponseDto.fromJson(value); case 'MemoryType': diff --git a/mobile/openapi/lib/model/memory_lane_response_dto.dart b/mobile/openapi/lib/model/memory_lane_response_dto.dart deleted file mode 100644 index 27248d05c1..0000000000 --- a/mobile/openapi/lib/model/memory_lane_response_dto.dart +++ /dev/null @@ -1,107 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.18 - -// ignore_for_file: unused_element, unused_import -// ignore_for_file: always_put_required_named_parameters_first -// ignore_for_file: constant_identifier_names -// ignore_for_file: lines_longer_than_80_chars - -part of openapi.api; - -class MemoryLaneResponseDto { - /// Returns a new [MemoryLaneResponseDto] instance. - MemoryLaneResponseDto({ - this.assets = const [], - required this.yearsAgo, - }); - - List assets; - - int yearsAgo; - - @override - bool operator ==(Object other) => identical(this, other) || other is MemoryLaneResponseDto && - _deepEquality.equals(other.assets, assets) && - other.yearsAgo == yearsAgo; - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (assets.hashCode) + - (yearsAgo.hashCode); - - @override - String toString() => 'MemoryLaneResponseDto[assets=$assets, yearsAgo=$yearsAgo]'; - - Map toJson() { - final json = {}; - json[r'assets'] = this.assets; - json[r'yearsAgo'] = this.yearsAgo; - return json; - } - - /// Returns a new [MemoryLaneResponseDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static MemoryLaneResponseDto? fromJson(dynamic value) { - upgradeDto(value, "MemoryLaneResponseDto"); - if (value is Map) { - final json = value.cast(); - - return MemoryLaneResponseDto( - assets: AssetResponseDto.listFromJson(json[r'assets']), - yearsAgo: mapValueOfType(json, r'yearsAgo')!, - ); - } - return null; - } - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = MemoryLaneResponseDto.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } - - static Map mapFromJson(dynamic json) { - final map = {}; - if (json is Map && json.isNotEmpty) { - json = json.cast(); // ignore: parameter_assignments - for (final entry in json.entries) { - final value = MemoryLaneResponseDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of MemoryLaneResponseDto-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; - if (json is Map && json.isNotEmpty) { - // ignore: parameter_assignments - json = json.cast(); - for (final entry in json.entries) { - map[entry.key] = MemoryLaneResponseDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'assets', - 'yearsAgo', - }; -} - diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index adad1308c2..0951177c72 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -1726,62 +1726,6 @@ ] } }, - "/assets/memory-lane": { - "get": { - "operationId": "getMemoryLane", - "parameters": [ - { - "name": "day", - "required": true, - "in": "query", - "schema": { - "minimum": 1, - "maximum": 31, - "type": "integer" - } - }, - { - "name": "month", - "required": true, - "in": "query", - "schema": { - "minimum": 1, - "maximum": 12, - "type": "integer" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/MemoryLaneResponseDto" - }, - "type": "array" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "Assets" - ] - } - }, "/assets/random": { "get": { "deprecated": true, @@ -10117,24 +10061,6 @@ ], "type": "object" }, - "MemoryLaneResponseDto": { - "properties": { - "assets": { - "items": { - "$ref": "#/components/schemas/AssetResponseDto" - }, - "type": "array" - }, - "yearsAgo": { - "type": "integer" - } - }, - "required": [ - "assets", - "yearsAgo" - ], - "type": "object" - }, "MemoryResponseDto": { "properties": { "assets": { diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index 2684d2558f..20fb72b486 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -462,10 +462,6 @@ export type AssetJobsDto = { assetIds: string[]; name: AssetJobName; }; -export type MemoryLaneResponseDto = { - assets: AssetResponseDto[]; - yearsAgo: number; -}; export type AssetStatsResponseDto = { images: number; total: number; @@ -1866,20 +1862,6 @@ export function runAssetJobs({ assetJobsDto }: { body: assetJobsDto }))); } -export function getMemoryLane({ day, month }: { - day: number; - month: number; -}, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: MemoryLaneResponseDto[]; - }>(`/assets/memory-lane${QS.query(QS.explode({ - day, - month - }))}`, { - ...opts - })); -} /** * This property was deprecated in v1.116.0 */ diff --git a/server/src/controllers/asset.controller.ts b/server/src/controllers/asset.controller.ts index 9a7252a087..925b64c8a8 100644 --- a/server/src/controllers/asset.controller.ts +++ b/server/src/controllers/asset.controller.ts @@ -1,7 +1,7 @@ import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common'; import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { EndpointLifecycle } from 'src/decorators'; -import { AssetResponseDto, MemoryLaneResponseDto } from 'src/dtos/asset-response.dto'; +import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AssetBulkDeleteDto, AssetBulkUpdateDto, @@ -13,7 +13,6 @@ import { UpdateAssetDto, } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { MemoryLaneDto } from 'src/dtos/search.dto'; import { RouteKey } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { AssetService } from 'src/services/asset.service'; @@ -24,12 +23,6 @@ import { UUIDParamDto } from 'src/validation'; export class AssetController { constructor(private service: AssetService) {} - @Get('memory-lane') - @Authenticated() - getMemoryLane(@Auth() auth: AuthDto, @Query() dto: MemoryLaneDto): Promise { - return this.service.getMemoryLane(auth, dto); - } - @Get('random') @Authenticated() @EndpointLifecycle({ deprecatedAt: 'v1.116.0' }) diff --git a/server/src/dtos/asset-response.dto.ts b/server/src/dtos/asset-response.dto.ts index c0e589f380..3732e665cd 100644 --- a/server/src/dtos/asset-response.dto.ts +++ b/server/src/dtos/asset-response.dto.ts @@ -199,10 +199,3 @@ export function mapAsset(entity: MapAsset, options: AssetMapOptions = {}): Asset resized: true, }; } - -export class MemoryLaneResponseDto { - @ApiProperty({ type: 'integer' }) - yearsAgo!: number; - - assets!: AssetResponseDto[]; -} diff --git a/server/src/services/asset.service.spec.ts b/server/src/services/asset.service.spec.ts index af4fef5bd5..ecfb7936d2 100755 --- a/server/src/services/asset.service.spec.ts +++ b/server/src/services/asset.service.spec.ts @@ -1,6 +1,6 @@ import { BadRequestException } from '@nestjs/common'; import { DateTime } from 'luxon'; -import { MapAsset, mapAsset } from 'src/dtos/asset-response.dto'; +import { MapAsset } from 'src/dtos/asset-response.dto'; import { AssetJobName, AssetStatsResponseDto } from 'src/dtos/asset.dto'; import { AssetStatus, AssetType, JobName, JobStatus } from 'src/enum'; import { AssetStats } from 'src/repositories/asset.repository'; @@ -11,7 +11,6 @@ import { faceStub } from 'test/fixtures/face.stub'; import { userStub } from 'test/fixtures/user.stub'; import { factory } from 'test/small.factory'; import { makeStream, newTestService, ServiceMocks } from 'test/utils'; -import { vitest } from 'vitest'; const stats: AssetStats = { [AssetType.IMAGE]: 10, @@ -44,62 +43,6 @@ describe(AssetService.name, () => { mockGetById([assetStub.livePhotoStillAsset, assetStub.livePhotoMotionAsset]); }); - describe('getMemoryLane', () => { - beforeAll(() => { - vitest.useFakeTimers(); - vitest.setSystemTime(new Date('2024-01-15')); - }); - - afterAll(() => { - vitest.useRealTimers(); - }); - - it('should group the assets correctly', async () => { - const image1 = { ...assetStub.image, localDateTime: new Date(2023, 1, 15, 0, 0, 0) }; - const image2 = { ...assetStub.image, localDateTime: new Date(2023, 1, 15, 1, 0, 0) }; - const image3 = { ...assetStub.image, localDateTime: new Date(2015, 1, 15) }; - const image4 = { ...assetStub.image, localDateTime: new Date(2009, 1, 15) }; - - mocks.partner.getAll.mockResolvedValue([]); - mocks.asset.getByDayOfYear.mockResolvedValue([ - { - year: 2023, - assets: [image1, image2], - }, - { - year: 2015, - assets: [image3], - }, - { - year: 2009, - assets: [image4], - }, - ] as any); - - await expect(sut.getMemoryLane(authStub.admin, { day: 15, month: 1 })).resolves.toEqual([ - { yearsAgo: 1, title: '1 year ago', assets: [mapAsset(image1), mapAsset(image2)] }, - { yearsAgo: 9, title: '9 years ago', assets: [mapAsset(image3)] }, - { yearsAgo: 15, title: '15 years ago', assets: [mapAsset(image4)] }, - ]); - - expect(mocks.asset.getByDayOfYear.mock.calls).toEqual([[[authStub.admin.user.id], { day: 15, month: 1 }]]); - }); - - it('should get memories with partners with inTimeline enabled', async () => { - const partner = factory.partner(); - const auth = factory.auth({ user: { id: partner.sharedWithId } }); - - mocks.partner.getAll.mockResolvedValue([partner]); - mocks.asset.getByDayOfYear.mockResolvedValue([]); - - await sut.getMemoryLane(auth, { day: 15, month: 1 }); - - expect(mocks.asset.getByDayOfYear.mock.calls).toEqual([ - [[auth.user.id, partner.sharedById], { day: 15, month: 1 }], - ]); - }); - }); - describe('getStatistics', () => { it('should get the statistics for a user, excluding archived assets', async () => { mocks.asset.getStatistics.mockResolvedValue(stats); diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index 3e13ed0b8e..bcbe86875b 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -3,13 +3,7 @@ import _ from 'lodash'; import { DateTime, Duration } from 'luxon'; import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { OnJob } from 'src/decorators'; -import { - AssetResponseDto, - MapAsset, - MemoryLaneResponseDto, - SanitizedAssetResponseDto, - mapAsset, -} from 'src/dtos/asset-response.dto'; +import { AssetResponseDto, MapAsset, SanitizedAssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { AssetBulkDeleteDto, AssetBulkUpdateDto, @@ -20,7 +14,6 @@ import { mapStats, } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { MemoryLaneDto } from 'src/dtos/search.dto'; import { AssetStatus, JobName, JobStatus, Permission, QueueName } from 'src/enum'; import { BaseService } from 'src/services/base.service'; import { ISidecarWriteJob, JobItem, JobOf } from 'src/types'; @@ -28,26 +21,6 @@ import { getAssetFiles, getMyPartnerIds, onAfterUnlink, onBeforeLink, onBeforeUn @Injectable() export class AssetService extends BaseService { - async getMemoryLane(auth: AuthDto, dto: MemoryLaneDto): Promise { - const partnerIds = await getMyPartnerIds({ - userId: auth.user.id, - repository: this.partnerRepository, - timelineEnabled: true, - }); - const userIds = [auth.user.id, ...partnerIds]; - - const groups = await this.assetRepository.getByDayOfYear(userIds, dto); - return groups.map(({ year, assets }) => { - const yearsAgo = DateTime.utc().year - year; - return { - yearsAgo, - // TODO move this to clients - title: `${yearsAgo} year${yearsAgo > 1 ? 's' : ''} ago`, - assets: assets.map((asset) => mapAsset(asset, { auth })), - }; - }); - } - async getStatistics(auth: AuthDto, dto: AssetStatsDto) { const stats = await this.assetRepository.getStatistics(auth.user.id, dto); return mapStats(stats);