1
0
mirror of https://github.com/immich-app/immich.git synced 2025-08-09 23:17:29 +02:00

fix(server): stacked assets for full sync, userIds as array for delta sync (#9100)

* fix(server): stacked assets for full sync, userIds as array for delta sync

* refactor(server): sync

* fix getDeltaSync after partner removal

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
Fynn Petersen-Frey
2024-04-29 05:24:21 +02:00
committed by GitHub
parent fc2e709ad4
commit 32e7cfea3d
22 changed files with 817 additions and 386 deletions

View File

@@ -77,12 +77,14 @@ part 'model/asset_bulk_upload_check_dto.dart';
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_delta_sync_dto.dart';
part 'model/asset_delta_sync_response_dto.dart';
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_file_upload_response_dto.dart';
part 'model/asset_full_sync_dto.dart';
part 'model/asset_ids_dto.dart';
part 'model/asset_ids_response_dto.dart';
part 'model/asset_job_name.dart';

View File

@@ -16,47 +16,27 @@ class SyncApi {
final ApiClient apiClient;
/// Performs an HTTP 'GET /sync/full-sync' operation and returns the [Response].
/// Performs an HTTP 'POST /sync/delta-sync' operation and returns the [Response].
/// Parameters:
///
/// * [int] limit (required):
///
/// * [DateTime] updatedUntil (required):
///
/// * [DateTime] lastCreationDate:
///
/// * [String] lastId:
///
/// * [String] userId:
Future<Response> getAllForUserFullSyncWithHttpInfo(int limit, DateTime updatedUntil, { DateTime? lastCreationDate, String? lastId, String? userId, }) async {
/// * [AssetDeltaSyncDto] assetDeltaSyncDto (required):
Future<Response> getDeltaSyncWithHttpInfo(AssetDeltaSyncDto assetDeltaSyncDto,) async {
// ignore: prefer_const_declarations
final path = r'/sync/full-sync';
final path = r'/sync/delta-sync';
// ignore: prefer_final_locals
Object? postBody;
Object? postBody = assetDeltaSyncDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (lastCreationDate != null) {
queryParams.addAll(_queryParams('', 'lastCreationDate', lastCreationDate));
}
if (lastId != null) {
queryParams.addAll(_queryParams('', 'lastId', lastId));
}
queryParams.addAll(_queryParams('', 'limit', limit));
queryParams.addAll(_queryParams('', 'updatedUntil', updatedUntil));
if (userId != null) {
queryParams.addAll(_queryParams('', 'userId', userId));
}
const contentTypes = <String>[];
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'GET',
'POST',
queryParams,
postBody,
headerParams,
@@ -67,17 +47,56 @@ class SyncApi {
/// Parameters:
///
/// * [int] limit (required):
/// * [AssetDeltaSyncDto] assetDeltaSyncDto (required):
Future<AssetDeltaSyncResponseDto?> 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;
}
/// Performs an HTTP 'POST /sync/full-sync' operation and returns the [Response].
/// Parameters:
///
/// * [DateTime] updatedUntil (required):
/// * [AssetFullSyncDto] assetFullSyncDto (required):
Future<Response> getFullSyncForUserWithHttpInfo(AssetFullSyncDto assetFullSyncDto,) async {
// ignore: prefer_const_declarations
final path = r'/sync/full-sync';
// ignore: prefer_final_locals
Object? postBody = assetFullSyncDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [DateTime] lastCreationDate:
///
/// * [String] lastId:
///
/// * [String] userId:
Future<List<AssetResponseDto>?> getAllForUserFullSync(int limit, DateTime updatedUntil, { DateTime? lastCreationDate, String? lastId, String? userId, }) async {
final response = await getAllForUserFullSyncWithHttpInfo(limit, updatedUntil, lastCreationDate: lastCreationDate, lastId: lastId, userId: userId, );
/// * [AssetFullSyncDto] assetFullSyncDto (required):
Future<List<AssetResponseDto>?> getFullSyncForUser(AssetFullSyncDto assetFullSyncDto,) async {
final response = await getFullSyncForUserWithHttpInfo(assetFullSyncDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -93,58 +112,4 @@ class SyncApi {
}
return null;
}
/// Performs an HTTP 'GET /sync/delta-sync' operation and returns the [Response].
/// Parameters:
///
/// * [DateTime] updatedAfter (required):
///
/// * [List<String>] userIds (required):
Future<Response> getDeltaSyncWithHttpInfo(DateTime updatedAfter, List<String> userIds,) async {
// ignore: prefer_const_declarations
final path = r'/sync/delta-sync';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
queryParams.addAll(_queryParams('', 'updatedAfter', updatedAfter));
queryParams.addAll(_queryParams('multi', 'userIds', userIds));
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [DateTime] updatedAfter (required):
///
/// * [List<String>] userIds (required):
Future<AssetDeltaSyncResponseDto?> getDeltaSync(DateTime updatedAfter, List<String> userIds,) async {
final response = await getDeltaSyncWithHttpInfo(updatedAfter, userIds,);
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;
}
}

View File

@@ -224,6 +224,8 @@ class ApiClient {
return AssetBulkUploadCheckResponseDto.fromJson(value);
case 'AssetBulkUploadCheckResult':
return AssetBulkUploadCheckResult.fromJson(value);
case 'AssetDeltaSyncDto':
return AssetDeltaSyncDto.fromJson(value);
case 'AssetDeltaSyncResponseDto':
return AssetDeltaSyncResponseDto.fromJson(value);
case 'AssetFaceResponseDto':
@@ -236,6 +238,8 @@ class ApiClient {
return AssetFaceWithoutPersonResponseDto.fromJson(value);
case 'AssetFileUploadResponseDto':
return AssetFileUploadResponseDto.fromJson(value);
case 'AssetFullSyncDto':
return AssetFullSyncDto.fromJson(value);
case 'AssetIdsDto':
return AssetIdsDto.fromJson(value);
case 'AssetIdsResponseDto':

View File

@@ -0,0 +1,108 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// 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 [],
});
DateTime updatedAfter;
List<String> 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<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'updatedAfter'] = 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) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return AssetDeltaSyncDto(
updatedAfter: mapDateTime(json, r'updatedAfter', r'')!,
userIds: json[r'userIds'] is Iterable
? (json[r'userIds'] as Iterable).cast<String>().toList(growable: false)
: const [],
);
}
return null;
}
static List<AssetDeltaSyncDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetDeltaSyncDto>[];
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<String, AssetDeltaSyncDto> mapFromJson(dynamic json) {
final map = <String, AssetDeltaSyncDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // 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<String, List<AssetDeltaSyncDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AssetDeltaSyncDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
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 = <String>{
'updatedAfter',
'userIds',
};
}

View File

@@ -0,0 +1,158 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// 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.lastCreationDate,
this.lastId,
required this.limit,
required this.updatedUntil,
this.userId,
});
///
/// 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.
///
DateTime? lastCreationDate;
///
/// 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;
/// Minimum value: 1
int limit;
DateTime updatedUntil;
///
/// 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.lastCreationDate == lastCreationDate &&
other.lastId == lastId &&
other.limit == limit &&
other.updatedUntil == updatedUntil &&
other.userId == userId;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(lastCreationDate == null ? 0 : lastCreationDate!.hashCode) +
(lastId == null ? 0 : lastId!.hashCode) +
(limit.hashCode) +
(updatedUntil.hashCode) +
(userId == null ? 0 : userId!.hashCode);
@override
String toString() => 'AssetFullSyncDto[lastCreationDate=$lastCreationDate, lastId=$lastId, limit=$limit, updatedUntil=$updatedUntil, userId=$userId]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (this.lastCreationDate != null) {
json[r'lastCreationDate'] = this.lastCreationDate!.toUtc().toIso8601String();
} else {
// json[r'lastCreationDate'] = null;
}
if (this.lastId != null) {
json[r'lastId'] = this.lastId;
} else {
// json[r'lastId'] = null;
}
json[r'limit'] = this.limit;
json[r'updatedUntil'] = 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) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return AssetFullSyncDto(
lastCreationDate: mapDateTime(json, r'lastCreationDate', r''),
lastId: mapValueOfType<String>(json, r'lastId'),
limit: mapValueOfType<int>(json, r'limit')!,
updatedUntil: mapDateTime(json, r'updatedUntil', r'')!,
userId: mapValueOfType<String>(json, r'userId'),
);
}
return null;
}
static List<AssetFullSyncDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetFullSyncDto>[];
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<String, AssetFullSyncDto> mapFromJson(dynamic json) {
final map = <String, AssetFullSyncDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // 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<String, List<AssetFullSyncDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AssetFullSyncDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
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 = <String>{
'limit',
'updatedUntil',
};
}