From d41013131283ee75f098fdb1423e18203ade5e55 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Wed, 15 Apr 2026 13:58:48 -0400 Subject: [PATCH] chore!: remove old timeline sync endpoints (#27804) --- mobile/openapi/README.md | 7 - mobile/openapi/lib/api.dart | 3 - mobile/openapi/lib/api/deprecated_api.dart | 115 ---------- mobile/openapi/lib/api/sync_api.dart | 115 ---------- mobile/openapi/lib/api_client.dart | 6 - .../lib/model/asset_delta_sync_dto.dart | 113 ---------- .../model/asset_delta_sync_response_dto.dart | 119 ---------- .../lib/model/asset_full_sync_dto.dart | 150 ------------- mobile/openapi/lib/model/job_name.dart | 3 - open-api/immich-openapi-specs.json | 205 ------------------ open-api/typescript-sdk/src/fetch-client.ts | 54 ----- server/src/controllers/sync.controller.ts | 35 +-- server/src/dtos/sync.dto.ts | 31 --- server/src/enum.ts | 16 -- server/src/queries/asset.repository.sql | 57 ----- server/src/queries/audit.repository.sql | 16 -- server/src/repositories/asset.repository.ts | 77 ------- server/src/repositories/audit.repository.ts | 44 ---- server/src/repositories/index.ts | 2 - server/src/schema/index.ts | 4 - .../1776217577402-DropAuditTable.ts | 18 ++ server/src/schema/tables/audit.table.ts | 24 -- server/src/services/audit.service.spec.ts | 26 --- server/src/services/audit.service.ts | 15 -- server/src/services/base.service.ts | 3 - server/src/services/index.ts | 2 - server/src/services/queue.service.spec.ts | 1 - server/src/services/queue.service.ts | 1 - server/src/services/sync.service.spec.ts | 98 --------- server/src/services/sync.service.ts | 83 +------ server/src/types.ts | 1 - .../repositories/asset.repository.mock.ts | 2 - server/test/utils.ts | 4 - 33 files changed, 20 insertions(+), 1430 deletions(-) delete mode 100644 mobile/openapi/lib/model/asset_delta_sync_dto.dart delete mode 100644 mobile/openapi/lib/model/asset_delta_sync_response_dto.dart delete mode 100644 mobile/openapi/lib/model/asset_full_sync_dto.dart delete mode 100644 server/src/queries/audit.repository.sql delete mode 100644 server/src/repositories/audit.repository.ts create mode 100644 server/src/schema/migrations/1776217577402-DropAuditTable.ts delete mode 100644 server/src/schema/tables/audit.table.ts delete mode 100644 server/src/services/audit.service.spec.ts delete mode 100644 server/src/services/audit.service.ts delete mode 100644 server/src/services/sync.service.spec.ts diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 612a65ae4e..c893ce33a5 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -143,8 +143,6 @@ Class | Method | HTTP request | Description *DatabaseBackupsAdminApi* | [**uploadDatabaseBackup**](doc//DatabaseBackupsAdminApi.md#uploaddatabasebackup) | **POST** /admin/database-backups/upload | Upload database backup *DeprecatedApi* | [**createPartnerDeprecated**](doc//DeprecatedApi.md#createpartnerdeprecated) | **POST** /partners/{id} | Create a partner *DeprecatedApi* | [**getAllUserAssetsByDeviceId**](doc//DeprecatedApi.md#getalluserassetsbydeviceid) | **GET** /assets/device/{deviceId} | Retrieve assets by device ID -*DeprecatedApi* | [**getDeltaSync**](doc//DeprecatedApi.md#getdeltasync) | **POST** /sync/delta-sync | Get delta sync for user -*DeprecatedApi* | [**getFullSyncForUser**](doc//DeprecatedApi.md#getfullsyncforuser) | **POST** /sync/full-sync | Get full sync for user *DeprecatedApi* | [**getQueuesLegacy**](doc//DeprecatedApi.md#getqueueslegacy) | **GET** /jobs | Retrieve queue counts and status *DeprecatedApi* | [**runQueueCommandLegacy**](doc//DeprecatedApi.md#runqueuecommandlegacy) | **PUT** /jobs/{name} | Run jobs *DownloadApi* | [**downloadArchive**](doc//DownloadApi.md#downloadarchive) | **POST** /download/archive | Download asset archive @@ -263,8 +261,6 @@ Class | Method | HTTP request | Description *StacksApi* | [**searchStacks**](doc//StacksApi.md#searchstacks) | **GET** /stacks | Retrieve stacks *StacksApi* | [**updateStack**](doc//StacksApi.md#updatestack) | **PUT** /stacks/{id} | Update a stack *SyncApi* | [**deleteSyncAck**](doc//SyncApi.md#deletesyncack) | **DELETE** /sync/ack | Delete acknowledgements -*SyncApi* | [**getDeltaSync**](doc//SyncApi.md#getdeltasync) | **POST** /sync/delta-sync | Get delta sync for user -*SyncApi* | [**getFullSyncForUser**](doc//SyncApi.md#getfullsyncforuser) | **POST** /sync/full-sync | Get full sync for user *SyncApi* | [**getSyncAck**](doc//SyncApi.md#getsyncack) | **GET** /sync/ack | Retrieve acknowledgements *SyncApi* | [**getSyncStream**](doc//SyncApi.md#getsyncstream) | **POST** /sync/stream | Stream sync changes *SyncApi* | [**sendSyncAck**](doc//SyncApi.md#sendsyncack) | **POST** /sync/ack | Acknowledge changes @@ -352,8 +348,6 @@ Class | Method | HTTP request | Description - [AssetBulkUploadCheckResponseDto](doc//AssetBulkUploadCheckResponseDto.md) - [AssetBulkUploadCheckResult](doc//AssetBulkUploadCheckResult.md) - [AssetCopyDto](doc//AssetCopyDto.md) - - [AssetDeltaSyncDto](doc//AssetDeltaSyncDto.md) - - [AssetDeltaSyncResponseDto](doc//AssetDeltaSyncResponseDto.md) - [AssetEditAction](doc//AssetEditAction.md) - [AssetEditActionItemDto](doc//AssetEditActionItemDto.md) - [AssetEditActionItemDtoParameters](doc//AssetEditActionItemDtoParameters.md) @@ -366,7 +360,6 @@ Class | Method | HTTP request | Description - [AssetFaceUpdateDto](doc//AssetFaceUpdateDto.md) - [AssetFaceUpdateItem](doc//AssetFaceUpdateItem.md) - [AssetFaceWithoutPersonResponseDto](doc//AssetFaceWithoutPersonResponseDto.md) - - [AssetFullSyncDto](doc//AssetFullSyncDto.md) - [AssetIdErrorReason](doc//AssetIdErrorReason.md) - [AssetIdsDto](doc//AssetIdsDto.md) - [AssetIdsResponseDto](doc//AssetIdsResponseDto.md) diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 9403852ef0..b64f222791 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -94,8 +94,6 @@ part 'model/asset_bulk_upload_check_item.dart'; part 'model/asset_bulk_upload_check_response_dto.dart'; part 'model/asset_bulk_upload_check_result.dart'; part 'model/asset_copy_dto.dart'; -part 'model/asset_delta_sync_dto.dart'; -part 'model/asset_delta_sync_response_dto.dart'; part 'model/asset_edit_action.dart'; part 'model/asset_edit_action_item_dto.dart'; part 'model/asset_edit_action_item_dto_parameters.dart'; @@ -108,7 +106,6 @@ part 'model/asset_face_response_dto.dart'; part 'model/asset_face_update_dto.dart'; part 'model/asset_face_update_item.dart'; part 'model/asset_face_without_person_response_dto.dart'; -part 'model/asset_full_sync_dto.dart'; part 'model/asset_id_error_reason.dart'; part 'model/asset_ids_dto.dart'; part 'model/asset_ids_response_dto.dart'; diff --git a/mobile/openapi/lib/api/deprecated_api.dart b/mobile/openapi/lib/api/deprecated_api.dart index a292c176fd..5fa5df88b6 100644 --- a/mobile/openapi/lib/api/deprecated_api.dart +++ b/mobile/openapi/lib/api/deprecated_api.dart @@ -135,121 +135,6 @@ class DeprecatedApi { return null; } - /// Get delta sync for user - /// - /// Retrieve changed assets since the last sync for the authenticated user. - /// - /// Note: This method returns the HTTP [Response]. - /// - /// Parameters: - /// - /// * [AssetDeltaSyncDto] assetDeltaSyncDto (required): - Future getDeltaSyncWithHttpInfo(AssetDeltaSyncDto assetDeltaSyncDto,) async { - // ignore: prefer_const_declarations - final apiPath = r'/sync/delta-sync'; - - // ignore: prefer_final_locals - Object? postBody = assetDeltaSyncDto; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = ['application/json']; - - - return apiClient.invokeAPI( - apiPath, - 'POST', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Get delta sync for user - /// - /// Retrieve changed assets since the last sync for the authenticated user. - /// - /// Parameters: - /// - /// * [AssetDeltaSyncDto] assetDeltaSyncDto (required): - Future getDeltaSync(AssetDeltaSyncDto assetDeltaSyncDto,) async { - final response = await getDeltaSyncWithHttpInfo(assetDeltaSyncDto,); - 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) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetDeltaSyncResponseDto',) as AssetDeltaSyncResponseDto; - - } - return null; - } - - /// Get full sync for user - /// - /// Retrieve all assets for a full synchronization for the authenticated user. - /// - /// Note: This method returns the HTTP [Response]. - /// - /// Parameters: - /// - /// * [AssetFullSyncDto] assetFullSyncDto (required): - Future getFullSyncForUserWithHttpInfo(AssetFullSyncDto assetFullSyncDto,) async { - // ignore: prefer_const_declarations - final apiPath = r'/sync/full-sync'; - - // ignore: prefer_final_locals - Object? postBody = assetFullSyncDto; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = ['application/json']; - - - return apiClient.invokeAPI( - apiPath, - 'POST', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Get full sync for user - /// - /// Retrieve all assets for a full synchronization for the authenticated user. - /// - /// Parameters: - /// - /// * [AssetFullSyncDto] assetFullSyncDto (required): - Future?> getFullSyncForUser(AssetFullSyncDto assetFullSyncDto,) async { - final response = await getFullSyncForUserWithHttpInfo(assetFullSyncDto,); - 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; - } - /// Retrieve queue counts and status /// /// Retrieve the counts of the current queue, as well as the current status. diff --git a/mobile/openapi/lib/api/sync_api.dart b/mobile/openapi/lib/api/sync_api.dart index 6194fd0f89..e7bc822ace 100644 --- a/mobile/openapi/lib/api/sync_api.dart +++ b/mobile/openapi/lib/api/sync_api.dart @@ -64,121 +64,6 @@ class SyncApi { } } - /// Get delta sync for user - /// - /// Retrieve changed assets since the last sync for the authenticated user. - /// - /// Note: This method returns the HTTP [Response]. - /// - /// Parameters: - /// - /// * [AssetDeltaSyncDto] assetDeltaSyncDto (required): - Future getDeltaSyncWithHttpInfo(AssetDeltaSyncDto assetDeltaSyncDto,) async { - // ignore: prefer_const_declarations - final apiPath = r'/sync/delta-sync'; - - // ignore: prefer_final_locals - Object? postBody = assetDeltaSyncDto; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = ['application/json']; - - - return apiClient.invokeAPI( - apiPath, - 'POST', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Get delta sync for user - /// - /// Retrieve changed assets since the last sync for the authenticated user. - /// - /// Parameters: - /// - /// * [AssetDeltaSyncDto] assetDeltaSyncDto (required): - Future getDeltaSync(AssetDeltaSyncDto assetDeltaSyncDto,) async { - final response = await getDeltaSyncWithHttpInfo(assetDeltaSyncDto,); - 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) { - return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetDeltaSyncResponseDto',) as AssetDeltaSyncResponseDto; - - } - return null; - } - - /// Get full sync for user - /// - /// Retrieve all assets for a full synchronization for the authenticated user. - /// - /// Note: This method returns the HTTP [Response]. - /// - /// Parameters: - /// - /// * [AssetFullSyncDto] assetFullSyncDto (required): - Future getFullSyncForUserWithHttpInfo(AssetFullSyncDto assetFullSyncDto,) async { - // ignore: prefer_const_declarations - final apiPath = r'/sync/full-sync'; - - // ignore: prefer_final_locals - Object? postBody = assetFullSyncDto; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = ['application/json']; - - - return apiClient.invokeAPI( - apiPath, - 'POST', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - /// Get full sync for user - /// - /// Retrieve all assets for a full synchronization for the authenticated user. - /// - /// Parameters: - /// - /// * [AssetFullSyncDto] assetFullSyncDto (required): - Future?> getFullSyncForUser(AssetFullSyncDto assetFullSyncDto,) async { - final response = await getFullSyncForUserWithHttpInfo(assetFullSyncDto,); - 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; - } - /// Retrieve acknowledgements /// /// Retrieve the synchronization acknowledgments for the current session. diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 3ed1f7529f..c54a7bafa8 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -234,10 +234,6 @@ class ApiClient { return AssetBulkUploadCheckResult.fromJson(value); case 'AssetCopyDto': return AssetCopyDto.fromJson(value); - case 'AssetDeltaSyncDto': - return AssetDeltaSyncDto.fromJson(value); - case 'AssetDeltaSyncResponseDto': - return AssetDeltaSyncResponseDto.fromJson(value); case 'AssetEditAction': return AssetEditActionTypeTransformer().decode(value); case 'AssetEditActionItemDto': @@ -262,8 +258,6 @@ class ApiClient { return AssetFaceUpdateItem.fromJson(value); case 'AssetFaceWithoutPersonResponseDto': return AssetFaceWithoutPersonResponseDto.fromJson(value); - case 'AssetFullSyncDto': - return AssetFullSyncDto.fromJson(value); case 'AssetIdErrorReason': return AssetIdErrorReasonTypeTransformer().decode(value); case 'AssetIdsDto': diff --git a/mobile/openapi/lib/model/asset_delta_sync_dto.dart b/mobile/openapi/lib/model/asset_delta_sync_dto.dart deleted file mode 100644 index f59cdc1a67..0000000000 --- a/mobile/openapi/lib/model/asset_delta_sync_dto.dart +++ /dev/null @@ -1,113 +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 AssetDeltaSyncDto { - /// Returns a new [AssetDeltaSyncDto] instance. - AssetDeltaSyncDto({ - required this.updatedAfter, - this.userIds = const [], - }); - - /// Sync assets updated after this date - DateTime updatedAfter; - - /// User IDs to sync - List userIds; - - @override - bool operator ==(Object other) => identical(this, other) || other is AssetDeltaSyncDto && - other.updatedAfter == updatedAfter && - _deepEquality.equals(other.userIds, userIds); - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (updatedAfter.hashCode) + - (userIds.hashCode); - - @override - String toString() => 'AssetDeltaSyncDto[updatedAfter=$updatedAfter, userIds=$userIds]'; - - Map toJson() { - final json = {}; - json[r'updatedAfter'] = _isEpochMarker(r'/^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$/') - ? this.updatedAfter.millisecondsSinceEpoch - : this.updatedAfter.toUtc().toIso8601String(); - json[r'userIds'] = this.userIds; - return json; - } - - /// Returns a new [AssetDeltaSyncDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static AssetDeltaSyncDto? fromJson(dynamic value) { - upgradeDto(value, "AssetDeltaSyncDto"); - if (value is Map) { - final json = value.cast(); - - return AssetDeltaSyncDto( - updatedAfter: mapDateTime(json, r'updatedAfter', r'/^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$/')!, - userIds: json[r'userIds'] is Iterable - ? (json[r'userIds'] as Iterable).cast().toList(growable: false) - : const [], - ); - } - 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 = AssetDeltaSyncDto.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 = AssetDeltaSyncDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of AssetDeltaSyncDto-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] = AssetDeltaSyncDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'updatedAfter', - 'userIds', - }; -} - diff --git a/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart b/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart deleted file mode 100644 index 348bae370b..0000000000 --- a/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart +++ /dev/null @@ -1,119 +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 AssetDeltaSyncResponseDto { - /// Returns a new [AssetDeltaSyncResponseDto] instance. - AssetDeltaSyncResponseDto({ - this.deleted = const [], - required this.needsFullSync, - this.upserted = const [], - }); - - /// Deleted asset IDs - List deleted; - - /// Whether full sync is needed - bool needsFullSync; - - List upserted; - - @override - bool operator ==(Object other) => identical(this, other) || other is AssetDeltaSyncResponseDto && - _deepEquality.equals(other.deleted, deleted) && - other.needsFullSync == needsFullSync && - _deepEquality.equals(other.upserted, upserted); - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (deleted.hashCode) + - (needsFullSync.hashCode) + - (upserted.hashCode); - - @override - String toString() => 'AssetDeltaSyncResponseDto[deleted=$deleted, needsFullSync=$needsFullSync, upserted=$upserted]'; - - Map toJson() { - final json = {}; - json[r'deleted'] = this.deleted; - json[r'needsFullSync'] = this.needsFullSync; - json[r'upserted'] = this.upserted; - return json; - } - - /// Returns a new [AssetDeltaSyncResponseDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static AssetDeltaSyncResponseDto? fromJson(dynamic value) { - upgradeDto(value, "AssetDeltaSyncResponseDto"); - if (value is Map) { - final json = value.cast(); - - return AssetDeltaSyncResponseDto( - deleted: json[r'deleted'] is Iterable - ? (json[r'deleted'] as Iterable).cast().toList(growable: false) - : const [], - needsFullSync: mapValueOfType(json, r'needsFullSync')!, - upserted: AssetResponseDto.listFromJson(json[r'upserted']), - ); - } - 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 = AssetDeltaSyncResponseDto.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 = AssetDeltaSyncResponseDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of AssetDeltaSyncResponseDto-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] = AssetDeltaSyncResponseDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'deleted', - 'needsFullSync', - 'upserted', - }; -} - diff --git a/mobile/openapi/lib/model/asset_full_sync_dto.dart b/mobile/openapi/lib/model/asset_full_sync_dto.dart deleted file mode 100644 index 835e063e92..0000000000 --- a/mobile/openapi/lib/model/asset_full_sync_dto.dart +++ /dev/null @@ -1,150 +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 AssetFullSyncDto { - /// Returns a new [AssetFullSyncDto] instance. - AssetFullSyncDto({ - this.lastId, - required this.limit, - required this.updatedUntil, - this.userId, - }); - - /// Last asset ID (pagination) - /// - /// Please note: This property should have been non-nullable! Since the specification file - /// does not include a default value (using the "default:" property), however, the generated - /// source code must fall back to having a nullable type. - /// Consider adding a "default:" property in the specification file to hide this note. - /// - String? lastId; - - /// Maximum number of assets to return - /// - /// Minimum value: 1 - /// Maximum value: 9007199254740991 - int limit; - - /// Sync assets updated until this date - DateTime updatedUntil; - - /// Filter by user ID - /// - /// Please note: This property should have been non-nullable! Since the specification file - /// does not include a default value (using the "default:" property), however, the generated - /// source code must fall back to having a nullable type. - /// Consider adding a "default:" property in the specification file to hide this note. - /// - String? userId; - - @override - bool operator ==(Object other) => identical(this, other) || other is AssetFullSyncDto && - other.lastId == lastId && - other.limit == limit && - other.updatedUntil == updatedUntil && - other.userId == userId; - - @override - int get hashCode => - // ignore: unnecessary_parenthesis - (lastId == null ? 0 : lastId!.hashCode) + - (limit.hashCode) + - (updatedUntil.hashCode) + - (userId == null ? 0 : userId!.hashCode); - - @override - String toString() => 'AssetFullSyncDto[lastId=$lastId, limit=$limit, updatedUntil=$updatedUntil, userId=$userId]'; - - Map toJson() { - final json = {}; - if (this.lastId != null) { - json[r'lastId'] = this.lastId; - } else { - // json[r'lastId'] = null; - } - json[r'limit'] = this.limit; - json[r'updatedUntil'] = _isEpochMarker(r'/^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$/') - ? this.updatedUntil.millisecondsSinceEpoch - : this.updatedUntil.toUtc().toIso8601String(); - if (this.userId != null) { - json[r'userId'] = this.userId; - } else { - // json[r'userId'] = null; - } - return json; - } - - /// Returns a new [AssetFullSyncDto] instance and imports its values from - /// [value] if it's a [Map], null otherwise. - // ignore: prefer_constructors_over_static_methods - static AssetFullSyncDto? fromJson(dynamic value) { - upgradeDto(value, "AssetFullSyncDto"); - if (value is Map) { - final json = value.cast(); - - return AssetFullSyncDto( - lastId: mapValueOfType(json, r'lastId'), - limit: mapValueOfType(json, r'limit')!, - updatedUntil: mapDateTime(json, r'updatedUntil', r'/^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$/')!, - userId: mapValueOfType(json, r'userId'), - ); - } - 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 = AssetFullSyncDto.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 = AssetFullSyncDto.fromJson(entry.value); - if (value != null) { - map[entry.key] = value; - } - } - } - return map; - } - - // maps a json object with a list of AssetFullSyncDto-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] = AssetFullSyncDto.listFromJson(entry.value, growable: growable,); - } - } - return map; - } - - /// The list of required keys that must be present in a JSON. - static const requiredKeys = { - 'limit', - 'updatedUntil', - }; -} - diff --git a/mobile/openapi/lib/model/job_name.dart b/mobile/openapi/lib/model/job_name.dart index 96b9339b7d..08f70569f8 100644 --- a/mobile/openapi/lib/model/job_name.dart +++ b/mobile/openapi/lib/model/job_name.dart @@ -38,7 +38,6 @@ class JobName { static const assetFileMigration = JobName._(r'AssetFileMigration'); static const assetGenerateThumbnailsQueueAll = JobName._(r'AssetGenerateThumbnailsQueueAll'); static const assetGenerateThumbnails = JobName._(r'AssetGenerateThumbnails'); - static const auditLogCleanup = JobName._(r'AuditLogCleanup'); static const auditTableCleanup = JobName._(r'AuditTableCleanup'); static const databaseBackup = JobName._(r'DatabaseBackup'); static const facialRecognitionQueueAll = JobName._(r'FacialRecognitionQueueAll'); @@ -97,7 +96,6 @@ class JobName { assetFileMigration, assetGenerateThumbnailsQueueAll, assetGenerateThumbnails, - auditLogCleanup, auditTableCleanup, databaseBackup, facialRecognitionQueueAll, @@ -191,7 +189,6 @@ class JobNameTypeTransformer { case r'AssetFileMigration': return JobName.assetFileMigration; case r'AssetGenerateThumbnailsQueueAll': return JobName.assetGenerateThumbnailsQueueAll; case r'AssetGenerateThumbnails': return JobName.assetGenerateThumbnails; - case r'AuditLogCleanup': return JobName.auditLogCleanup; case r'AuditTableCleanup': return JobName.auditTableCleanup; case r'DatabaseBackup': return JobName.databaseBackup; case r'FacialRecognitionQueueAll': return JobName.facialRecognitionQueueAll; diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 8eb172c1fb..1b2e6af587 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -12294,123 +12294,6 @@ "x-immich-state": "Stable" } }, - "/sync/delta-sync": { - "post": { - "deprecated": true, - "description": "Retrieve changed assets since the last sync for the authenticated user.", - "operationId": "getDeltaSync", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AssetDeltaSyncDto" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AssetDeltaSyncResponseDto" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "summary": "Get delta sync for user", - "tags": [ - "Sync", - "Deprecated" - ], - "x-immich-history": [ - { - "version": "v1", - "state": "Added" - }, - { - "version": "v2", - "state": "Deprecated" - } - ], - "x-immich-state": "Deprecated" - } - }, - "/sync/full-sync": { - "post": { - "deprecated": true, - "description": "Retrieve all assets for a full synchronization for the authenticated user.", - "operationId": "getFullSyncForUser", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AssetFullSyncDto" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/AssetResponseDto" - }, - "type": "array" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "summary": "Get full sync for user", - "tags": [ - "Sync", - "Deprecated" - ], - "x-immich-history": [ - { - "version": "v1", - "state": "Added" - }, - { - "version": "v2", - "state": "Deprecated" - } - ], - "x-immich-state": "Deprecated" - } - }, "/sync/stream": { "post": { "description": "Retrieve a JSON lines streamed response of changes for synchronization. This endpoint is used by the mobile app to efficiently stay up to date with changes.", @@ -16031,59 +15914,6 @@ ], "type": "object" }, - "AssetDeltaSyncDto": { - "properties": { - "updatedAfter": { - "description": "Sync assets updated after this date", - "example": "2024-01-01T00:00:00.000Z", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", - "type": "string" - }, - "userIds": { - "description": "User IDs to sync", - "items": { - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$", - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "updatedAfter", - "userIds" - ], - "type": "object" - }, - "AssetDeltaSyncResponseDto": { - "description": "Asset delta sync response", - "properties": { - "deleted": { - "description": "Deleted asset IDs", - "items": { - "type": "string" - }, - "type": "array" - }, - "needsFullSync": { - "description": "Whether full sync is needed", - "type": "boolean" - }, - "upserted": { - "items": { - "$ref": "#/components/schemas/AssetResponseDto" - }, - "type": "array" - } - }, - "required": [ - "deleted", - "needsFullSync", - "upserted" - ], - "type": "object" - }, "AssetEditAction": { "description": "Type of edit action to perform", "enum": [ @@ -16429,40 +16259,6 @@ ], "type": "object" }, - "AssetFullSyncDto": { - "properties": { - "lastId": { - "description": "Last asset ID (pagination)", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$", - "type": "string" - }, - "limit": { - "description": "Maximum number of assets to return", - "maximum": 9007199254740991, - "minimum": 1, - "type": "integer" - }, - "updatedUntil": { - "description": "Sync assets updated until this date", - "example": "2024-01-01T00:00:00.000Z", - "format": "date-time", - "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", - "type": "string" - }, - "userId": { - "description": "Filter by user ID", - "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$", - "type": "string" - } - }, - "required": [ - "limit", - "updatedUntil" - ], - "type": "object" - }, "AssetIdErrorReason": { "description": "Error reason if failed", "enum": [ @@ -18207,7 +18003,6 @@ "AssetFileMigration", "AssetGenerateThumbnailsQueueAll", "AssetGenerateThumbnails", - "AuditLogCleanup", "AuditTableCleanup", "DatabaseBackup", "FacialRecognitionQueueAll", diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index de6e2383e9..a452d86b8c 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -2321,29 +2321,6 @@ export type SyncAckSetDto = { /** Acknowledgment IDs (max 1000) */ acks: string[]; }; -export type AssetDeltaSyncDto = { - /** Sync assets updated after this date */ - updatedAfter: string; - /** User IDs to sync */ - userIds: string[]; -}; -export type AssetDeltaSyncResponseDto = { - /** Deleted asset IDs */ - deleted: string[]; - /** Whether full sync is needed */ - needsFullSync: boolean; - upserted: AssetResponseDto[]; -}; -export type AssetFullSyncDto = { - /** Last asset ID (pagination) */ - lastId?: string; - /** Maximum number of assets to return */ - limit: number; - /** Sync assets updated until this date */ - updatedUntil: string; - /** Filter by user ID */ - userId?: string; -}; export type SyncStreamDto = { /** Reset sync state */ reset?: boolean; @@ -6094,36 +6071,6 @@ export function sendSyncAck({ syncAckSetDto }: { body: syncAckSetDto }))); } -/** - * Get delta sync for user - */ -export function getDeltaSync({ assetDeltaSyncDto }: { - assetDeltaSyncDto: AssetDeltaSyncDto; -}, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: AssetDeltaSyncResponseDto; - }>("/sync/delta-sync", oazapfts.json({ - ...opts, - method: "POST", - body: assetDeltaSyncDto - }))); -} -/** - * Get full sync for user - */ -export function getFullSyncForUser({ assetFullSyncDto }: { - assetFullSyncDto: AssetFullSyncDto; -}, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: AssetResponseDto[]; - }>("/sync/full-sync", oazapfts.json({ - ...opts, - method: "POST", - body: assetFullSyncDto - }))); -} /** * Stream sync changes */ @@ -7120,7 +7067,6 @@ export enum JobName { AssetFileMigration = "AssetFileMigration", AssetGenerateThumbnailsQueueAll = "AssetGenerateThumbnailsQueueAll", AssetGenerateThumbnails = "AssetGenerateThumbnails", - AuditLogCleanup = "AuditLogCleanup", AuditTableCleanup = "AuditTableCleanup", DatabaseBackup = "DatabaseBackup", FacialRecognitionQueueAll = "FacialRecognitionQueueAll", diff --git a/server/src/controllers/sync.controller.ts b/server/src/controllers/sync.controller.ts index de94738f73..c9f3fa7825 100644 --- a/server/src/controllers/sync.controller.ts +++ b/server/src/controllers/sync.controller.ts @@ -2,17 +2,8 @@ import { Body, Controller, Delete, Get, Header, HttpCode, HttpStatus, Post, Res import { ApiTags } from '@nestjs/swagger'; import { Response } from 'express'; import { Endpoint, HistoryBuilder } from 'src/decorators'; -import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { - AssetDeltaSyncDto, - AssetDeltaSyncResponseDto, - AssetFullSyncDto, - SyncAckDeleteDto, - SyncAckDto, - SyncAckSetDto, - SyncStreamDto, -} from 'src/dtos/sync.dto'; +import { SyncAckDeleteDto, SyncAckDto, SyncAckSetDto, SyncStreamDto } from 'src/dtos/sync.dto'; import { ApiTag, Permission } from 'src/enum'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { GlobalExceptionFilter } from 'src/middleware/global-exception.filter'; @@ -26,30 +17,6 @@ export class SyncController { private errorService: GlobalExceptionFilter, ) {} - @Post('full-sync') - @Authenticated() - @HttpCode(HttpStatus.OK) - @Endpoint({ - summary: 'Get full sync for user', - description: 'Retrieve all assets for a full synchronization for the authenticated user.', - history: new HistoryBuilder().added('v1').deprecated('v2'), - }) - getFullSyncForUser(@Auth() auth: AuthDto, @Body() dto: AssetFullSyncDto): Promise { - return this.service.getFullSync(auth, dto); - } - - @Post('delta-sync') - @Authenticated() - @HttpCode(HttpStatus.OK) - @Endpoint({ - summary: 'Get delta sync for user', - description: 'Retrieve changed assets since the last sync for the authenticated user.', - history: new HistoryBuilder().added('v1').deprecated('v2'), - }) - getDeltaSync(@Auth() auth: AuthDto, @Body() dto: AssetDeltaSyncDto): Promise { - return this.service.getDeltaSync(auth, dto); - } - @Post('stream') @Authenticated({ permission: Permission.SyncStream }) @Header('Content-Type', 'application/jsonlines+json') diff --git a/server/src/dtos/sync.dto.ts b/server/src/dtos/sync.dto.ts index d7903ebb0c..f6383d0a5d 100644 --- a/server/src/dtos/sync.dto.ts +++ b/server/src/dtos/sync.dto.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-unsafe-function-type */ import { createZodDto } from 'nestjs-zod'; -import { AssetResponseSchema } from 'src/dtos/asset-response.dto'; import { AssetEditActionSchema } from 'src/dtos/editing.dto'; import { AlbumUserRoleSchema, @@ -17,36 +16,6 @@ import { import { isoDatetimeToDate } from 'src/validation'; import z from 'zod'; -const AssetFullSyncSchema = z - .object({ - lastId: z.uuidv4().optional().describe('Last asset ID (pagination)'), - updatedUntil: isoDatetimeToDate.describe('Sync assets updated until this date'), - limit: z.int().min(1).describe('Maximum number of assets to return'), - userId: z.uuidv4().optional().describe('Filter by user ID'), - }) - .meta({ id: 'AssetFullSyncDto' }); - -const AssetDeltaSyncSchema = z - .object({ - updatedAfter: isoDatetimeToDate.describe('Sync assets updated after this date'), - userIds: z.array(z.uuidv4()).describe('User IDs to sync'), - }) - .meta({ id: 'AssetDeltaSyncDto' }); - -export class AssetFullSyncDto extends createZodDto(AssetFullSyncSchema) {} -export class AssetDeltaSyncDto extends createZodDto(AssetDeltaSyncSchema) {} - -const AssetDeltaSyncResponseSchema = z - .object({ - needsFullSync: z.boolean().describe('Whether full sync is needed'), - upserted: z.array(AssetResponseSchema), - deleted: z.array(z.string()).describe('Deleted asset IDs'), - }) - .describe('Asset delta sync response') - .meta({ id: 'AssetDeltaSyncResponseDto' }); - -export class AssetDeltaSyncResponseDto extends createZodDto(AssetDeltaSyncResponseSchema) {} - export const extraSyncModels: Function[] = []; const ExtraModel = (): ClassDecorator => { diff --git a/server/src/enum.ts b/server/src/enum.ts index 067b5435e4..08d710e08c 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -88,21 +88,6 @@ export enum AssetOrder { export const AssetOrderSchema = z.enum(AssetOrder).describe('Asset sort order').meta({ id: 'AssetOrder' }); -export enum DatabaseAction { - Create = 'CREATE', - Update = 'UPDATE', - Delete = 'DELETE', -} - -export const DatabaseActionSchema = z.enum(DatabaseAction).describe('Database action').meta({ id: 'DatabaseAction' }); - -export enum EntityType { - Asset = 'ASSET', - Album = 'ALBUM', -} - -export const EntityTypeSchema = z.enum(EntityType).describe('Entity type').meta({ id: 'EntityType' }); - export enum MemoryType { /** pictures taken on this day X years ago */ OnThisDay = 'on_this_day', @@ -761,7 +746,6 @@ export enum JobName { AssetGenerateThumbnailsQueueAll = 'AssetGenerateThumbnailsQueueAll', AssetGenerateThumbnails = 'AssetGenerateThumbnails', - AuditLogCleanup = 'AuditLogCleanup', AuditTableCleanup = 'AuditTableCleanup', DatabaseBackup = 'DatabaseBackup', diff --git a/server/src/queries/asset.repository.sql b/server/src/queries/asset.repository.sql index a68fde2b93..88cd9c08d5 100644 --- a/server/src/queries/asset.repository.sql +++ b/server/src/queries/asset.repository.sql @@ -497,63 +497,6 @@ where limit $5 --- AssetRepository.getAllForUserFullSync -select - "asset".*, - to_json("asset_exif") as "exifInfo", - to_json("stacked_assets") as "stack" -from - "asset" - left join "asset_exif" on "asset"."id" = "asset_exif"."assetId" - left join "stack" on "stack"."id" = "asset"."stackId" - left join lateral ( - select - "stack".*, - count("stacked") as "assetCount" - from - "asset" as "stacked" - where - "stacked"."stackId" = "stack"."id" - group by - "stack"."id" - ) as "stacked_assets" on "stack"."id" is not null -where - "asset"."ownerId" = $1::uuid - and "asset"."visibility" != $2 - and "asset"."updatedAt" <= $3 - and "asset"."id" > $4 -order by - "asset"."id" -limit - $5 - --- AssetRepository.getChangedDeltaSync -select - "asset".*, - to_json("asset_exif") as "exifInfo", - to_json("stacked_assets") as "stack" -from - "asset" - left join "asset_exif" on "asset"."id" = "asset_exif"."assetId" - left join "stack" on "stack"."id" = "asset"."stackId" - left join lateral ( - select - "stack".*, - count("stacked") as "assetCount" - from - "asset" as "stacked" - where - "stacked"."stackId" = "stack"."id" - group by - "stack"."id" - ) as "stacked_assets" on "stack"."id" is not null -where - "asset"."ownerId" = any ($1::uuid[]) - and "asset"."visibility" != $2 - and "asset"."updatedAt" > $3 -limit - $4 - -- AssetRepository.detectOfflineExternalAssets update "asset" set diff --git a/server/src/queries/audit.repository.sql b/server/src/queries/audit.repository.sql deleted file mode 100644 index b1a10abf48..0000000000 --- a/server/src/queries/audit.repository.sql +++ /dev/null @@ -1,16 +0,0 @@ --- NOTE: This file is auto generated by ./sql-generator - --- AuditRepository.getAfter -select distinct - on ("audit"."entityId", "audit"."entityType") "audit"."entityId" -from - "audit" -where - "audit"."createdAt" > $1 - and "audit"."action" = $2 - and "audit"."entityType" = $3 - and "audit"."ownerId" in ($4) -order by - "audit"."entityId" desc, - "audit"."entityType" desc, - "audit"."createdAt" desc diff --git a/server/src/repositories/asset.repository.ts b/server/src/repositories/asset.repository.ts index 932f72daae..686a0345a4 100644 --- a/server/src/repositories/asset.repository.ts +++ b/server/src/repositories/asset.repository.ts @@ -106,19 +106,6 @@ interface AssetExploreFieldOptions { minAssetsPerField: number; } -interface AssetFullSyncOptions { - ownerId: string; - lastId?: string; - updatedUntil: Date; - limit: number; -} - -interface AssetDeltaSyncOptions { - userIds: string[]; - updatedAfter: Date; - limit: number; -} - interface AssetGetByChecksumOptions { ownerId: string; checksum: Buffer; @@ -905,70 +892,6 @@ export class AssetRepository { return { fieldName: 'exifInfo.city', items }; } - @GenerateSql({ - params: [ - { - ownerId: DummyValue.UUID, - lastId: DummyValue.UUID, - updatedUntil: DummyValue.DATE, - limit: 10, - }, - ], - }) - getAllForUserFullSync(options: AssetFullSyncOptions) { - const { ownerId, lastId, updatedUntil, limit } = options; - return this.db - .selectFrom('asset') - .selectAll('asset') - .$call(withExif) - .leftJoin('stack', 'stack.id', 'asset.stackId') - .leftJoinLateral( - (eb) => - eb - .selectFrom('asset as stacked') - .selectAll('stack') - .select((eb) => eb.fn.count(eb.table('stacked')).as('assetCount')) - .whereRef('stacked.stackId', '=', 'stack.id') - .groupBy('stack.id') - .as('stacked_assets'), - (join) => join.on('stack.id', 'is not', null), - ) - .select((eb) => eb.fn.toJson(eb.table('stacked_assets')).$castTo().as('stack')) - .where('asset.ownerId', '=', asUuid(ownerId)) - .where('asset.visibility', '!=', AssetVisibility.Hidden) - .where('asset.updatedAt', '<=', updatedUntil) - .$if(!!lastId, (qb) => qb.where('asset.id', '>', lastId!)) - .orderBy('asset.id') - .limit(limit) - .execute(); - } - - @GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE, limit: 100 }] }) - async getChangedDeltaSync(options: AssetDeltaSyncOptions) { - return this.db - .selectFrom('asset') - .selectAll('asset') - .$call(withExif) - .leftJoin('stack', 'stack.id', 'asset.stackId') - .leftJoinLateral( - (eb) => - eb - .selectFrom('asset as stacked') - .selectAll('stack') - .select((eb) => eb.fn.count(eb.table('stacked')).as('assetCount')) - .whereRef('stacked.stackId', '=', 'stack.id') - .groupBy('stack.id') - .as('stacked_assets'), - (join) => join.on('stack.id', 'is not', null), - ) - .select((eb) => eb.fn.toJson(eb.table('stacked_assets').$castTo()).as('stack')) - .where('asset.ownerId', '=', anyUuid(options.userIds)) - .where('asset.visibility', '!=', AssetVisibility.Hidden) - .where('asset.updatedAt', '>', options.updatedAfter) - .limit(options.limit) - .execute(); - } - async upsertFile( file: Pick< Insertable, diff --git a/server/src/repositories/audit.repository.ts b/server/src/repositories/audit.repository.ts deleted file mode 100644 index 2d56eddc9a..0000000000 --- a/server/src/repositories/audit.repository.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { Kysely } from 'kysely'; -import { InjectKysely } from 'nestjs-kysely'; -import { DummyValue, GenerateSql } from 'src/decorators'; -import { DatabaseAction, EntityType } from 'src/enum'; -import { DB } from 'src/schema'; - -export interface AuditSearch { - action?: DatabaseAction; - entityType?: EntityType; - userIds: string[]; -} - -@Injectable() -export class AuditRepository { - constructor(@InjectKysely() private db: Kysely) {} - - @GenerateSql({ - params: [ - DummyValue.DATE, - { action: DatabaseAction.Create, entityType: EntityType.Asset, userIds: [DummyValue.UUID] }, - ], - }) - async getAfter(since: Date, options: AuditSearch): Promise { - const records = await this.db - .selectFrom('audit') - .where('audit.createdAt', '>', since) - .$if(!!options.action, (qb) => qb.where('audit.action', '=', options.action!)) - .$if(!!options.entityType, (qb) => qb.where('audit.entityType', '=', options.entityType!)) - .where('audit.ownerId', 'in', options.userIds) - .distinctOn(['audit.entityId', 'audit.entityType']) - .orderBy('audit.entityId', 'desc') - .orderBy('audit.entityType', 'desc') - .orderBy('audit.createdAt', 'desc') - .select('audit.entityId') - .execute(); - - return records.map(({ entityId }) => entityId); - } - - async removeBefore(before: Date): Promise { - await this.db.deleteFrom('audit').where('createdAt', '<', before).execute(); - } -} diff --git a/server/src/repositories/index.ts b/server/src/repositories/index.ts index 361a2e7179..fcff171a5e 100644 --- a/server/src/repositories/index.ts +++ b/server/src/repositories/index.ts @@ -7,7 +7,6 @@ import { AppRepository } from 'src/repositories/app.repository'; import { AssetEditRepository } from 'src/repositories/asset-edit.repository'; import { AssetJobRepository } from 'src/repositories/asset-job.repository'; import { AssetRepository } from 'src/repositories/asset.repository'; -import { AuditRepository } from 'src/repositories/audit.repository'; import { ConfigRepository } from 'src/repositories/config.repository'; import { CronRepository } from 'src/repositories/cron.repository'; import { CryptoRepository } from 'src/repositories/crypto.repository'; @@ -56,7 +55,6 @@ export const repositories = [ ActivityRepository, AlbumRepository, AlbumUserRepository, - AuditRepository, ApiKeyRepository, AppRepository, AssetRepository, diff --git a/server/src/schema/index.ts b/server/src/schema/index.ts index 2426c2aab7..e3db3d01c7 100644 --- a/server/src/schema/index.ts +++ b/server/src/schema/index.ts @@ -40,7 +40,6 @@ import { AssetMetadataAuditTable } from 'src/schema/tables/asset-metadata-audit. import { AssetMetadataTable } from 'src/schema/tables/asset-metadata.table'; import { AssetOcrTable } from 'src/schema/tables/asset-ocr.table'; import { AssetTable } from 'src/schema/tables/asset.table'; -import { AuditTable } from 'src/schema/tables/audit.table'; import { FaceSearchTable } from 'src/schema/tables/face-search.table'; import { GeodataPlacesTable } from 'src/schema/tables/geodata-places.table'; import { LibraryTable } from 'src/schema/tables/library.table'; @@ -98,7 +97,6 @@ export class ImmichDatabase { AssetOcrTable, AssetTable, AssetFileTable, - AuditTable, AssetExifTable, FaceSearchTable, GeodataPlacesTable, @@ -197,8 +195,6 @@ export interface DB { asset_ocr: AssetOcrTable; ocr_search: OcrSearchTable; - audit: AuditTable; - face_search: FaceSearchTable; geodata_places: GeodataPlacesTable; diff --git a/server/src/schema/migrations/1776217577402-DropAuditTable.ts b/server/src/schema/migrations/1776217577402-DropAuditTable.ts new file mode 100644 index 0000000000..f7e968a3ed --- /dev/null +++ b/server/src/schema/migrations/1776217577402-DropAuditTable.ts @@ -0,0 +1,18 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await sql`DROP TABLE "audit";`.execute(db); +} + +export async function down(db: Kysely): Promise { + await sql`CREATE TABLE "audit" ( + "id" serial NOT NULL, + "entityType" character varying NOT NULL, + "entityId" uuid NOT NULL, + "action" character varying NOT NULL, + "ownerId" uuid NOT NULL, + "createdAt" timestamp with time zone NOT NULL DEFAULT now(), + CONSTRAINT "audit_pkey" PRIMARY KEY ("id") +);`.execute(db); + await sql`CREATE INDEX "audit_ownerId_createdAt_idx" ON "audit" ("ownerId", "createdAt");`.execute(db); +} diff --git a/server/src/schema/tables/audit.table.ts b/server/src/schema/tables/audit.table.ts deleted file mode 100644 index 78c9a57c09..0000000000 --- a/server/src/schema/tables/audit.table.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Column, CreateDateColumn, Generated, Index, PrimaryColumn, Table, Timestamp } from '@immich/sql-tools'; -import { DatabaseAction, EntityType } from 'src/enum'; - -@Table('audit') -@Index({ columns: ['ownerId', 'createdAt'] }) -export class AuditTable { - @PrimaryColumn({ type: 'serial', synchronize: false }) - id!: Generated; - - @Column() - entityType!: EntityType; - - @Column({ type: 'uuid' }) - entityId!: string; - - @Column() - action!: DatabaseAction; - - @Column({ type: 'uuid' }) - ownerId!: string; - - @CreateDateColumn() - createdAt!: Generated; -} diff --git a/server/src/services/audit.service.spec.ts b/server/src/services/audit.service.spec.ts deleted file mode 100644 index 7363ea74e1..0000000000 --- a/server/src/services/audit.service.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { JobStatus } from 'src/enum'; -import { AuditService } from 'src/services/audit.service'; -import { newTestService, ServiceMocks } from 'test/utils'; - -describe(AuditService.name, () => { - let sut: AuditService; - let mocks: ServiceMocks; - - beforeEach(() => { - ({ sut, mocks } = newTestService(AuditService)); - }); - - it('should work', () => { - expect(sut).toBeDefined(); - }); - - describe('handleCleanup', () => { - it('should delete old audit entries', async () => { - mocks.audit.removeBefore.mockResolvedValue(); - - await expect(sut.handleCleanup()).resolves.toBe(JobStatus.Success); - - expect(mocks.audit.removeBefore).toHaveBeenCalledWith(expect.any(Date)); - }); - }); -}); diff --git a/server/src/services/audit.service.ts b/server/src/services/audit.service.ts deleted file mode 100644 index 498d99b82c..0000000000 --- a/server/src/services/audit.service.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DateTime } from 'luxon'; -import { AUDIT_LOG_MAX_DURATION } from 'src/constants'; -import { OnJob } from 'src/decorators'; -import { JobName, JobStatus, QueueName } from 'src/enum'; -import { BaseService } from 'src/services/base.service'; - -@Injectable() -export class AuditService extends BaseService { - @OnJob({ name: JobName.AuditLogCleanup, queue: QueueName.BackgroundTask }) - async handleCleanup(): Promise { - await this.auditRepository.removeBefore(DateTime.now().minus(AUDIT_LOG_MAX_DURATION).toJSDate()); - return JobStatus.Success; - } -} diff --git a/server/src/services/base.service.ts b/server/src/services/base.service.ts index b3a50a07ae..4b02d6e944 100644 --- a/server/src/services/base.service.ts +++ b/server/src/services/base.service.ts @@ -14,7 +14,6 @@ import { AppRepository } from 'src/repositories/app.repository'; import { AssetEditRepository } from 'src/repositories/asset-edit.repository'; import { AssetJobRepository } from 'src/repositories/asset-job.repository'; import { AssetRepository } from 'src/repositories/asset.repository'; -import { AuditRepository } from 'src/repositories/audit.repository'; import { ConfigRepository } from 'src/repositories/config.repository'; import { CronRepository } from 'src/repositories/cron.repository'; import { CryptoRepository } from 'src/repositories/crypto.repository'; @@ -72,7 +71,6 @@ export const BASE_SERVICE_DEPENDENCIES = [ AssetRepository, AssetEditRepository, AssetJobRepository, - AuditRepository, ConfigRepository, CronRepository, CryptoRepository, @@ -131,7 +129,6 @@ export class BaseService { protected assetRepository: AssetRepository, protected assetEditRepository: AssetEditRepository, protected assetJobRepository: AssetJobRepository, - protected auditRepository: AuditRepository, protected configRepository: ConfigRepository, protected cronRepository: CronRepository, protected cryptoRepository: CryptoRepository, diff --git a/server/src/services/index.ts b/server/src/services/index.ts index ba54474b71..f4e82b13a4 100644 --- a/server/src/services/index.ts +++ b/server/src/services/index.ts @@ -4,7 +4,6 @@ import { ApiKeyService } from 'src/services/api-key.service'; import { ApiService } from 'src/services/api.service'; import { AssetMediaService } from 'src/services/asset-media.service'; import { AssetService } from 'src/services/asset.service'; -import { AuditService } from 'src/services/audit.service'; import { AuthAdminService } from 'src/services/auth-admin.service'; import { AuthService } from 'src/services/auth.service'; import { CliService } from 'src/services/cli.service'; @@ -54,7 +53,6 @@ export const services = [ ApiService, AssetMediaService, AssetService, - AuditService, AuthService, AuthAdminService, CliService, diff --git a/server/src/services/queue.service.spec.ts b/server/src/services/queue.service.spec.ts index 2c76fee877..d4c425e8bd 100644 --- a/server/src/services/queue.service.spec.ts +++ b/server/src/services/queue.service.spec.ts @@ -42,7 +42,6 @@ describe(QueueService.name, () => { { name: JobName.MemoryCleanup }, { name: JobName.SessionCleanup }, { name: JobName.AuditTableCleanup }, - { name: JobName.AuditLogCleanup }, { name: JobName.MemoryGenerate }, { name: JobName.UserSyncUsage }, { name: JobName.AssetGenerateThumbnailsQueueAll, data: { force: false } }, diff --git a/server/src/services/queue.service.ts b/server/src/services/queue.service.ts index 662ccbe618..ba6f4c5f3b 100644 --- a/server/src/services/queue.service.ts +++ b/server/src/services/queue.service.ts @@ -270,7 +270,6 @@ export class QueueService extends BaseService { { name: JobName.MemoryCleanup }, { name: JobName.SessionCleanup }, { name: JobName.AuditTableCleanup }, - { name: JobName.AuditLogCleanup }, ); } diff --git a/server/src/services/sync.service.spec.ts b/server/src/services/sync.service.spec.ts deleted file mode 100644 index 234e3ac223..0000000000 --- a/server/src/services/sync.service.spec.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { mapAsset } from 'src/dtos/asset-response.dto'; -import { SyncService } from 'src/services/sync.service'; -import { AssetFactory } from 'test/factories/asset.factory'; -import { PartnerFactory } from 'test/factories/partner.factory'; -import { authStub } from 'test/fixtures/auth.stub'; -import { getForAsset, getForPartner } from 'test/mappers'; -import { factory } from 'test/small.factory'; -import { newTestService, ServiceMocks } from 'test/utils'; - -const untilDate = new Date(2024); -const mapAssetOpts = { auth: authStub.user1, stripMetadata: false, withStack: true }; - -describe(SyncService.name, () => { - let sut: SyncService; - let mocks: ServiceMocks; - - beforeEach(() => { - ({ sut, mocks } = newTestService(SyncService)); - }); - - it('should exist', () => { - expect(sut).toBeDefined(); - }); - - describe('getAllAssetsForUserFullSync', () => { - it('should return a list of all assets owned by the user', async () => { - const [asset1, asset2] = [ - AssetFactory.from({ libraryId: 'library-id', isExternal: true }).owner(authStub.user1.user).build(), - AssetFactory.from().owner(authStub.user1.user).build(), - ]; - mocks.asset.getAllForUserFullSync.mockResolvedValue([getForAsset(asset1), getForAsset(asset2)]); - await expect(sut.getFullSync(authStub.user1, { limit: 2, updatedUntil: untilDate })).resolves.toEqual([ - mapAsset(getForAsset(asset1), mapAssetOpts), - mapAsset(getForAsset(asset2), mapAssetOpts), - ]); - expect(mocks.asset.getAllForUserFullSync).toHaveBeenCalledWith({ - ownerId: authStub.user1.user.id, - updatedUntil: untilDate, - limit: 2, - }); - }); - }); - - describe('getChangesForDeltaSync', () => { - it('should return a response requiring a full sync when partners are out of sync', async () => { - const partner = PartnerFactory.create(); - const auth = factory.auth({ user: { id: partner.sharedWithId } }); - - mocks.partner.getAll.mockResolvedValue([getForPartner(partner)]); - - await expect( - sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [auth.user.id] }), - ).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] }); - - expect(mocks.asset.getChangedDeltaSync).toHaveBeenCalledTimes(0); - expect(mocks.audit.getAfter).toHaveBeenCalledTimes(0); - }); - - it('should return a response requiring a full sync when last sync was too long ago', async () => { - mocks.partner.getAll.mockResolvedValue([]); - await expect( - sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(2000), userIds: [authStub.user1.user.id] }), - ).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] }); - expect(mocks.asset.getChangedDeltaSync).toHaveBeenCalledTimes(0); - expect(mocks.audit.getAfter).toHaveBeenCalledTimes(0); - }); - - it('should return a response requiring a full sync when there are too many changes', async () => { - const asset = AssetFactory.create(); - mocks.partner.getAll.mockResolvedValue([]); - mocks.asset.getChangedDeltaSync.mockResolvedValue( - Array.from>({ length: 10_000 }).fill(getForAsset(asset)), - ); - await expect( - sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }), - ).resolves.toEqual({ needsFullSync: true, upserted: [], deleted: [] }); - expect(mocks.asset.getChangedDeltaSync).toHaveBeenCalledTimes(1); - expect(mocks.audit.getAfter).toHaveBeenCalledTimes(0); - }); - - it('should return a response with changes and deletions', async () => { - const asset = AssetFactory.create({ ownerId: authStub.user1.user.id }); - const deletedAsset = AssetFactory.create({ libraryId: 'library-id', isExternal: true }); - mocks.partner.getAll.mockResolvedValue([]); - mocks.asset.getChangedDeltaSync.mockResolvedValue([getForAsset(asset)]); - mocks.audit.getAfter.mockResolvedValue([deletedAsset.id]); - await expect( - sut.getDeltaSync(authStub.user1, { updatedAfter: new Date(), userIds: [authStub.user1.user.id] }), - ).resolves.toEqual({ - needsFullSync: false, - upserted: [mapAsset(getForAsset(asset), mapAssetOpts)], - deleted: [deletedAsset.id], - }); - expect(mocks.asset.getChangedDeltaSync).toHaveBeenCalledTimes(1); - expect(mocks.audit.getAfter).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/server/src/services/sync.service.ts b/server/src/services/sync.service.ts index 9bdeca14d7..50bf9368c8 100644 --- a/server/src/services/sync.service.ts +++ b/server/src/services/sync.service.ts @@ -2,14 +2,9 @@ import { BadRequestException, ForbiddenException, Injectable } from '@nestjs/com import { Insertable } from 'kysely'; import { DateTime, Duration } from 'luxon'; import { Writable } from 'node:stream'; -import { AUDIT_LOG_MAX_DURATION } from 'src/constants'; import { OnJob } from 'src/decorators'; -import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { - AssetDeltaSyncDto, - AssetDeltaSyncResponseDto, - AssetFullSyncDto, SyncAckDeleteDto, SyncAckSetDto, syncAssetFaceV2ToV1, @@ -17,23 +12,12 @@ import { SyncItem, SyncStreamDto, } from 'src/dtos/sync.dto'; -import { - AssetVisibility, - DatabaseAction, - EntityType, - JobName, - Permission, - QueueName, - SyncEntityType, - SyncRequestType, -} from 'src/enum'; +import { JobName, QueueName, SyncEntityType, SyncRequestType } from 'src/enum'; import { SyncQueryOptions } from 'src/repositories/sync.repository'; import { SessionSyncCheckpointTable } from 'src/schema/tables/sync-checkpoint.table'; import { BaseService } from 'src/services/base.service'; import { SyncAck } from 'src/types'; -import { getMyPartnerIds } from 'src/utils/asset.util'; import { hexOrBufferToBase64 } from 'src/utils/bytes'; -import { setIsEqual } from 'src/utils/set'; import { fromAck, serialize, SerializeOptions, toAck } from 'src/utils/sync'; type CheckpointMap = Partial>; @@ -66,7 +50,6 @@ const sendEntityBackfillCompleteAck = (response: Writable, ackType: SyncEntityTy send(response, { type: SyncEntityType.SyncAckV1, data: {}, ackType, ids: [id, COMPLETE_ID] }); }; -const FULL_SYNC = { needsFullSync: true, deleted: [], upserted: [] }; export const SYNC_TYPES_ORDER = [ SyncRequestType.AuthUsersV1, SyncRequestType.UsersV1, @@ -887,68 +870,4 @@ export class SyncService extends BaseService { }, ]); } - - async getFullSync(auth: AuthDto, dto: AssetFullSyncDto): Promise { - // mobile implementation is faster if this is a single id - const userId = dto.userId || auth.user.id; - await this.requireAccess({ auth, permission: Permission.TimelineRead, ids: [userId] }); - const assets = await this.assetRepository.getAllForUserFullSync({ - ownerId: userId, - updatedUntil: dto.updatedUntil, - lastId: dto.lastId, - limit: dto.limit, - }); - return assets.map((a) => mapAsset(a, { auth, stripMetadata: false, withStack: true })); - } - - async getDeltaSync(auth: AuthDto, dto: AssetDeltaSyncDto): Promise { - // app has not synced in the last 100 days - const duration = DateTime.now().diff(DateTime.fromJSDate(dto.updatedAfter)); - if (duration > AUDIT_LOG_MAX_DURATION) { - return FULL_SYNC; - } - - // app does not have the correct partners synced - const partnerIds = await getMyPartnerIds({ userId: auth.user.id, repository: this.partnerRepository }); - const userIds = [auth.user.id, ...partnerIds]; - if (!setIsEqual(new Set(userIds), new Set(dto.userIds))) { - return FULL_SYNC; - } - - await this.requireAccess({ auth, permission: Permission.TimelineRead, ids: dto.userIds }); - - const limit = 10_000; - const upserted = await this.assetRepository.getChangedDeltaSync({ limit, updatedAfter: dto.updatedAfter, userIds }); - - // too many changes, need to do a full sync - if (upserted.length === limit) { - return FULL_SYNC; - } - - const deleted = await this.auditRepository.getAfter(dto.updatedAfter, { - userIds, - entityType: EntityType.Asset, - action: DatabaseAction.Delete, - }); - - const result = { - needsFullSync: false, - upserted: upserted - // do not return archived assets for partner users - .filter( - (a) => - a.ownerId === auth.user.id || (a.ownerId !== auth.user.id && a.visibility === AssetVisibility.Timeline), - ) - .map((a) => - mapAsset(a, { - auth, - stripMetadata: false, - // ignore stacks for non partner users - withStack: a.ownerId === auth.user.id, - }), - ), - deleted, - }; - return result; - } } diff --git a/server/src/types.ts b/server/src/types.ts index 33174e187e..f9bde47aae 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -351,7 +351,6 @@ export type JobItem = | { name: JobName.FileDelete; data: IDeleteFilesJob } // Cleanup - | { name: JobName.AuditLogCleanup; data?: IBaseJob } | { name: JobName.SessionCleanup; data?: IBaseJob } // Tags diff --git a/server/test/repositories/asset.repository.mock.ts b/server/test/repositories/asset.repository.mock.ts index f66de5371e..f3d6693578 100644 --- a/server/test/repositories/asset.repository.mock.ts +++ b/server/test/repositories/asset.repository.mock.ts @@ -33,8 +33,6 @@ export const newAssetRepositoryMock = (): Mocked { cron: automock(CronRepository, { args: [, loggerMock] }), crypto: newCryptoRepositoryMock(), activity: automock(ActivityRepository), - audit: automock(AuditRepository), album: automock(AlbumRepository, { strict: false }), albumUser: automock(AlbumUserRepository), asset: newAssetRepositoryMock(), @@ -373,7 +370,6 @@ export const newTestService = ( overrides.asset || (mocks.asset as As), overrides.assetEdit || (mocks.assetEdit as As), overrides.assetJob || (mocks.assetJob as As), - overrides.audit || (mocks.audit as As), overrides.config || (mocks.config as As as ConfigRepository), overrides.cron || (mocks.cron as As), overrides.crypto || (mocks.crypto as As),