Browse Source

refactor: deprecate getUserAssetsByDeviceId (#5273)

* refactor: deprecated getUserAssetsByDeviceId

* prevent breaking changes

* chore: add deprecation

* prevent breaking changes

* prevent breaking changes

---------

Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
shenlong 1 year ago
parent
commit
0108211c0f

+ 98 - 4
cli/src/api/open-api/api.ts

@@ -6808,6 +6808,48 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
 
 
     
+            setSearchParams(localVarUrlObj, localVarQueryParameter);
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+
+            return {
+                url: toPathString(localVarUrlObj),
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * Get all asset of a device that are in the database, ID only.
+         * @param {string} deviceId 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        getAllUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            // verify required parameter 'deviceId' is not null or undefined
+            assertParamExists('getAllUserAssetsByDeviceId', 'deviceId', deviceId)
+            const localVarPath = `/asset/device/{deviceId}`
+                .replace(`{${"deviceId"}}`, encodeURIComponent(String(deviceId)));
+            // 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: 'GET', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication cookie required
+
+            // authentication api_key required
+            await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
+
+            // authentication bearer required
+            // http bearer authentication required
+            await setBearerAuthToObject(localVarHeaderParameter, configuration)
+
+
+    
             setSearchParams(localVarUrlObj, localVarQueryParameter);
             let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
             localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@@ -7477,9 +7519,11 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
             };
         },
         /**
-         * Get all asset of a device that are in the database, ID only.
+         * 
+         * @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
          * @param {string} deviceId 
          * @param {*} [options] Override http request option.
+         * @deprecated
          * @throws {RequiredError}
          */
         getUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
@@ -8311,6 +8355,16 @@ export const AssetApiFp = function(configuration?: Configuration) {
             const localVarAxiosArgs = await localVarAxiosParamCreator.getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch, options);
             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
         },
+        /**
+         * Get all asset of a device that are in the database, ID only.
+         * @param {string} deviceId 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async getAllUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
+            const localVarAxiosArgs = await localVarAxiosParamCreator.getAllUserAssetsByDeviceId(deviceId, options);
+            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
+        },
         /**
          * Get a single asset\'s information
          * @param {string} id 
@@ -8458,9 +8512,11 @@ export const AssetApiFp = function(configuration?: Configuration) {
             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
         },
         /**
-         * Get all asset of a device that are in the database, ID only.
+         * 
+         * @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
          * @param {string} deviceId 
          * @param {*} [options] Override http request option.
+         * @deprecated
          * @throws {RequiredError}
          */
         async getUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
@@ -8686,6 +8742,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
         getAllAssets(requestParameters: AssetApiGetAllAssetsRequest = {}, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
             return localVarFp.getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(axios, basePath));
         },
+        /**
+         * Get all asset of a device that are in the database, ID only.
+         * @param {AssetApiGetAllUserAssetsByDeviceIdRequest} requestParameters Request parameters.
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        getAllUserAssetsByDeviceId(requestParameters: AssetApiGetAllUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
+            return localVarFp.getAllUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(axios, basePath));
+        },
         /**
          * Get a single asset\'s information
          * @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@@ -8792,9 +8857,11 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
             return localVarFp.getTimeBuckets(requestParameters.size, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.withPartners, requestParameters.key, options).then((request) => request(axios, basePath));
         },
         /**
-         * Get all asset of a device that are in the database, ID only.
+         * 
+         * @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
          * @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
          * @param {*} [options] Override http request option.
+         * @deprecated
          * @throws {RequiredError}
          */
         getUserAssetsByDeviceId(requestParameters: AssetApiGetUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
@@ -9030,6 +9097,20 @@ export interface AssetApiGetAllAssetsRequest {
     readonly ifNoneMatch?: string
 }
 
+/**
+ * Request parameters for getAllUserAssetsByDeviceId operation in AssetApi.
+ * @export
+ * @interface AssetApiGetAllUserAssetsByDeviceIdRequest
+ */
+export interface AssetApiGetAllUserAssetsByDeviceIdRequest {
+    /**
+     * 
+     * @type {string}
+     * @memberof AssetApiGetAllUserAssetsByDeviceId
+     */
+    readonly deviceId: string
+}
+
 /**
  * Request parameters for getAssetById operation in AssetApi.
  * @export
@@ -9974,6 +10055,17 @@ export class AssetApi extends BaseAPI {
         return AssetApiFp(this.configuration).getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(this.axios, this.basePath));
     }
 
+    /**
+     * Get all asset of a device that are in the database, ID only.
+     * @param {AssetApiGetAllUserAssetsByDeviceIdRequest} requestParameters Request parameters.
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof AssetApi
+     */
+    public getAllUserAssetsByDeviceId(requestParameters: AssetApiGetAllUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig) {
+        return AssetApiFp(this.configuration).getAllUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(this.axios, this.basePath));
+    }
+
     /**
      * Get a single asset\'s information
      * @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@@ -10104,9 +10196,11 @@ export class AssetApi extends BaseAPI {
     }
 
     /**
-     * Get all asset of a device that are in the database, ID only.
+     * 
+     * @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
      * @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
      * @param {*} [options] Override http request option.
+     * @deprecated
      * @throws {RequiredError}
      * @memberof AssetApi
      */

+ 1 - 1
mobile/ios/Podfile.lock

@@ -169,4 +169,4 @@ SPEC CHECKSUMS:
 
 PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
 
-COCOAPODS: 1.12.1
+COCOAPODS: 1.11.3

+ 3 - 0
mobile/lib/modules/backup/services/backup.service.dart

@@ -42,6 +42,9 @@ class BackupService {
 
     try {
       return await _apiService.assetApi.getUserAssetsByDeviceId(deviceId);
+
+      // TODO! Start using this in 1.92.0
+      // return await _apiService.assetApi.getAllUserAssetsByDeviceId(deviceId);
     } catch (e) {
       debugPrint('Error [getDeviceBackupAsset] ${e.toString()}');
       return null;

+ 2 - 1
mobile/openapi/README.md

@@ -98,6 +98,7 @@ Class | Method | HTTP request | Description
 *AssetApi* | [**downloadFile**](doc//AssetApi.md#downloadfile) | **POST** /asset/download/{id} | 
 *AssetApi* | [**emptyTrash**](doc//AssetApi.md#emptytrash) | **POST** /asset/trash/empty | 
 *AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset | 
+*AssetApi* | [**getAllUserAssetsByDeviceId**](doc//AssetApi.md#getalluserassetsbydeviceid) | **GET** /asset/device/{deviceId} | 
 *AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | 
 *AssetApi* | [**getAssetSearchTerms**](doc//AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms | 
 *AssetApi* | [**getAssetStatistics**](doc//AssetApi.md#getassetstatistics) | **GET** /asset/statistics | 
@@ -110,7 +111,7 @@ Class | Method | HTTP request | Description
 *AssetApi* | [**getRandom**](doc//AssetApi.md#getrandom) | **GET** /asset/random | 
 *AssetApi* | [**getTimeBucket**](doc//AssetApi.md#gettimebucket) | **GET** /asset/time-bucket | 
 *AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | 
-*AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} | 
+*AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} | Use /asset/device/:deviceId instead - Remove in 1.92 release
 *AssetApi* | [**restoreAssets**](doc//AssetApi.md#restoreassets) | **POST** /asset/restore | 
 *AssetApi* | [**restoreTrash**](doc//AssetApi.md#restoretrash) | **POST** /asset/trash/restore | 
 *AssetApi* | [**runAssetJobs**](doc//AssetApi.md#runassetjobs) | **POST** /asset/jobs | 

+ 61 - 5
mobile/openapi/doc/AssetApi.md

@@ -16,6 +16,7 @@ Method | HTTP request | Description
 [**downloadFile**](AssetApi.md#downloadfile) | **POST** /asset/download/{id} | 
 [**emptyTrash**](AssetApi.md#emptytrash) | **POST** /asset/trash/empty | 
 [**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset | 
+[**getAllUserAssetsByDeviceId**](AssetApi.md#getalluserassetsbydeviceid) | **GET** /asset/device/{deviceId} | 
 [**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | 
 [**getAssetSearchTerms**](AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms | 
 [**getAssetStatistics**](AssetApi.md#getassetstatistics) | **GET** /asset/statistics | 
@@ -28,7 +29,7 @@ Method | HTTP request | Description
 [**getRandom**](AssetApi.md#getrandom) | **GET** /asset/random | 
 [**getTimeBucket**](AssetApi.md#gettimebucket) | **GET** /asset/time-bucket | 
 [**getTimeBuckets**](AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | 
-[**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} | 
+[**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} | Use /asset/device/:deviceId instead - Remove in 1.92 release
 [**restoreAssets**](AssetApi.md#restoreassets) | **POST** /asset/restore | 
 [**restoreTrash**](AssetApi.md#restoretrash) | **POST** /asset/trash/restore | 
 [**runAssetJobs**](AssetApi.md#runassetjobs) | **POST** /asset/jobs | 
@@ -443,6 +444,63 @@ 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)
 
+# **getAllUserAssetsByDeviceId**
+> List<String> getAllUserAssetsByDeviceId(deviceId)
+
+
+
+Get all asset of a device that are in the database, ID only.
+
+### Example
+```dart
+import 'package:openapi/api.dart';
+// TODO Configure API key authorization: cookie
+//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
+// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
+//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
+// TODO Configure API key authorization: api_key
+//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
+// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
+//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
+// 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 deviceId = deviceId_example; // String | 
+
+try {
+    final result = api_instance.getAllUserAssetsByDeviceId(deviceId);
+    print(result);
+} catch (e) {
+    print('Exception when calling AssetApi->getAllUserAssetsByDeviceId: $e\n');
+}
+```
+
+### Parameters
+
+Name | Type | Description  | Notes
+------------- | ------------- | ------------- | -------------
+ **deviceId** | **String**|  | 
+
+### Return type
+
+**List<String>**
+
+### Authorization
+
+[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **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)
+
 # **getAssetById**
 > AssetResponseDto getAssetById(id, key)
 
@@ -1154,9 +1212,7 @@ Name | Type | Description  | Notes
 # **getUserAssetsByDeviceId**
 > List<String> getUserAssetsByDeviceId(deviceId)
 
-
-
-Get all asset of a device that are in the database, ID only.
+Use /asset/device/:deviceId instead - Remove in 1.92 release
 
 ### Example
 ```dart
@@ -1177,7 +1233,7 @@ import 'package:openapi/api.dart';
 //defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 
 final api_instance = AssetApi();
-final deviceId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | 
+final deviceId = deviceId_example; // String | 
 
 try {
     final result = api_instance.getUserAssetsByDeviceId(deviceId);

+ 58 - 2
mobile/openapi/lib/api/asset_api.dart

@@ -414,6 +414,62 @@ class AssetApi {
     return null;
   }
 
+  /// Get all asset of a device that are in the database, ID only.
+  ///
+  /// Note: This method returns the HTTP [Response].
+  ///
+  /// Parameters:
+  ///
+  /// * [String] deviceId (required):
+  Future<Response> getAllUserAssetsByDeviceIdWithHttpInfo(String deviceId,) async {
+    // ignore: prefer_const_declarations
+    final path = r'/asset/device/{deviceId}'
+      .replaceAll('{deviceId}', deviceId);
+
+    // ignore: prefer_final_locals
+    Object? postBody;
+
+    final queryParams = <QueryParam>[];
+    final headerParams = <String, String>{};
+    final formParams = <String, String>{};
+
+    const contentTypes = <String>[];
+
+
+    return apiClient.invokeAPI(
+      path,
+      'GET',
+      queryParams,
+      postBody,
+      headerParams,
+      formParams,
+      contentTypes.isEmpty ? null : contentTypes.first,
+    );
+  }
+
+  /// Get all asset of a device that are in the database, ID only.
+  ///
+  /// Parameters:
+  ///
+  /// * [String] deviceId (required):
+  Future<List<String>?> getAllUserAssetsByDeviceId(String deviceId,) async {
+    final response = await getAllUserAssetsByDeviceIdWithHttpInfo(deviceId,);
+    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<String>') as List)
+        .cast<String>()
+        .toList();
+
+    }
+    return null;
+  }
+
   /// Get a single asset's information
   ///
   /// Note: This method returns the HTTP [Response].
@@ -1211,7 +1267,7 @@ class AssetApi {
     return null;
   }
 
-  /// Get all asset of a device that are in the database, ID only.
+  /// Use /asset/device/:deviceId instead - Remove in 1.92 release
   ///
   /// Note: This method returns the HTTP [Response].
   ///
@@ -1244,7 +1300,7 @@ class AssetApi {
     );
   }
 
-  /// Get all asset of a device that are in the database, ID only.
+  /// Use /asset/device/:deviceId instead - Remove in 1.92 release
   ///
   /// Parameters:
   ///

+ 8 - 1
mobile/openapi/test/asset_api_test.dart

@@ -58,6 +58,13 @@ void main() {
       // TODO
     });
 
+    // Get all asset of a device that are in the database, ID only.
+    //
+    //Future<List<String>> getAllUserAssetsByDeviceId(String deviceId) async
+    test('test getAllUserAssetsByDeviceId', () async {
+      // TODO
+    });
+
     // Get a single asset's information
     //
     //Future<AssetResponseDto> getAssetById(String id, { String key }) async
@@ -120,7 +127,7 @@ void main() {
       // TODO
     });
 
-    // Get all asset of a device that are in the database, ID only.
+    // Use /asset/device/:deviceId instead - Remove in 1.92 release
     //
     //Future<List<String>> getUserAssetsByDeviceId(String deviceId) async
     test('test getUserAssetsByDeviceId', () async {

+ 47 - 2
server/immich-openapi-specs.json

@@ -1219,6 +1219,51 @@
         ]
       }
     },
+    "/asset/device/{deviceId}": {
+      "get": {
+        "description": "Get all asset of a device that are in the database, ID only.",
+        "operationId": "getAllUserAssetsByDeviceId",
+        "parameters": [
+          {
+            "name": "deviceId",
+            "required": true,
+            "in": "path",
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "items": {
+                    "type": "string"
+                  },
+                  "type": "array"
+                }
+              }
+            },
+            "description": ""
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          },
+          {
+            "cookie": []
+          },
+          {
+            "api_key": []
+          }
+        ],
+        "tags": [
+          "Asset"
+        ]
+      }
+    },
     "/asset/download/archive": {
       "post": {
         "operationId": "downloadArchive",
@@ -2281,7 +2326,7 @@
     },
     "/asset/{deviceId}": {
       "get": {
-        "description": "Get all asset of a device that are in the database, ID only.",
+        "deprecated": true,
         "operationId": "getUserAssetsByDeviceId",
         "parameters": [
           {
@@ -2289,7 +2334,6 @@
             "required": true,
             "in": "path",
             "schema": {
-              "format": "uuid",
               "type": "string"
             }
           }
@@ -2320,6 +2364,7 @@
             "api_key": []
           }
         ],
+        "summary": "Use /asset/device/:deviceId instead - Remove in 1.92 release",
         "tags": [
           "Asset"
         ]

+ 14 - 0
server/src/domain/asset/asset.service.spec.ts

@@ -1067,4 +1067,18 @@ describe(AssetService.name, () => {
       );
     });
   });
+
+  it('get assets by device id', async () => {
+    const assets = [assetStub.image, assetStub.image1];
+
+    assetMock.getAllByDeviceId.mockImplementation(() =>
+      Promise.resolve<string[]>(Array.from(assets.map((asset) => asset.deviceAssetId))),
+    );
+
+    const deviceId = 'device-id';
+    const result = await sut.getUserAssetsByDeviceId(authStub.user1, deviceId);
+
+    expect(result.length).toEqual(2);
+    expect(result).toEqual(assets.map((asset) => asset.deviceAssetId));
+  });
 });

+ 4 - 0
server/src/domain/asset/asset.service.ts

@@ -386,6 +386,10 @@ export class AssetService {
     return assets.map((a) => mapAsset(a));
   }
 
+  async getUserAssetsByDeviceId(authUser: AuthUserDto, deviceId: string) {
+    return this.assetRepository.getAllByDeviceId(authUser.id, deviceId);
+  }
+
   async update(authUser: AuthUserDto, id: string, dto: UpdateAssetDto): Promise<AssetResponseDto> {
     await this.access.requirePermission(authUser, Permission.ASSET_UPDATE, id);
 

+ 1 - 0
server/src/domain/repositories/asset.repository.ts

@@ -162,6 +162,7 @@ export interface IAssetRepository {
   getByLibraryIdAndOriginalPath(libraryId: string, originalPath: string): Promise<AssetEntity | null>;
   deleteAll(ownerId: string): Promise<void>;
   getAll(pagination: PaginationOptions, options?: AssetSearchOptions): Paginated<AssetEntity>;
+  getAllByDeviceId(userId: string, deviceId: string): Promise<string[]>;
   updateAll(ids: string[], options: Partial<AssetEntity>): Promise<void>;
   save(asset: Pick<AssetEntity, 'id'> & Partial<AssetEntity>): Promise<AssetEntity>;
   remove(asset: AssetEntity): Promise<void>;

+ 3 - 2
server/src/immich/api-v1/asset/asset.controller.ts

@@ -14,7 +14,7 @@ import {
   UseInterceptors,
   ValidationPipe,
 } from '@nestjs/common';
-import { ApiBody, ApiConsumes, ApiHeader, ApiOkResponse, ApiTags } from '@nestjs/swagger';
+import { ApiBody, ApiConsumes, ApiHeader, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
 import { Response as Res } from 'express';
 import { AuthUser, Authenticated, SharedLinkRoute } from '../../app.guard';
 import { UUIDParamDto } from '../../controllers/dto/uuid-param.dto';
@@ -147,9 +147,10 @@ export class AssetController {
   }
 
   /**
-   * Get all asset of a device that are in the database, ID only.
+   * @deprecated Use /asset/device/:deviceId instead - Remove at 1.92 release
    */
   @Get('/:deviceId')
+  @ApiOperation({ deprecated: true, summary: 'Use /asset/device/:deviceId instead - Remove in 1.92 release' })
   getUserAssetsByDeviceId(@AuthUser() authUser: AuthUserDto, @Param() { deviceId }: DeviceIdDto) {
     return this.assetService.getUserAssetsByDeviceId(authUser, deviceId);
   }

+ 2 - 4
server/src/immich/api-v1/asset/dto/device-id.dto.ts

@@ -1,9 +1,7 @@
-import { ApiProperty } from '@nestjs/swagger';
-import { IsNotEmpty, IsUUID } from 'class-validator';
+import { IsNotEmpty, IsString } from 'class-validator';
 
 export class DeviceIdDto {
   @IsNotEmpty()
-  @IsUUID('4')
-  @ApiProperty({ format: 'uuid' })
+  @IsString()
   deviceId!: string;
 }

+ 9 - 0
server/src/immich/controllers/asset.controller.ts

@@ -38,6 +38,7 @@ import {
   StreamableFile,
 } from '@nestjs/common';
 import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
+import { DeviceIdDto } from '../api-v1/asset/dto/device-id.dto';
 import { AuthUser, Authenticated, SharedLinkRoute } from '../app.guard';
 import { UseValidation, asStreamableFile } from '../app.utils';
 import { Route } from '../interceptors';
@@ -100,6 +101,14 @@ export class AssetController {
     return this.service.downloadFile(authUser, id).then(asStreamableFile);
   }
 
+  /**
+   * Get all asset of a device that are in the database, ID only.
+   */
+  @Get('/device/:deviceId')
+  getAllUserAssetsByDeviceId(@AuthUser() authUser: AuthUserDto, @Param() { deviceId }: DeviceIdDto) {
+    return this.service.getUserAssetsByDeviceId(authUser, deviceId);
+  }
+
   @Get('statistics')
   getAssetStatistics(@AuthUser() authUser: AuthUserDto, @Query() dto: AssetStatsDto): Promise<AssetStatsResponseDto> {
     return this.service.getStatistics(authUser, dto);

+ 5 - 5
server/src/immich/controllers/search.controller.ts

@@ -19,11 +19,6 @@ import { UseValidation } from '../app.utils';
 export class SearchController {
   constructor(private service: SearchService) {}
 
-  @Get('person')
-  searchPerson(@AuthUser() authUser: AuthUserDto, @Query() dto: SearchPeopleDto): Promise<PersonResponseDto[]> {
-    return this.service.searchPerson(authUser, dto);
-  }
-
   @Get()
   search(@AuthUser() authUser: AuthUserDto, @Query() dto: SearchDto): Promise<SearchResponseDto> {
     return this.service.search(authUser, dto);
@@ -33,4 +28,9 @@ export class SearchController {
   getExploreData(@AuthUser() authUser: AuthUserDto): Promise<SearchExploreResponseDto[]> {
     return this.service.getExploreData(authUser) as Promise<SearchExploreResponseDto[]>;
   }
+
+  @Get('person')
+  searchPerson(@AuthUser() authUser: AuthUserDto, @Query() dto: SearchPeopleDto): Promise<PersonResponseDto[]> {
+    return this.service.searchPerson(authUser, dto);
+  }
 }

+ 21 - 0
server/src/infra/repositories/asset.repository.ts

@@ -326,6 +326,27 @@ export class AssetRepository implements IAssetRepository {
     });
   }
 
+  /**
+   * Get assets by device's Id on the database
+   * @param ownerId
+   * @param deviceId
+   *
+   * @returns Promise<string[]> - Array of assetIds belong to the device
+   */
+  async getAllByDeviceId(ownerId: string, deviceId: string): Promise<string[]> {
+    const items = await this.repository.find({
+      select: { deviceAssetId: true },
+      where: {
+        ownerId,
+        deviceId,
+        isVisible: true,
+      },
+      withDeleted: true,
+    });
+
+    return items.map((asset) => asset.deviceAssetId);
+  }
+
   getById(id: string): Promise<AssetEntity | null> {
     return this.repository.findOne({
       where: { id },

+ 1 - 0
server/test/repositories/asset.repository.mock.ts

@@ -18,6 +18,7 @@ export const newAssetRepositoryMock = (): jest.Mocked<IAssetRepository> => {
     getFirstAssetForAlbumId: jest.fn(),
     getLastUpdatedAssetForAlbumId: jest.fn(),
     getAll: jest.fn().mockResolvedValue({ items: [], hasNextPage: false }),
+    getAllByDeviceId: jest.fn(),
     updateAll: jest.fn(),
     getByLibraryId: jest.fn(),
     getByLibraryIdAndOriginalPath: jest.fn(),

+ 98 - 4
web/src/api/open-api/api.ts

@@ -6808,6 +6808,48 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
 
 
     
+            setSearchParams(localVarUrlObj, localVarQueryParameter);
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+
+            return {
+                url: toPathString(localVarUrlObj),
+                options: localVarRequestOptions,
+            };
+        },
+        /**
+         * Get all asset of a device that are in the database, ID only.
+         * @param {string} deviceId 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        getAllUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            // verify required parameter 'deviceId' is not null or undefined
+            assertParamExists('getAllUserAssetsByDeviceId', 'deviceId', deviceId)
+            const localVarPath = `/asset/device/{deviceId}`
+                .replace(`{${"deviceId"}}`, encodeURIComponent(String(deviceId)));
+            // 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: 'GET', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication cookie required
+
+            // authentication api_key required
+            await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
+
+            // authentication bearer required
+            // http bearer authentication required
+            await setBearerAuthToObject(localVarHeaderParameter, configuration)
+
+
+    
             setSearchParams(localVarUrlObj, localVarQueryParameter);
             let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
             localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@@ -7477,9 +7519,11 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
             };
         },
         /**
-         * Get all asset of a device that are in the database, ID only.
+         * 
+         * @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
          * @param {string} deviceId 
          * @param {*} [options] Override http request option.
+         * @deprecated
          * @throws {RequiredError}
          */
         getUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
@@ -8311,6 +8355,16 @@ export const AssetApiFp = function(configuration?: Configuration) {
             const localVarAxiosArgs = await localVarAxiosParamCreator.getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch, options);
             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
         },
+        /**
+         * Get all asset of a device that are in the database, ID only.
+         * @param {string} deviceId 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async getAllUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
+            const localVarAxiosArgs = await localVarAxiosParamCreator.getAllUserAssetsByDeviceId(deviceId, options);
+            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
+        },
         /**
          * Get a single asset\'s information
          * @param {string} id 
@@ -8458,9 +8512,11 @@ export const AssetApiFp = function(configuration?: Configuration) {
             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
         },
         /**
-         * Get all asset of a device that are in the database, ID only.
+         * 
+         * @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
          * @param {string} deviceId 
          * @param {*} [options] Override http request option.
+         * @deprecated
          * @throws {RequiredError}
          */
         async getUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
@@ -8686,6 +8742,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
         getAllAssets(requestParameters: AssetApiGetAllAssetsRequest = {}, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
             return localVarFp.getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(axios, basePath));
         },
+        /**
+         * Get all asset of a device that are in the database, ID only.
+         * @param {AssetApiGetAllUserAssetsByDeviceIdRequest} requestParameters Request parameters.
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        getAllUserAssetsByDeviceId(requestParameters: AssetApiGetAllUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
+            return localVarFp.getAllUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(axios, basePath));
+        },
         /**
          * Get a single asset\'s information
          * @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@@ -8792,9 +8857,11 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
             return localVarFp.getTimeBuckets(requestParameters.size, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.withPartners, requestParameters.key, options).then((request) => request(axios, basePath));
         },
         /**
-         * Get all asset of a device that are in the database, ID only.
+         * 
+         * @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
          * @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
          * @param {*} [options] Override http request option.
+         * @deprecated
          * @throws {RequiredError}
          */
         getUserAssetsByDeviceId(requestParameters: AssetApiGetUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
@@ -9030,6 +9097,20 @@ export interface AssetApiGetAllAssetsRequest {
     readonly ifNoneMatch?: string
 }
 
+/**
+ * Request parameters for getAllUserAssetsByDeviceId operation in AssetApi.
+ * @export
+ * @interface AssetApiGetAllUserAssetsByDeviceIdRequest
+ */
+export interface AssetApiGetAllUserAssetsByDeviceIdRequest {
+    /**
+     * 
+     * @type {string}
+     * @memberof AssetApiGetAllUserAssetsByDeviceId
+     */
+    readonly deviceId: string
+}
+
 /**
  * Request parameters for getAssetById operation in AssetApi.
  * @export
@@ -9974,6 +10055,17 @@ export class AssetApi extends BaseAPI {
         return AssetApiFp(this.configuration).getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(this.axios, this.basePath));
     }
 
+    /**
+     * Get all asset of a device that are in the database, ID only.
+     * @param {AssetApiGetAllUserAssetsByDeviceIdRequest} requestParameters Request parameters.
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof AssetApi
+     */
+    public getAllUserAssetsByDeviceId(requestParameters: AssetApiGetAllUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig) {
+        return AssetApiFp(this.configuration).getAllUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(this.axios, this.basePath));
+    }
+
     /**
      * Get a single asset\'s information
      * @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@@ -10104,9 +10196,11 @@ export class AssetApi extends BaseAPI {
     }
 
     /**
-     * Get all asset of a device that are in the database, ID only.
+     * 
+     * @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
      * @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
      * @param {*} [options] Override http request option.
+     * @deprecated
      * @throws {RequiredError}
      * @memberof AssetApi
      */