mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	feat(mobile) duplicated asset upload handling mechanism (#853)
This commit is contained in:
		
							parent
							
								
									f1af17bf4d
								
							
						
					
					
						commit
						6159c83fd2
					
				@ -24,6 +24,7 @@
 | 
			
		||||
  "backup_controller_page_backup_selected": "Ausgewählt: ",
 | 
			
		||||
  "backup_controller_page_backup_sub": "Gesicherte Fotos und Videos",
 | 
			
		||||
  "backup_controller_page_cancel": "Abbrechen",
 | 
			
		||||
  "backup_background_service_default_notification": "Suche nach neuen assets…",
 | 
			
		||||
  "backup_controller_page_created": "Erstellt: {}",
 | 
			
		||||
  "backup_controller_page_desc_backup": "Aktiviere die Sicherung um Elemente automatisch auf den Server zu laden.",
 | 
			
		||||
  "backup_controller_page_excluded": "Ausgeschlossen: ",
 | 
			
		||||
@ -123,4 +124,4 @@
 | 
			
		||||
  "version_announcement_overlay_text_2": "Bitte nehm dir die Zeit und lese das ",
 | 
			
		||||
  "version_announcement_overlay_text_3": " und achte darauf, dass deine docker-compose und .env Dateien aktuell sind, vor allem wenn du ein System für automatische Updates benutzt (z.B. Watchtower).",
 | 
			
		||||
  "version_announcement_overlay_title": "Neue Server-Version verfügbar \uD83C\uDF89"
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -25,3 +25,7 @@ const String backgroundBackupInfoBox = "immichBackgroundBackupInfoBox"; // Box
 | 
			
		||||
const String backupFailedSince = "immichBackupFailedSince"; // Key 1
 | 
			
		||||
const String backupRequireWifi = "immichBackupRequireWifi"; // Key 2
 | 
			
		||||
const String backupRequireCharging = "immichBackupRequireCharging"; // Key 3
 | 
			
		||||
 | 
			
		||||
// Duplicate asset
 | 
			
		||||
const String duplicatedAssetsBox = "immichDuplicatedAssetsBox"; // Box
 | 
			
		||||
const String duplicatedAssetsKey = "immichDuplicatedAssetsKey"; // Key 1
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/constants/locales.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/background_service/background.service.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/hive_backup_albums.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/hive_duplicated_assets.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
 | 
			
		||||
@ -30,12 +31,14 @@ void main() async {
 | 
			
		||||
 | 
			
		||||
  Hive.registerAdapter(HiveSavedLoginInfoAdapter());
 | 
			
		||||
  Hive.registerAdapter(HiveBackupAlbumsAdapter());
 | 
			
		||||
  Hive.registerAdapter(HiveDuplicatedAssetsAdapter());
 | 
			
		||||
 | 
			
		||||
  await Hive.openBox(userInfoBox);
 | 
			
		||||
  await Hive.openBox<HiveSavedLoginInfo>(hiveLoginInfoBox);
 | 
			
		||||
  await Hive.openBox<HiveBackupAlbums>(hiveBackupInfoBox);
 | 
			
		||||
  await Hive.openBox(hiveGithubReleaseInfoBox);
 | 
			
		||||
  await Hive.openBox(userSettingInfoBox);
 | 
			
		||||
  await Hive.openBox<HiveDuplicatedAssets>(duplicatedAssetsBox);
 | 
			
		||||
 | 
			
		||||
  SystemChrome.setSystemUIOverlayStyle(
 | 
			
		||||
    const SystemUiOverlayStyle(
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import 'package:immich_mobile/modules/backup/background_service/localization.dar
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/current_upload_asset.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/error_upload_asset.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/hive_backup_albums.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/hive_duplicated_assets.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/services/backup.service.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
 | 
			
		||||
@ -316,10 +317,13 @@ class BackgroundService {
 | 
			
		||||
 | 
			
		||||
    Hive.registerAdapter(HiveSavedLoginInfoAdapter());
 | 
			
		||||
    Hive.registerAdapter(HiveBackupAlbumsAdapter());
 | 
			
		||||
    Hive.registerAdapter(HiveDuplicatedAssetsAdapter());
 | 
			
		||||
 | 
			
		||||
    await Hive.openBox(userInfoBox);
 | 
			
		||||
    await Hive.openBox<HiveSavedLoginInfo>(hiveLoginInfoBox);
 | 
			
		||||
    await Hive.openBox(userSettingInfoBox);
 | 
			
		||||
    await Hive.openBox(backgroundBackupInfoBox);
 | 
			
		||||
    await Hive.openBox<HiveDuplicatedAssets>(duplicatedAssetsBox);
 | 
			
		||||
 | 
			
		||||
    ApiService apiService = ApiService();
 | 
			
		||||
    apiService.setEndpoint(Hive.box(userInfoBox).get(serverEndpointKey));
 | 
			
		||||
@ -410,7 +414,7 @@ class BackgroundService {
 | 
			
		||||
    final bool ok = await backupService.backupAsset(
 | 
			
		||||
      toUpload,
 | 
			
		||||
      _cancellationToken!,
 | 
			
		||||
      notifyTotalProgress ? _onAssetUploaded : (assetId, deviceId) {},
 | 
			
		||||
      notifyTotalProgress ? _onAssetUploaded : (assetId, deviceId, isDup) {},
 | 
			
		||||
      notifySingleProgress ? _onProgress : (sent, total) {},
 | 
			
		||||
      notifySingleProgress ? _onSetCurrentBackupAsset : (asset) {},
 | 
			
		||||
      _onBackupError,
 | 
			
		||||
@ -429,7 +433,7 @@ class BackgroundService {
 | 
			
		||||
    return "$percent% ($_uploadedAssetsCount/$_assetsToUploadCount)";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _onAssetUploaded(String deviceAssetId, String deviceId) {
 | 
			
		||||
  void _onAssetUploaded(String deviceAssetId, String deviceId, bool isDup) {
 | 
			
		||||
    debugPrint("Uploaded $deviceAssetId from $deviceId");
 | 
			
		||||
    _uploadedAssetsCount++;
 | 
			
		||||
    _updateNotification(
 | 
			
		||||
 | 
			
		||||
@ -45,8 +45,10 @@ class ErrorUploadAsset extends Equatable {
 | 
			
		||||
  List<Object> get props {
 | 
			
		||||
    return [
 | 
			
		||||
      id,
 | 
			
		||||
      createdAt,
 | 
			
		||||
      fileName,
 | 
			
		||||
      fileType,
 | 
			
		||||
      asset,
 | 
			
		||||
      errorMessage,
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,57 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
 | 
			
		||||
import 'package:collection/collection.dart';
 | 
			
		||||
import 'package:hive/hive.dart';
 | 
			
		||||
 | 
			
		||||
part 'hive_duplicated_assets.model.g.dart';
 | 
			
		||||
 | 
			
		||||
@HiveType(typeId: 2)
 | 
			
		||||
class HiveDuplicatedAssets {
 | 
			
		||||
  @HiveField(0, defaultValue: [])
 | 
			
		||||
  List<String> duplicatedAssetIds;
 | 
			
		||||
 | 
			
		||||
  HiveDuplicatedAssets({
 | 
			
		||||
    required this.duplicatedAssetIds,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  HiveDuplicatedAssets copyWith({
 | 
			
		||||
    List<String>? duplicatedAssetIds,
 | 
			
		||||
  }) {
 | 
			
		||||
    return HiveDuplicatedAssets(
 | 
			
		||||
      duplicatedAssetIds: duplicatedAssetIds ?? this.duplicatedAssetIds,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toMap() {
 | 
			
		||||
    return {
 | 
			
		||||
      'duplicatedAssetIds': duplicatedAssetIds,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  factory HiveDuplicatedAssets.fromMap(Map<String, dynamic> map) {
 | 
			
		||||
    return HiveDuplicatedAssets(
 | 
			
		||||
      duplicatedAssetIds: List<String>.from(map['duplicatedAssetIds']),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String toJson() => json.encode(toMap());
 | 
			
		||||
 | 
			
		||||
  factory HiveDuplicatedAssets.fromJson(String source) =>
 | 
			
		||||
      HiveDuplicatedAssets.fromMap(json.decode(source));
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() =>
 | 
			
		||||
      'HiveDuplicatedAssets(duplicatedAssetIds: $duplicatedAssetIds)';
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) {
 | 
			
		||||
    if (identical(this, other)) return true;
 | 
			
		||||
    final listEquals = const DeepCollectionEquality().equals;
 | 
			
		||||
 | 
			
		||||
    return other is HiveDuplicatedAssets &&
 | 
			
		||||
        listEquals(other.duplicatedAssetIds, duplicatedAssetIds);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => duplicatedAssetIds.hashCode;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,42 @@
 | 
			
		||||
// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
			
		||||
 | 
			
		||||
part of 'hive_duplicated_assets.model.dart';
 | 
			
		||||
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
// TypeAdapterGenerator
 | 
			
		||||
// **************************************************************************
 | 
			
		||||
 | 
			
		||||
class HiveDuplicatedAssetsAdapter extends TypeAdapter<HiveDuplicatedAssets> {
 | 
			
		||||
  @override
 | 
			
		||||
  final int typeId = 2;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  HiveDuplicatedAssets read(BinaryReader reader) {
 | 
			
		||||
    final numOfFields = reader.readByte();
 | 
			
		||||
    final fields = <int, dynamic>{
 | 
			
		||||
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
 | 
			
		||||
    };
 | 
			
		||||
    return HiveDuplicatedAssets(
 | 
			
		||||
      duplicatedAssetIds:
 | 
			
		||||
          fields[0] == null ? [] : (fields[0] as List).cast<String>(),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void write(BinaryWriter writer, HiveDuplicatedAssets obj) {
 | 
			
		||||
    writer
 | 
			
		||||
      ..writeByte(1)
 | 
			
		||||
      ..writeByte(0)
 | 
			
		||||
      ..write(obj.duplicatedAssetIds);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode => typeId.hashCode;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) =>
 | 
			
		||||
      identical(this, other) ||
 | 
			
		||||
      other is HiveDuplicatedAssetsAdapter &&
 | 
			
		||||
          runtimeType == other.runtimeType &&
 | 
			
		||||
          typeId == other.typeId;
 | 
			
		||||
}
 | 
			
		||||
@ -10,6 +10,7 @@ import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/current_upload_asset.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/error_upload_asset.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/hive_backup_albums.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/models/hive_duplicated_assets.model.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/providers/error_backup_list.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/background_service/background.service.dart';
 | 
			
		||||
import 'package:immich_mobile/modules/backup/services/backup.service.dart';
 | 
			
		||||
@ -296,6 +297,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
 | 
			
		||||
  /// Those assets are unique and are used as the total assets
 | 
			
		||||
  ///
 | 
			
		||||
  Future<void> _updateBackupAssetCount() async {
 | 
			
		||||
    Set<String> duplicatedAssetIds = _backupService.getDuplicatedAssetIds();
 | 
			
		||||
    Set<AssetEntity> assetsFromSelectedAlbums = {};
 | 
			
		||||
    Set<AssetEntity> assetsFromExcludedAlbums = {};
 | 
			
		||||
 | 
			
		||||
@ -326,9 +328,15 @@ class BackupNotifier extends StateNotifier<BackUpState> {
 | 
			
		||||
    // Find asset that were backup from selected albums
 | 
			
		||||
    Set<String> selectedAlbumsBackupAssets =
 | 
			
		||||
        Set.from(allUniqueAssets.map((e) => e.id));
 | 
			
		||||
 | 
			
		||||
    selectedAlbumsBackupAssets
 | 
			
		||||
        .removeWhere((assetId) => !allAssetsInDatabase.contains(assetId));
 | 
			
		||||
 | 
			
		||||
    // Remove duplicated asset from all unique assets
 | 
			
		||||
    allUniqueAssets.removeWhere(
 | 
			
		||||
      (asset) => duplicatedAssetIds.contains(asset.id),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (allUniqueAssets.isEmpty) {
 | 
			
		||||
      debugPrint("No Asset On Device");
 | 
			
		||||
      state = state.copyWith(
 | 
			
		||||
@ -455,14 +463,26 @@ class BackupNotifier extends StateNotifier<BackUpState> {
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _onAssetUploaded(String deviceAssetId, String deviceId) {
 | 
			
		||||
    state = state.copyWith(
 | 
			
		||||
      selectedAlbumsBackupAssetsIds: {
 | 
			
		||||
        ...state.selectedAlbumsBackupAssetsIds,
 | 
			
		||||
        deviceAssetId
 | 
			
		||||
      },
 | 
			
		||||
      allAssetsInDatabase: [...state.allAssetsInDatabase, deviceAssetId],
 | 
			
		||||
    );
 | 
			
		||||
  void _onAssetUploaded(
 | 
			
		||||
    String deviceAssetId,
 | 
			
		||||
    String deviceId,
 | 
			
		||||
    bool isDuplicated,
 | 
			
		||||
  ) {
 | 
			
		||||
    if (isDuplicated) {
 | 
			
		||||
      state = state.copyWith(
 | 
			
		||||
        allUniqueAssets: state.allUniqueAssets
 | 
			
		||||
            .where((asset) => asset.id != deviceAssetId)
 | 
			
		||||
            .toSet(),
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      state = state.copyWith(
 | 
			
		||||
        selectedAlbumsBackupAssetsIds: {
 | 
			
		||||
          ...state.selectedAlbumsBackupAssetsIds,
 | 
			
		||||
          deviceAssetId
 | 
			
		||||
        },
 | 
			
		||||
        allAssetsInDatabase: [...state.allAssetsInDatabase, deviceAssetId],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (state.allUniqueAssets.length -
 | 
			
		||||
            state.selectedAlbumsBackupAssetsIds.length ==
 | 
			
		||||
@ -564,6 +584,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
 | 
			
		||||
          albums.lastExcludedBackupTime,
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
      await Hive.openBox<HiveDuplicatedAssets>(duplicatedAssetsBox);
 | 
			
		||||
      final Box backgroundBox = await Hive.openBox(backgroundBackupInfoBox);
 | 
			
		||||
      state = state.copyWith(
 | 
			
		||||
        backupProgress: previous,
 | 
			
		||||
@ -608,6 +629,13 @@ class BackupNotifier extends StateNotifier<BackUpState> {
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        debugPrint("[_notifyBackgroundServiceCanRun] failed to close box");
 | 
			
		||||
      }
 | 
			
		||||
      try {
 | 
			
		||||
        if (Hive.isBoxOpen(duplicatedAssetsBox)) {
 | 
			
		||||
          await Hive.box<HiveDuplicatedAssets>(duplicatedAssetsBox).close();
 | 
			
		||||
        }
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        debugPrint("[_notifyBackgroundServiceCanRun] failed to close box");
 | 
			
		||||
      }
 | 
			
		||||
      try {
 | 
			
		||||
        if (Hive.isBoxOpen(backgroundBackupInfoBox)) {
 | 
			
		||||
          await Hive.box(backgroundBackupInfoBox).close();
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,8 @@ import 'package:http_parser/http_parser.dart';
 | 
			
		||||
import 'package:path/path.dart' as p;
 | 
			
		||||
import 'package:cancellation_token_http/http.dart' as http;
 | 
			
		||||
 | 
			
		||||
import '../models/hive_duplicated_assets.model.dart';
 | 
			
		||||
 | 
			
		||||
final backupServiceProvider = Provider(
 | 
			
		||||
  (ref) => BackupService(
 | 
			
		||||
    ref.watch(apiServiceProvider),
 | 
			
		||||
@ -41,6 +43,29 @@ class BackupService {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _saveDuplicatedAssetIdToLocalStorage(List<String> deviceAssetIds) {
 | 
			
		||||
    HiveDuplicatedAssets duplicatedAssets =
 | 
			
		||||
        Hive.box<HiveDuplicatedAssets>(duplicatedAssetsBox)
 | 
			
		||||
                .get(duplicatedAssetsKey) ??
 | 
			
		||||
            HiveDuplicatedAssets(duplicatedAssetIds: []);
 | 
			
		||||
 | 
			
		||||
    duplicatedAssets.duplicatedAssetIds =
 | 
			
		||||
        {...duplicatedAssets.duplicatedAssetIds, ...deviceAssetIds}.toList();
 | 
			
		||||
 | 
			
		||||
    Hive.box<HiveDuplicatedAssets>(duplicatedAssetsBox)
 | 
			
		||||
        .put(duplicatedAssetsKey, duplicatedAssets);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Get duplicated asset id from Hive storage
 | 
			
		||||
  Set<String> getDuplicatedAssetIds() {
 | 
			
		||||
    HiveDuplicatedAssets duplicatedAssets =
 | 
			
		||||
        Hive.box<HiveDuplicatedAssets>(duplicatedAssetsBox)
 | 
			
		||||
                .get(duplicatedAssetsKey) ??
 | 
			
		||||
            HiveDuplicatedAssets(duplicatedAssetIds: []);
 | 
			
		||||
 | 
			
		||||
    return duplicatedAssets.duplicatedAssetIds.toSet();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns all assets newer than the last successful backup per album
 | 
			
		||||
  Future<List<AssetEntity>> buildUploadCandidates(
 | 
			
		||||
    HiveBackupAlbums backupAlbums,
 | 
			
		||||
@ -140,34 +165,47 @@ class BackupService {
 | 
			
		||||
  Future<List<AssetEntity>> removeAlreadyUploadedAssets(
 | 
			
		||||
    List<AssetEntity> candidates,
 | 
			
		||||
  ) async {
 | 
			
		||||
    final String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
 | 
			
		||||
    if (candidates.length < 10) {
 | 
			
		||||
      final List<CheckDuplicateAssetResponseDto?> duplicateResponse =
 | 
			
		||||
          await Future.wait(
 | 
			
		||||
        candidates.map(
 | 
			
		||||
          (e) => _apiService.assetApi.checkDuplicateAsset(
 | 
			
		||||
            CheckDuplicateAssetDto(deviceAssetId: e.id, deviceId: deviceId),
 | 
			
		||||
          ),
 | 
			
		||||
    if (candidates.isEmpty) {
 | 
			
		||||
      return candidates;
 | 
			
		||||
    }
 | 
			
		||||
    final Set<String> duplicatedAssetIds = getDuplicatedAssetIds();
 | 
			
		||||
    candidates = duplicatedAssetIds.isEmpty
 | 
			
		||||
        ? candidates
 | 
			
		||||
        : candidates
 | 
			
		||||
            .whereNot((asset) => duplicatedAssetIds.contains(asset.id))
 | 
			
		||||
            .toList();
 | 
			
		||||
    if (candidates.isEmpty) {
 | 
			
		||||
      return candidates;
 | 
			
		||||
    }
 | 
			
		||||
    final Set<String> existing = {};
 | 
			
		||||
    try {
 | 
			
		||||
      final String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
 | 
			
		||||
      final CheckExistingAssetsResponseDto? duplicates =
 | 
			
		||||
          await _apiService.assetApi.checkExistingAssets(
 | 
			
		||||
        CheckExistingAssetsDto(
 | 
			
		||||
          deviceAssetIds: candidates.map((e) => e.id).toList(),
 | 
			
		||||
          deviceId: deviceId,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      return candidates
 | 
			
		||||
          .whereIndexed((i, e) => duplicateResponse[i]?.isExist == false)
 | 
			
		||||
          .toList();
 | 
			
		||||
    } else {
 | 
			
		||||
      final List<String>? allAssetsInDatabase = await getDeviceBackupAsset();
 | 
			
		||||
 | 
			
		||||
      if (allAssetsInDatabase == null) {
 | 
			
		||||
        return candidates;
 | 
			
		||||
      if (duplicates != null) {
 | 
			
		||||
        existing.addAll(duplicates.existingIds);
 | 
			
		||||
      }
 | 
			
		||||
    } on ApiException {
 | 
			
		||||
      // workaround for older server versions or when checking for too many assets at once
 | 
			
		||||
      final List<String>? allAssetsInDatabase = await getDeviceBackupAsset();
 | 
			
		||||
      if (allAssetsInDatabase != null) {
 | 
			
		||||
        existing.addAll(allAssetsInDatabase);
 | 
			
		||||
      }
 | 
			
		||||
      final Set<String> inDb = allAssetsInDatabase.toSet();
 | 
			
		||||
      return candidates.whereNot((e) => inDb.contains(e.id)).toList();
 | 
			
		||||
    }
 | 
			
		||||
    return existing.isEmpty
 | 
			
		||||
        ? candidates
 | 
			
		||||
        : candidates.whereNot((e) => existing.contains(e.id)).toList();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<bool> backupAsset(
 | 
			
		||||
    Iterable<AssetEntity> assetList,
 | 
			
		||||
    http.CancellationToken cancelToken,
 | 
			
		||||
    Function(String, String) singleAssetDoneCb,
 | 
			
		||||
    Function(String, String, bool) uploadSuccessCb,
 | 
			
		||||
    Function(int, int) uploadProgressCb,
 | 
			
		||||
    Function(CurrentUploadAsset) setCurrentUploadAssetCb,
 | 
			
		||||
    Function(ErrorUploadAsset) errorCb,
 | 
			
		||||
@ -176,6 +214,7 @@ class BackupService {
 | 
			
		||||
    String savedEndpoint = Hive.box(userInfoBox).get(serverEndpointKey);
 | 
			
		||||
    File? file;
 | 
			
		||||
    bool anyErrors = false;
 | 
			
		||||
    final List<String> duplicatedAssetIds = [];
 | 
			
		||||
 | 
			
		||||
    for (var entity in assetList) {
 | 
			
		||||
      try {
 | 
			
		||||
@ -235,8 +274,13 @@ class BackupService {
 | 
			
		||||
 | 
			
		||||
          var response = await req.send(cancellationToken: cancelToken);
 | 
			
		||||
 | 
			
		||||
          if (response.statusCode == 201) {
 | 
			
		||||
            singleAssetDoneCb(entity.id, deviceId);
 | 
			
		||||
          if (response.statusCode == 200) {
 | 
			
		||||
            // asset is a duplicate (already exists on the server)
 | 
			
		||||
            duplicatedAssetIds.add(entity.id);
 | 
			
		||||
            uploadSuccessCb(entity.id, deviceId, true);
 | 
			
		||||
          } else if (response.statusCode == 201) {
 | 
			
		||||
            // stored a new asset on the server
 | 
			
		||||
            uploadSuccessCb(entity.id, deviceId, false);
 | 
			
		||||
          } else {
 | 
			
		||||
            var data = await response.stream.bytesToString();
 | 
			
		||||
            var error = jsonDecode(data);
 | 
			
		||||
@ -260,7 +304,8 @@ class BackupService {
 | 
			
		||||
        }
 | 
			
		||||
      } on http.CancelledException {
 | 
			
		||||
        debugPrint("Backup was cancelled by the user");
 | 
			
		||||
        return false;
 | 
			
		||||
        anyErrors = true;
 | 
			
		||||
        break;
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        debugPrint("ERROR backupAsset: ${e.toString()}");
 | 
			
		||||
        anyErrors = true;
 | 
			
		||||
@ -271,6 +316,9 @@ class BackupService {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (duplicatedAssetIds.isNotEmpty) {
 | 
			
		||||
      _saveDuplicatedAssetIdToLocalStorage(duplicatedAssetIds);
 | 
			
		||||
    }
 | 
			
		||||
    return !anyErrors;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -419,7 +419,6 @@ class BackupControllerPage extends HookConsumerWidget {
 | 
			
		||||
              ActionChip(
 | 
			
		||||
                avatar: Icon(
 | 
			
		||||
                  Icons.info,
 | 
			
		||||
                  size: 24,
 | 
			
		||||
                  color: Colors.red[400],
 | 
			
		||||
                ),
 | 
			
		||||
                elevation: 1,
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,8 @@ doc/AssetTypeEnum.md
 | 
			
		||||
doc/AuthenticationApi.md
 | 
			
		||||
doc/CheckDuplicateAssetDto.md
 | 
			
		||||
doc/CheckDuplicateAssetResponseDto.md
 | 
			
		||||
doc/CheckExistingAssetsDto.md
 | 
			
		||||
doc/CheckExistingAssetsResponseDto.md
 | 
			
		||||
doc/CreateAlbumDto.md
 | 
			
		||||
doc/CreateDeviceInfoDto.md
 | 
			
		||||
doc/CreateProfileImageResponseDto.md
 | 
			
		||||
@ -93,6 +95,8 @@ lib/model/asset_response_dto.dart
 | 
			
		||||
lib/model/asset_type_enum.dart
 | 
			
		||||
lib/model/check_duplicate_asset_dto.dart
 | 
			
		||||
lib/model/check_duplicate_asset_response_dto.dart
 | 
			
		||||
lib/model/check_existing_assets_dto.dart
 | 
			
		||||
lib/model/check_existing_assets_response_dto.dart
 | 
			
		||||
lib/model/create_album_dto.dart
 | 
			
		||||
lib/model/create_device_info_dto.dart
 | 
			
		||||
lib/model/create_profile_image_response_dto.dart
 | 
			
		||||
@ -133,3 +137,5 @@ lib/model/user_count_response_dto.dart
 | 
			
		||||
lib/model/user_response_dto.dart
 | 
			
		||||
lib/model/validate_access_token_response_dto.dart
 | 
			
		||||
pubspec.yaml
 | 
			
		||||
test/check_existing_assets_dto_test.dart
 | 
			
		||||
test/check_existing_assets_response_dto_test.dart
 | 
			
		||||
 | 
			
		||||
@ -76,6 +76,7 @@ Class | Method | HTTP request | Description
 | 
			
		||||
*AlbumApi* | [**removeUserFromAlbum**](doc//AlbumApi.md#removeuserfromalbum) | **DELETE** /album/{albumId}/user/{userId} | 
 | 
			
		||||
*AlbumApi* | [**updateAlbumInfo**](doc//AlbumApi.md#updatealbuminfo) | **PATCH** /album/{albumId} | 
 | 
			
		||||
*AssetApi* | [**checkDuplicateAsset**](doc//AssetApi.md#checkduplicateasset) | **POST** /asset/check | 
 | 
			
		||||
*AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist | 
 | 
			
		||||
*AssetApi* | [**deleteAsset**](doc//AssetApi.md#deleteasset) | **DELETE** /asset | 
 | 
			
		||||
*AssetApi* | [**downloadFile**](doc//AssetApi.md#downloadfile) | **GET** /asset/download | 
 | 
			
		||||
*AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset | 
 | 
			
		||||
@ -130,6 +131,8 @@ Class | Method | HTTP request | Description
 | 
			
		||||
 - [AssetTypeEnum](doc//AssetTypeEnum.md)
 | 
			
		||||
 - [CheckDuplicateAssetDto](doc//CheckDuplicateAssetDto.md)
 | 
			
		||||
 - [CheckDuplicateAssetResponseDto](doc//CheckDuplicateAssetResponseDto.md)
 | 
			
		||||
 - [CheckExistingAssetsDto](doc//CheckExistingAssetsDto.md)
 | 
			
		||||
 - [CheckExistingAssetsResponseDto](doc//CheckExistingAssetsResponseDto.md)
 | 
			
		||||
 - [CreateAlbumDto](doc//CreateAlbumDto.md)
 | 
			
		||||
 - [CreateDeviceInfoDto](doc//CreateDeviceInfoDto.md)
 | 
			
		||||
 - [CreateProfileImageResponseDto](doc//CreateProfileImageResponseDto.md)
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ All URIs are relative to */api*
 | 
			
		||||
Method | HTTP request | Description
 | 
			
		||||
------------- | ------------- | -------------
 | 
			
		||||
[**checkDuplicateAsset**](AssetApi.md#checkduplicateasset) | **POST** /asset/check | 
 | 
			
		||||
[**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist | 
 | 
			
		||||
[**deleteAsset**](AssetApi.md#deleteasset) | **DELETE** /asset | 
 | 
			
		||||
[**downloadFile**](AssetApi.md#downloadfile) | **GET** /asset/download | 
 | 
			
		||||
[**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset | 
 | 
			
		||||
@ -76,6 +77,55 @@ Name | Type | Description  | Notes
 | 
			
		||||
 | 
			
		||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
# **checkExistingAssets**
 | 
			
		||||
> CheckExistingAssetsResponseDto checkExistingAssets(checkExistingAssetsDto)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Checks if multiple assets exist on the server and returns all existing - used by background backup
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
// TODO Configure HTTP Bearer authorization: bearer
 | 
			
		||||
// Case 1. Use String Token
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
 | 
			
		||||
// Case 2. Use Function which generate token.
 | 
			
		||||
// String yourTokenGeneratorFunction() { ... }
 | 
			
		||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 | 
			
		||||
 | 
			
		||||
final api_instance = AssetApi();
 | 
			
		||||
final checkExistingAssetsDto = CheckExistingAssetsDto(); // CheckExistingAssetsDto | 
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    final result = api_instance.checkExistingAssets(checkExistingAssetsDto);
 | 
			
		||||
    print(result);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    print('Exception when calling AssetApi->checkExistingAssets: $e\n');
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
 | 
			
		||||
Name | Type | Description  | Notes
 | 
			
		||||
------------- | ------------- | ------------- | -------------
 | 
			
		||||
 **checkExistingAssetsDto** | [**CheckExistingAssetsDto**](CheckExistingAssetsDto.md)|  | 
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
[**CheckExistingAssetsResponseDto**](CheckExistingAssetsResponseDto.md)
 | 
			
		||||
 | 
			
		||||
### Authorization
 | 
			
		||||
 | 
			
		||||
[bearer](../README.md#bearer)
 | 
			
		||||
 | 
			
		||||
### HTTP request headers
 | 
			
		||||
 | 
			
		||||
 - **Content-Type**: application/json
 | 
			
		||||
 - **Accept**: application/json
 | 
			
		||||
 | 
			
		||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
# **deleteAsset**
 | 
			
		||||
> List<DeleteAssetResponseDto> deleteAsset(deleteAssetDto)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								mobile/openapi/doc/CheckExistingAssetsDto.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mobile/openapi/doc/CheckExistingAssetsDto.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
# openapi.model.CheckExistingAssetsDto
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**deviceAssetIds** | **List<String>** |  | [default to const []]
 | 
			
		||||
**deviceId** | **String** |  | 
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								mobile/openapi/doc/CheckExistingAssetsResponseDto.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mobile/openapi/doc/CheckExistingAssetsResponseDto.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
# openapi.model.CheckExistingAssetsResponseDto
 | 
			
		||||
 | 
			
		||||
## Load the model package
 | 
			
		||||
```dart
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**existingIds** | **List<String>** |  | [default to const []]
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,8 @@ part 'model/asset_response_dto.dart';
 | 
			
		||||
part 'model/asset_type_enum.dart';
 | 
			
		||||
part 'model/check_duplicate_asset_dto.dart';
 | 
			
		||||
part 'model/check_duplicate_asset_response_dto.dart';
 | 
			
		||||
part 'model/check_existing_assets_dto.dart';
 | 
			
		||||
part 'model/check_existing_assets_response_dto.dart';
 | 
			
		||||
part 'model/create_album_dto.dart';
 | 
			
		||||
part 'model/create_device_info_dto.dart';
 | 
			
		||||
part 'model/create_profile_image_response_dto.dart';
 | 
			
		||||
 | 
			
		||||
@ -72,6 +72,62 @@ class AssetApi {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// 
 | 
			
		||||
  ///
 | 
			
		||||
  /// Checks if multiple assets exist on the server and returns all existing - used by background backup
 | 
			
		||||
  ///
 | 
			
		||||
  /// Note: This method returns the HTTP [Response].
 | 
			
		||||
  ///
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [CheckExistingAssetsDto] checkExistingAssetsDto (required):
 | 
			
		||||
  Future<Response> checkExistingAssetsWithHttpInfo(CheckExistingAssetsDto checkExistingAssetsDto,) async {
 | 
			
		||||
    // ignore: prefer_const_declarations
 | 
			
		||||
    final path = r'/asset/exist';
 | 
			
		||||
 | 
			
		||||
    // ignore: prefer_final_locals
 | 
			
		||||
    Object? postBody = checkExistingAssetsDto;
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// 
 | 
			
		||||
  ///
 | 
			
		||||
  /// Checks if multiple assets exist on the server and returns all existing - used by background backup
 | 
			
		||||
  ///
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
  /// * [CheckExistingAssetsDto] checkExistingAssetsDto (required):
 | 
			
		||||
  Future<CheckExistingAssetsResponseDto?> checkExistingAssets(CheckExistingAssetsDto checkExistingAssetsDto,) async {
 | 
			
		||||
    final response = await checkExistingAssetsWithHttpInfo(checkExistingAssetsDto,);
 | 
			
		||||
    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), 'CheckExistingAssetsResponseDto',) as CheckExistingAssetsResponseDto;
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Performs an HTTP 'DELETE /asset' operation and returns the [Response].
 | 
			
		||||
  /// Parameters:
 | 
			
		||||
  ///
 | 
			
		||||
 | 
			
		||||
@ -220,6 +220,10 @@ class ApiClient {
 | 
			
		||||
          return CheckDuplicateAssetDto.fromJson(value);
 | 
			
		||||
        case 'CheckDuplicateAssetResponseDto':
 | 
			
		||||
          return CheckDuplicateAssetResponseDto.fromJson(value);
 | 
			
		||||
        case 'CheckExistingAssetsDto':
 | 
			
		||||
          return CheckExistingAssetsDto.fromJson(value);
 | 
			
		||||
        case 'CheckExistingAssetsResponseDto':
 | 
			
		||||
          return CheckExistingAssetsResponseDto.fromJson(value);
 | 
			
		||||
        case 'CreateAlbumDto':
 | 
			
		||||
          return CreateAlbumDto.fromJson(value);
 | 
			
		||||
        case 'CreateDeviceInfoDto':
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										121
									
								
								mobile/openapi/lib/model/check_existing_assets_dto.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								mobile/openapi/lib/model/check_existing_assets_dto.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 CheckExistingAssetsDto {
 | 
			
		||||
  /// Returns a new [CheckExistingAssetsDto] instance.
 | 
			
		||||
  CheckExistingAssetsDto({
 | 
			
		||||
    this.deviceAssetIds = const [],
 | 
			
		||||
    required this.deviceId,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  List<String> deviceAssetIds;
 | 
			
		||||
 | 
			
		||||
  String deviceId;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is CheckExistingAssetsDto &&
 | 
			
		||||
     other.deviceAssetIds == deviceAssetIds &&
 | 
			
		||||
     other.deviceId == deviceId;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (deviceAssetIds.hashCode) +
 | 
			
		||||
    (deviceId.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'CheckExistingAssetsDto[deviceAssetIds=$deviceAssetIds, deviceId=$deviceId]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final _json = <String, dynamic>{};
 | 
			
		||||
      _json[r'deviceAssetIds'] = deviceAssetIds;
 | 
			
		||||
      _json[r'deviceId'] = deviceId;
 | 
			
		||||
    return _json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [CheckExistingAssetsDto] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static CheckExistingAssetsDto? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      // Ensure that the map contains the required keys.
 | 
			
		||||
      // Note 1: the values aren't checked for validity beyond being non-null.
 | 
			
		||||
      // Note 2: this code is stripped in release mode!
 | 
			
		||||
      assert(() {
 | 
			
		||||
        requiredKeys.forEach((key) {
 | 
			
		||||
          assert(json.containsKey(key), 'Required key "CheckExistingAssetsDto[$key]" is missing from JSON.');
 | 
			
		||||
          assert(json[key] != null, 'Required key "CheckExistingAssetsDto[$key]" has a null value in JSON.');
 | 
			
		||||
        });
 | 
			
		||||
        return true;
 | 
			
		||||
      }());
 | 
			
		||||
 | 
			
		||||
      return CheckExistingAssetsDto(
 | 
			
		||||
        deviceAssetIds: json[r'deviceAssetIds'] is List
 | 
			
		||||
            ? (json[r'deviceAssetIds'] as List).cast<String>()
 | 
			
		||||
            : const [],
 | 
			
		||||
        deviceId: mapValueOfType<String>(json, r'deviceId')!,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<CheckExistingAssetsDto>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <CheckExistingAssetsDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = CheckExistingAssetsDto.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, CheckExistingAssetsDto> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, CheckExistingAssetsDto>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = CheckExistingAssetsDto.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of CheckExistingAssetsDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<CheckExistingAssetsDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<CheckExistingAssetsDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = CheckExistingAssetsDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'deviceAssetIds',
 | 
			
		||||
    'deviceId',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										113
									
								
								mobile/openapi/lib/model/check_existing_assets_response_dto.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								mobile/openapi/lib/model/check_existing_assets_response_dto.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
			
		||||
//
 | 
			
		||||
// 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 CheckExistingAssetsResponseDto {
 | 
			
		||||
  /// Returns a new [CheckExistingAssetsResponseDto] instance.
 | 
			
		||||
  CheckExistingAssetsResponseDto({
 | 
			
		||||
    this.existingIds = const [],
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  List<String> existingIds;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool operator ==(Object other) => identical(this, other) || other is CheckExistingAssetsResponseDto &&
 | 
			
		||||
     other.existingIds == existingIds;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (existingIds.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'CheckExistingAssetsResponseDto[existingIds=$existingIds]';
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final _json = <String, dynamic>{};
 | 
			
		||||
      _json[r'existingIds'] = existingIds;
 | 
			
		||||
    return _json;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Returns a new [CheckExistingAssetsResponseDto] instance and imports its values from
 | 
			
		||||
  /// [value] if it's a [Map], null otherwise.
 | 
			
		||||
  // ignore: prefer_constructors_over_static_methods
 | 
			
		||||
  static CheckExistingAssetsResponseDto? fromJson(dynamic value) {
 | 
			
		||||
    if (value is Map) {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      // Ensure that the map contains the required keys.
 | 
			
		||||
      // Note 1: the values aren't checked for validity beyond being non-null.
 | 
			
		||||
      // Note 2: this code is stripped in release mode!
 | 
			
		||||
      assert(() {
 | 
			
		||||
        requiredKeys.forEach((key) {
 | 
			
		||||
          assert(json.containsKey(key), 'Required key "CheckExistingAssetsResponseDto[$key]" is missing from JSON.');
 | 
			
		||||
          assert(json[key] != null, 'Required key "CheckExistingAssetsResponseDto[$key]" has a null value in JSON.');
 | 
			
		||||
        });
 | 
			
		||||
        return true;
 | 
			
		||||
      }());
 | 
			
		||||
 | 
			
		||||
      return CheckExistingAssetsResponseDto(
 | 
			
		||||
        existingIds: json[r'existingIds'] is List
 | 
			
		||||
            ? (json[r'existingIds'] as List).cast<String>()
 | 
			
		||||
            : const [],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static List<CheckExistingAssetsResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final result = <CheckExistingAssetsResponseDto>[];
 | 
			
		||||
    if (json is List && json.isNotEmpty) {
 | 
			
		||||
      for (final row in json) {
 | 
			
		||||
        final value = CheckExistingAssetsResponseDto.fromJson(row);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          result.add(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result.toList(growable: growable);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Map<String, CheckExistingAssetsResponseDto> mapFromJson(dynamic json) {
 | 
			
		||||
    final map = <String, CheckExistingAssetsResponseDto>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = CheckExistingAssetsResponseDto.fromJson(entry.value);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // maps a json object with a list of CheckExistingAssetsResponseDto-objects as value to a dart map
 | 
			
		||||
  static Map<String, List<CheckExistingAssetsResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
 | 
			
		||||
    final map = <String, List<CheckExistingAssetsResponseDto>>{};
 | 
			
		||||
    if (json is Map && json.isNotEmpty) {
 | 
			
		||||
      json = json.cast<String, dynamic>(); // ignore: parameter_assignments
 | 
			
		||||
      for (final entry in json.entries) {
 | 
			
		||||
        final value = CheckExistingAssetsResponseDto.listFromJson(entry.value, growable: growable,);
 | 
			
		||||
        if (value != null) {
 | 
			
		||||
          map[entry.key] = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// The list of required keys that must be present in a JSON.
 | 
			
		||||
  static const requiredKeys = <String>{
 | 
			
		||||
    'existingIds',
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								mobile/openapi/test/check_existing_assets_dto_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mobile/openapi/test/check_existing_assets_dto_test.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
//
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
import 'package:test/test.dart';
 | 
			
		||||
 | 
			
		||||
// tests for CheckExistingAssetsDto
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = CheckExistingAssetsDto();
 | 
			
		||||
 | 
			
		||||
  group('test CheckExistingAssetsDto', () {
 | 
			
		||||
    // List<String> deviceAssetIds (default value: const [])
 | 
			
		||||
    test('to test the property `deviceAssetIds`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // String deviceId
 | 
			
		||||
    test('to test the property `deviceId`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
//
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
import 'package:test/test.dart';
 | 
			
		||||
 | 
			
		||||
// tests for CheckExistingAssetsResponseDto
 | 
			
		||||
void main() {
 | 
			
		||||
  // final instance = CheckExistingAssetsResponseDto();
 | 
			
		||||
 | 
			
		||||
  group('test CheckExistingAssetsResponseDto', () {
 | 
			
		||||
    // List<String> existingIds (default value: const [])
 | 
			
		||||
    test('to test the property `existingIds`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -137,6 +137,7 @@ describe('Album service', () => {
 | 
			
		||||
      getAssetWithNoEXIF: jest.fn(),
 | 
			
		||||
      getAssetWithNoThumbnail: jest.fn(),
 | 
			
		||||
      getAssetWithNoSmartInfo: jest.fn(),
 | 
			
		||||
      getExistingAssets: jest.fn(),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    sut = new AlbumService(albumRepositoryMock, assetRepositoryMock);
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,9 @@ import { AssetCountByTimeBucket } from './response-dto/asset-count-by-time-group
 | 
			
		||||
import { TimeGroupEnum } from './dto/get-asset-count-by-time-bucket.dto';
 | 
			
		||||
import { GetAssetByTimeBucketDto } from './dto/get-asset-by-time-bucket.dto';
 | 
			
		||||
import { AssetCountByUserIdResponseDto } from './response-dto/asset-count-by-user-id-response.dto';
 | 
			
		||||
import { CheckExistingAssetsDto } from './dto/check-existing-assets.dto';
 | 
			
		||||
import { CheckExistingAssetsResponseDto } from './response-dto/check-existing-assets-response.dto';
 | 
			
		||||
import { In } from 'typeorm/find-options/operator/In';
 | 
			
		||||
 | 
			
		||||
export interface IAssetRepository {
 | 
			
		||||
  create(
 | 
			
		||||
@ -32,6 +35,7 @@ export interface IAssetRepository {
 | 
			
		||||
  getAssetWithNoThumbnail(): Promise<AssetEntity[]>;
 | 
			
		||||
  getAssetWithNoEXIF(): Promise<AssetEntity[]>;
 | 
			
		||||
  getAssetWithNoSmartInfo(): Promise<AssetEntity[]>;
 | 
			
		||||
  getExistingAssets(userId: string, checkDuplicateAssetDto: CheckExistingAssetsDto): Promise<CheckExistingAssetsResponseDto>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const ASSET_REPOSITORY = 'ASSET_REPOSITORY';
 | 
			
		||||
@ -279,4 +283,17 @@ export class AssetRepository implements IAssetRepository {
 | 
			
		||||
      relations: ['exifInfo'],
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getExistingAssets(userId: string, checkDuplicateAssetDto: CheckExistingAssetsDto): Promise<CheckExistingAssetsResponseDto> {
 | 
			
		||||
    const existingAssets = await this.assetRepository.find({
 | 
			
		||||
      select: {deviceAssetId: true},
 | 
			
		||||
      where: {
 | 
			
		||||
        deviceAssetId: In(checkDuplicateAssetDto.deviceAssetIds),
 | 
			
		||||
        deviceId: checkDuplicateAssetDto.deviceId,
 | 
			
		||||
        userId,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    return new CheckExistingAssetsResponseDto(existingAssets.map(a => a.deviceAssetId));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -48,6 +48,8 @@ import { GetAssetCountByTimeBucketDto } from './dto/get-asset-count-by-time-buck
 | 
			
		||||
import { GetAssetByTimeBucketDto } from './dto/get-asset-by-time-bucket.dto';
 | 
			
		||||
import { QueryFailedError } from 'typeorm';
 | 
			
		||||
import { AssetCountByUserIdResponseDto } from './response-dto/asset-count-by-user-id-response.dto';
 | 
			
		||||
import { CheckExistingAssetsDto } from './dto/check-existing-assets.dto';
 | 
			
		||||
import { CheckExistingAssetsResponseDto } from './response-dto/check-existing-assets-response.dto';
 | 
			
		||||
 | 
			
		||||
@UseGuards(JwtAuthGuard)
 | 
			
		||||
@ApiBearerAuth()
 | 
			
		||||
@ -74,6 +76,7 @@ export class AssetController {
 | 
			
		||||
    @GetAuthUser() authUser: AuthUserDto,
 | 
			
		||||
    @UploadedFile() file: Express.Multer.File,
 | 
			
		||||
    @Body(ValidationPipe) assetInfo: CreateAssetDto,
 | 
			
		||||
    @Response({ passthrough: true }) res: Res,
 | 
			
		||||
  ): Promise<AssetFileUploadResponseDto> {
 | 
			
		||||
    const checksum = await this.assetService.calculateChecksum(file.path);
 | 
			
		||||
 | 
			
		||||
@ -111,6 +114,7 @@ export class AssetController {
 | 
			
		||||
 | 
			
		||||
      if (err instanceof QueryFailedError && (err as any).constraint === 'UQ_userid_checksum') {
 | 
			
		||||
        const existedAsset = await this.assetService.getAssetByChecksum(authUser.id, checksum);
 | 
			
		||||
        res.status(200); // normal POST is 201. we use 200 to indicate the asset already exists
 | 
			
		||||
        return new AssetFileUploadResponseDto(existedAsset.id);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -254,4 +258,16 @@ export class AssetController {
 | 
			
		||||
  ): Promise<CheckDuplicateAssetResponseDto> {
 | 
			
		||||
    return await this.assetService.checkDuplicatedAsset(authUser, checkDuplicateAssetDto);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Checks if multiple assets exist on the server and returns all existing - used by background backup 
 | 
			
		||||
   */
 | 
			
		||||
  @Post('/exist')
 | 
			
		||||
  @HttpCode(200)
 | 
			
		||||
  async checkExistingAssets(
 | 
			
		||||
    @GetAuthUser() authUser: AuthUserDto,
 | 
			
		||||
    @Body(ValidationPipe) checkExistingAssetsDto: CheckExistingAssetsDto,
 | 
			
		||||
  ): Promise<CheckExistingAssetsResponseDto> {
 | 
			
		||||
    return await this.assetService.checkExistingAssets(authUser, checkExistingAssetsDto);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -110,6 +110,7 @@ describe('AssetService', () => {
 | 
			
		||||
      getAssetWithNoEXIF: jest.fn(),
 | 
			
		||||
      getAssetWithNoThumbnail: jest.fn(),
 | 
			
		||||
      getAssetWithNoSmartInfo: jest.fn(),
 | 
			
		||||
      getExistingAssets: jest.fn(),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    sui = new AssetService(assetRepositoryMock, a);
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,8 @@ import { GetAssetCountByTimeBucketDto } from './dto/get-asset-count-by-time-buck
 | 
			
		||||
import { GetAssetByTimeBucketDto } from './dto/get-asset-by-time-bucket.dto';
 | 
			
		||||
import { AssetCountByUserIdResponseDto } from './response-dto/asset-count-by-user-id-response.dto';
 | 
			
		||||
import { timeUtils } from '@app/common/utils';
 | 
			
		||||
import { CheckExistingAssetsDto } from './dto/check-existing-assets.dto';
 | 
			
		||||
import { CheckExistingAssetsResponseDto } from './response-dto/check-existing-assets-response.dto';
 | 
			
		||||
 | 
			
		||||
const fileInfo = promisify(stat);
 | 
			
		||||
 | 
			
		||||
@ -466,6 +468,13 @@ export class AssetService {
 | 
			
		||||
    return new CheckDuplicateAssetResponseDto(isDuplicated, res?.id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async checkExistingAssets(
 | 
			
		||||
    authUser: AuthUserDto,
 | 
			
		||||
    checkExistingAssetsDto: CheckExistingAssetsDto,
 | 
			
		||||
  ): Promise<CheckExistingAssetsResponseDto> {
 | 
			
		||||
    return this._assetRepository.getExistingAssets(authUser.id, checkExistingAssetsDto);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getAssetCountByTimeBucket(
 | 
			
		||||
    authUser: AuthUserDto,
 | 
			
		||||
    getAssetCountByTimeBucketDto: GetAssetCountByTimeBucketDto,
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,9 @@
 | 
			
		||||
import { IsNotEmpty } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class CheckExistingAssetsDto {
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  deviceAssetIds!: string[];
 | 
			
		||||
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  deviceId!: string;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
export class CheckExistingAssetsResponseDto {
 | 
			
		||||
    constructor(existingIds: string[]) {
 | 
			
		||||
      this.existingIds = existingIds;
 | 
			
		||||
    }
 | 
			
		||||
    existingIds: string[];
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -452,6 +452,38 @@ export interface CheckDuplicateAssetResponseDto {
 | 
			
		||||
     */
 | 
			
		||||
    'id'?: string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @interface CheckExistingAssetsDto
 | 
			
		||||
 */
 | 
			
		||||
export interface CheckExistingAssetsDto {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {Array<string>}
 | 
			
		||||
     * @memberof CheckExistingAssetsDto
 | 
			
		||||
     */
 | 
			
		||||
    'deviceAssetIds': Array<string>;
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {string}
 | 
			
		||||
     * @memberof CheckExistingAssetsDto
 | 
			
		||||
     */
 | 
			
		||||
    'deviceId': string;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
 * @interface CheckExistingAssetsResponseDto
 | 
			
		||||
 */
 | 
			
		||||
export interface CheckExistingAssetsResponseDto {
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {Array<string>}
 | 
			
		||||
     * @memberof CheckExistingAssetsResponseDto
 | 
			
		||||
     */
 | 
			
		||||
    'existingIds': Array<string>;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @export
 | 
			
		||||
@ -2334,6 +2366,46 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
 | 
			
		||||
                options: localVarRequestOptions,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * Checks if multiple assets exist on the server and returns all existing - used by background backup
 | 
			
		||||
         * @summary 
 | 
			
		||||
         * @param {CheckExistingAssetsDto} checkExistingAssetsDto 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        checkExistingAssets: async (checkExistingAssetsDto: CheckExistingAssetsDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
 | 
			
		||||
            // verify required parameter 'checkExistingAssetsDto' is not null or undefined
 | 
			
		||||
            assertParamExists('checkExistingAssets', 'checkExistingAssetsDto', checkExistingAssetsDto)
 | 
			
		||||
            const localVarPath = `/asset/exist`;
 | 
			
		||||
            // use dummy base URL string because the URL constructor only accepts absolute URLs.
 | 
			
		||||
            const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
 | 
			
		||||
            let baseOptions;
 | 
			
		||||
            if (configuration) {
 | 
			
		||||
                baseOptions = configuration.baseOptions;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
 | 
			
		||||
            const localVarHeaderParameter = {} as any;
 | 
			
		||||
            const localVarQueryParameter = {} as any;
 | 
			
		||||
 | 
			
		||||
            // authentication bearer required
 | 
			
		||||
            // http bearer authentication required
 | 
			
		||||
            await setBearerAuthToObject(localVarHeaderParameter, configuration)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
            localVarHeaderParameter['Content-Type'] = 'application/json';
 | 
			
		||||
 | 
			
		||||
            setSearchParams(localVarUrlObj, localVarQueryParameter);
 | 
			
		||||
            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
 | 
			
		||||
            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
 | 
			
		||||
            localVarRequestOptions.data = serializeDataIfNeeded(checkExistingAssetsDto, localVarRequestOptions, configuration)
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                url: toPathString(localVarUrlObj),
 | 
			
		||||
                options: localVarRequestOptions,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {DeleteAssetDto} deleteAssetDto 
 | 
			
		||||
@ -2953,6 +3025,17 @@ export const AssetApiFp = function(configuration?: Configuration) {
 | 
			
		||||
            const localVarAxiosArgs = await localVarAxiosParamCreator.checkDuplicateAsset(checkDuplicateAssetDto, options);
 | 
			
		||||
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * Checks if multiple assets exist on the server and returns all existing - used by background backup
 | 
			
		||||
         * @summary 
 | 
			
		||||
         * @param {CheckExistingAssetsDto} checkExistingAssetsDto 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        async checkExistingAssets(checkExistingAssetsDto: CheckExistingAssetsDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<CheckExistingAssetsResponseDto>> {
 | 
			
		||||
            const localVarAxiosArgs = await localVarAxiosParamCreator.checkExistingAssets(checkExistingAssetsDto, options);
 | 
			
		||||
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {DeleteAssetDto} deleteAssetDto 
 | 
			
		||||
@ -3128,6 +3211,16 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
 | 
			
		||||
        checkDuplicateAsset(checkDuplicateAssetDto: CheckDuplicateAssetDto, options?: any): AxiosPromise<CheckDuplicateAssetResponseDto> {
 | 
			
		||||
            return localVarFp.checkDuplicateAsset(checkDuplicateAssetDto, options).then((request) => request(axios, basePath));
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * Checks if multiple assets exist on the server and returns all existing - used by background backup
 | 
			
		||||
         * @summary 
 | 
			
		||||
         * @param {CheckExistingAssetsDto} checkExistingAssetsDto 
 | 
			
		||||
         * @param {*} [options] Override http request option.
 | 
			
		||||
         * @throws {RequiredError}
 | 
			
		||||
         */
 | 
			
		||||
        checkExistingAssets(checkExistingAssetsDto: CheckExistingAssetsDto, options?: any): AxiosPromise<CheckExistingAssetsResponseDto> {
 | 
			
		||||
            return localVarFp.checkExistingAssets(checkExistingAssetsDto, options).then((request) => request(axios, basePath));
 | 
			
		||||
        },
 | 
			
		||||
        /**
 | 
			
		||||
         * 
 | 
			
		||||
         * @param {DeleteAssetDto} deleteAssetDto 
 | 
			
		||||
@ -3290,6 +3383,18 @@ export class AssetApi extends BaseAPI {
 | 
			
		||||
        return AssetApiFp(this.configuration).checkDuplicateAsset(checkDuplicateAssetDto, options).then((request) => request(this.axios, this.basePath));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if multiple assets exist on the server and returns all existing - used by background backup
 | 
			
		||||
     * @summary 
 | 
			
		||||
     * @param {CheckExistingAssetsDto} checkExistingAssetsDto 
 | 
			
		||||
     * @param {*} [options] Override http request option.
 | 
			
		||||
     * @throws {RequiredError}
 | 
			
		||||
     * @memberof AssetApi
 | 
			
		||||
     */
 | 
			
		||||
    public checkExistingAssets(checkExistingAssetsDto: CheckExistingAssetsDto, options?: AxiosRequestConfig) {
 | 
			
		||||
        return AssetApiFp(this.configuration).checkExistingAssets(checkExistingAssetsDto, options).then((request) => request(this.axios, this.basePath));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @param {DeleteAssetDto} deleteAssetDto 
 | 
			
		||||
 | 
			
		||||
@ -200,12 +200,12 @@ async function fileUploader(asset: File, uploadType: UploadType) {
 | 
			
		||||
}
 | 
			
		||||
// TODO: This should have a proper type
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
function handleUploadError(asset: File, respBody?: any) {
 | 
			
		||||
	const extraMsg = respBody ? ' ' + respBody.message : '';
 | 
			
		||||
function handleUploadError(asset: File, respBody: any, extraMessage?: string) {
 | 
			
		||||
	const extraMsg = respBody ? ' ' + respBody?.message : '';
 | 
			
		||||
 | 
			
		||||
	notificationController.show({
 | 
			
		||||
		type: NotificationType.Error,
 | 
			
		||||
		message: `Cannot upload file ${asset.name}!${extraMsg}`,
 | 
			
		||||
		message: `Cannot upload file ${asset.name} ${extraMsg}${extraMessage}`,
 | 
			
		||||
		timeout: 5000
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user