mirror of
https://github.com/immich-app/immich.git
synced 2025-01-01 08:31:59 +00:00
refactor(server): trash endpoints (#6652)
* refactor(server): trash endpoints * chore: open api * chore: fix wrong rename
This commit is contained in:
parent
33757689fe
commit
96b7885583
27 changed files with 601 additions and 104 deletions
|
@ -22,7 +22,7 @@ class TrashService {
|
||||||
try {
|
try {
|
||||||
List<String> remoteIds =
|
List<String> remoteIds =
|
||||||
assetList.where((a) => a.isRemote).map((e) => e.remoteId!).toList();
|
assetList.where((a) => a.isRemote).map((e) => e.remoteId!).toList();
|
||||||
await _apiService.assetApi.restoreAssets(BulkIdsDto(ids: remoteIds));
|
await _apiService.assetApi.restoreAssetsOld(BulkIdsDto(ids: remoteIds));
|
||||||
return true;
|
return true;
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Cannot restore assets ${error.toString()}", error, stack);
|
_log.severe("Cannot restore assets ${error.toString()}", error, stack);
|
||||||
|
@ -32,7 +32,7 @@ class TrashService {
|
||||||
|
|
||||||
Future<void> emptyTrash() async {
|
Future<void> emptyTrash() async {
|
||||||
try {
|
try {
|
||||||
await _apiService.assetApi.emptyTrash();
|
await _apiService.assetApi.emptyTrashOld();
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Cannot empty trash ${error.toString()}", error, stack);
|
_log.severe("Cannot empty trash ${error.toString()}", error, stack);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class TrashService {
|
||||||
|
|
||||||
Future<void> restoreTrash() async {
|
Future<void> restoreTrash() async {
|
||||||
try {
|
try {
|
||||||
await _apiService.assetApi.restoreTrash();
|
await _apiService.assetApi.restoreTrashOld();
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
_log.severe("Cannot restore trash ${error.toString()}", error, stack);
|
_log.severe("Cannot restore trash ${error.toString()}", error, stack);
|
||||||
}
|
}
|
||||||
|
|
3
mobile/openapi/.openapi-generator/FILES
generated
3
mobile/openapi/.openapi-generator/FILES
generated
|
@ -165,6 +165,7 @@ doc/TimeBucketSize.md
|
||||||
doc/ToneMapping.md
|
doc/ToneMapping.md
|
||||||
doc/TranscodeHWAccel.md
|
doc/TranscodeHWAccel.md
|
||||||
doc/TranscodePolicy.md
|
doc/TranscodePolicy.md
|
||||||
|
doc/TrashApi.md
|
||||||
doc/UpdateAlbumDto.md
|
doc/UpdateAlbumDto.md
|
||||||
doc/UpdateAssetDto.md
|
doc/UpdateAssetDto.md
|
||||||
doc/UpdateLibraryDto.md
|
doc/UpdateLibraryDto.md
|
||||||
|
@ -199,6 +200,7 @@ lib/api/server_info_api.dart
|
||||||
lib/api/shared_link_api.dart
|
lib/api/shared_link_api.dart
|
||||||
lib/api/system_config_api.dart
|
lib/api/system_config_api.dart
|
||||||
lib/api/tag_api.dart
|
lib/api/tag_api.dart
|
||||||
|
lib/api/trash_api.dart
|
||||||
lib/api/user_api.dart
|
lib/api/user_api.dart
|
||||||
lib/api_client.dart
|
lib/api_client.dart
|
||||||
lib/api_exception.dart
|
lib/api_exception.dart
|
||||||
|
@ -528,6 +530,7 @@ test/time_bucket_size_test.dart
|
||||||
test/tone_mapping_test.dart
|
test/tone_mapping_test.dart
|
||||||
test/transcode_hw_accel_test.dart
|
test/transcode_hw_accel_test.dart
|
||||||
test/transcode_policy_test.dart
|
test/transcode_policy_test.dart
|
||||||
|
test/trash_api_test.dart
|
||||||
test/update_album_dto_test.dart
|
test/update_album_dto_test.dart
|
||||||
test/update_asset_dto_test.dart
|
test/update_asset_dto_test.dart
|
||||||
test/update_library_dto_test.dart
|
test/update_library_dto_test.dart
|
||||||
|
|
BIN
mobile/openapi/README.md
generated
BIN
mobile/openapi/README.md
generated
Binary file not shown.
BIN
mobile/openapi/doc/AssetApi.md
generated
BIN
mobile/openapi/doc/AssetApi.md
generated
Binary file not shown.
BIN
mobile/openapi/doc/TrashApi.md
generated
Normal file
BIN
mobile/openapi/doc/TrashApi.md
generated
Normal file
Binary file not shown.
BIN
mobile/openapi/lib/api.dart
generated
BIN
mobile/openapi/lib/api.dart
generated
Binary file not shown.
BIN
mobile/openapi/lib/api/asset_api.dart
generated
BIN
mobile/openapi/lib/api/asset_api.dart
generated
Binary file not shown.
BIN
mobile/openapi/lib/api/trash_api.dart
generated
Normal file
BIN
mobile/openapi/lib/api/trash_api.dart
generated
Normal file
Binary file not shown.
BIN
mobile/openapi/test/asset_api_test.dart
generated
BIN
mobile/openapi/test/asset_api_test.dart
generated
Binary file not shown.
BIN
mobile/openapi/test/trash_api_test.dart
generated
Normal file
BIN
mobile/openapi/test/trash_api_test.dart
generated
Normal file
Binary file not shown.
|
@ -1734,7 +1734,7 @@
|
||||||
},
|
},
|
||||||
"/asset/restore": {
|
"/asset/restore": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "restoreAssets",
|
"operationId": "restoreAssetsOld",
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
"content": {
|
"content": {
|
||||||
|
@ -2219,7 +2219,7 @@
|
||||||
},
|
},
|
||||||
"/asset/trash/empty": {
|
"/asset/trash/empty": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "emptyTrash",
|
"operationId": "emptyTrashOld",
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
"responses": {
|
"responses": {
|
||||||
"204": {
|
"204": {
|
||||||
|
@ -2244,7 +2244,7 @@
|
||||||
},
|
},
|
||||||
"/asset/trash/restore": {
|
"/asset/trash/restore": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "restoreTrash",
|
"operationId": "restoreTrashOld",
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
"responses": {
|
"responses": {
|
||||||
"204": {
|
"204": {
|
||||||
|
@ -5983,6 +5983,91 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/trash/empty": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "emptyTrash",
|
||||||
|
"parameters": [],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearer": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cookie": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Trash"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/trash/restore": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "restoreTrash",
|
||||||
|
"parameters": [],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearer": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cookie": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Trash"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/trash/restore/assets": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "restoreAssets",
|
||||||
|
"parameters": [],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/BulkIdsDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearer": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cookie": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Trash"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/user": {
|
"/user": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "getAllUsers",
|
"operationId": "getAllUsers",
|
||||||
|
|
325
open-api/typescript-sdk/client/api.ts
generated
325
open-api/typescript-sdk/client/api.ts
generated
|
@ -7026,7 +7026,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
emptyTrash: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
emptyTrashOld: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/asset/trash/empty`;
|
const localVarPath = `/asset/trash/empty`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
@ -7896,9 +7896,9 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
restoreAssets: async (bulkIdsDto: BulkIdsDto, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
restoreAssetsOld: async (bulkIdsDto: BulkIdsDto, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'bulkIdsDto' is not null or undefined
|
// verify required parameter 'bulkIdsDto' is not null or undefined
|
||||||
assertParamExists('restoreAssets', 'bulkIdsDto', bulkIdsDto)
|
assertParamExists('restoreAssetsOld', 'bulkIdsDto', bulkIdsDto)
|
||||||
const localVarPath = `/asset/restore`;
|
const localVarPath = `/asset/restore`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
@ -7939,7 +7939,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
restoreTrash: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
restoreTrashOld: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/asset/trash/restore`;
|
const localVarPath = `/asset/trash/restore`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
@ -8672,10 +8672,10 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async emptyTrash(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
async emptyTrashOld(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.emptyTrash(options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.emptyTrashOld(options);
|
||||||
const index = configuration?.serverIndex ?? 0;
|
const index = configuration?.serverIndex ?? 0;
|
||||||
const operationBasePath = operationServerMap['AssetApi.emptyTrash']?.[index]?.url;
|
const operationBasePath = operationServerMap['AssetApi.emptyTrashOld']?.[index]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -8899,10 +8899,10 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async restoreAssets(bulkIdsDto: BulkIdsDto, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
async restoreAssetsOld(bulkIdsDto: BulkIdsDto, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.restoreAssets(bulkIdsDto, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.restoreAssetsOld(bulkIdsDto, options);
|
||||||
const index = configuration?.serverIndex ?? 0;
|
const index = configuration?.serverIndex ?? 0;
|
||||||
const operationBasePath = operationServerMap['AssetApi.restoreAssets']?.[index]?.url;
|
const operationBasePath = operationServerMap['AssetApi.restoreAssetsOld']?.[index]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -8910,10 +8910,10 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async restoreTrash(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
async restoreTrashOld(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.restoreTrash(options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.restoreTrashOld(options);
|
||||||
const index = configuration?.serverIndex ?? 0;
|
const index = configuration?.serverIndex ?? 0;
|
||||||
const operationBasePath = operationServerMap['AssetApi.restoreTrash']?.[index]?.url;
|
const operationBasePath = operationServerMap['AssetApi.restoreTrashOld']?.[index]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -9118,8 +9118,8 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
emptyTrash(options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
emptyTrashOld(options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
return localVarFp.emptyTrash(options).then((request) => request(axios, basePath));
|
return localVarFp.emptyTrashOld(options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Get all AssetEntity belong to the user
|
* Get all AssetEntity belong to the user
|
||||||
|
@ -9256,20 +9256,20 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {AssetApiRestoreAssetsRequest} requestParameters Request parameters.
|
* @param {AssetApiRestoreAssetsOldRequest} requestParameters Request parameters.
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
restoreAssets(requestParameters: AssetApiRestoreAssetsRequest, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
restoreAssetsOld(requestParameters: AssetApiRestoreAssetsOldRequest, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
return localVarFp.restoreAssets(requestParameters.bulkIdsDto, options).then((request) => request(axios, basePath));
|
return localVarFp.restoreAssetsOld(requestParameters.bulkIdsDto, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
restoreTrash(options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
restoreTrashOld(options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
return localVarFp.restoreTrash(options).then((request) => request(axios, basePath));
|
return localVarFp.restoreTrashOld(options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -9849,15 +9849,15 @@ export interface AssetApiGetTimeBucketsRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request parameters for restoreAssets operation in AssetApi.
|
* Request parameters for restoreAssetsOld operation in AssetApi.
|
||||||
* @export
|
* @export
|
||||||
* @interface AssetApiRestoreAssetsRequest
|
* @interface AssetApiRestoreAssetsOldRequest
|
||||||
*/
|
*/
|
||||||
export interface AssetApiRestoreAssetsRequest {
|
export interface AssetApiRestoreAssetsOldRequest {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {BulkIdsDto}
|
* @type {BulkIdsDto}
|
||||||
* @memberof AssetApiRestoreAssets
|
* @memberof AssetApiRestoreAssetsOld
|
||||||
*/
|
*/
|
||||||
readonly bulkIdsDto: BulkIdsDto
|
readonly bulkIdsDto: BulkIdsDto
|
||||||
}
|
}
|
||||||
|
@ -10434,8 +10434,8 @@ export class AssetApi extends BaseAPI {
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof AssetApi
|
* @memberof AssetApi
|
||||||
*/
|
*/
|
||||||
public emptyTrash(options?: RawAxiosRequestConfig) {
|
public emptyTrashOld(options?: RawAxiosRequestConfig) {
|
||||||
return AssetApiFp(this.configuration).emptyTrash(options).then((request) => request(this.axios, this.basePath));
|
return AssetApiFp(this.configuration).emptyTrashOld(options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10603,13 +10603,13 @@ export class AssetApi extends BaseAPI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {AssetApiRestoreAssetsRequest} requestParameters Request parameters.
|
* @param {AssetApiRestoreAssetsOldRequest} requestParameters Request parameters.
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof AssetApi
|
* @memberof AssetApi
|
||||||
*/
|
*/
|
||||||
public restoreAssets(requestParameters: AssetApiRestoreAssetsRequest, options?: RawAxiosRequestConfig) {
|
public restoreAssetsOld(requestParameters: AssetApiRestoreAssetsOldRequest, options?: RawAxiosRequestConfig) {
|
||||||
return AssetApiFp(this.configuration).restoreAssets(requestParameters.bulkIdsDto, options).then((request) => request(this.axios, this.basePath));
|
return AssetApiFp(this.configuration).restoreAssetsOld(requestParameters.bulkIdsDto, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10618,8 +10618,8 @@ export class AssetApi extends BaseAPI {
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof AssetApi
|
* @memberof AssetApi
|
||||||
*/
|
*/
|
||||||
public restoreTrash(options?: RawAxiosRequestConfig) {
|
public restoreTrashOld(options?: RawAxiosRequestConfig) {
|
||||||
return AssetApiFp(this.configuration).restoreTrash(options).then((request) => request(this.axios, this.basePath));
|
return AssetApiFp(this.configuration).restoreTrashOld(options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18135,6 +18135,269 @@ export class TagApi extends BaseAPI {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TrashApi - axios parameter creator
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const TrashApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
emptyTrash: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
const localVarPath = `/trash/empty`;
|
||||||
|
// 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 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};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {BulkIdsDto} bulkIdsDto
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
restoreAssets: async (bulkIdsDto: BulkIdsDto, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'bulkIdsDto' is not null or undefined
|
||||||
|
assertParamExists('restoreAssets', 'bulkIdsDto', bulkIdsDto)
|
||||||
|
const localVarPath = `/trash/restore/assets`;
|
||||||
|
// 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 cookie required
|
||||||
|
|
||||||
|
// authentication api_key required
|
||||||
|
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
|
||||||
|
|
||||||
|
// 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(bulkIdsDto, localVarRequestOptions, configuration)
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
restoreTrash: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
const localVarPath = `/trash/restore`;
|
||||||
|
// 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 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};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TrashApi - functional programming interface
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const TrashApiFp = function(configuration?: Configuration) {
|
||||||
|
const localVarAxiosParamCreator = TrashApiAxiosParamCreator(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async emptyTrash(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.emptyTrash(options);
|
||||||
|
const index = configuration?.serverIndex ?? 0;
|
||||||
|
const operationBasePath = operationServerMap['TrashApi.emptyTrash']?.[index]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {BulkIdsDto} bulkIdsDto
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async restoreAssets(bulkIdsDto: BulkIdsDto, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.restoreAssets(bulkIdsDto, options);
|
||||||
|
const index = configuration?.serverIndex ?? 0;
|
||||||
|
const operationBasePath = operationServerMap['TrashApi.restoreAssets']?.[index]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async restoreTrash(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.restoreTrash(options);
|
||||||
|
const index = configuration?.serverIndex ?? 0;
|
||||||
|
const operationBasePath = operationServerMap['TrashApi.restoreTrash']?.[index]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TrashApi - factory interface
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const TrashApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||||
|
const localVarFp = TrashApiFp(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
emptyTrash(options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
|
return localVarFp.emptyTrash(options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {TrashApiRestoreAssetsRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
restoreAssets(requestParameters: TrashApiRestoreAssetsRequest, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
|
return localVarFp.restoreAssets(requestParameters.bulkIdsDto, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
restoreTrash(options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
|
return localVarFp.restoreTrash(options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for restoreAssets operation in TrashApi.
|
||||||
|
* @export
|
||||||
|
* @interface TrashApiRestoreAssetsRequest
|
||||||
|
*/
|
||||||
|
export interface TrashApiRestoreAssetsRequest {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {BulkIdsDto}
|
||||||
|
* @memberof TrashApiRestoreAssets
|
||||||
|
*/
|
||||||
|
readonly bulkIdsDto: BulkIdsDto
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TrashApi - object-oriented interface
|
||||||
|
* @export
|
||||||
|
* @class TrashApi
|
||||||
|
* @extends {BaseAPI}
|
||||||
|
*/
|
||||||
|
export class TrashApi extends BaseAPI {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof TrashApi
|
||||||
|
*/
|
||||||
|
public emptyTrash(options?: RawAxiosRequestConfig) {
|
||||||
|
return TrashApiFp(this.configuration).emptyTrash(options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {TrashApiRestoreAssetsRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof TrashApi
|
||||||
|
*/
|
||||||
|
public restoreAssets(requestParameters: TrashApiRestoreAssetsRequest, options?: RawAxiosRequestConfig) {
|
||||||
|
return TrashApiFp(this.configuration).restoreAssets(requestParameters.bulkIdsDto, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof TrashApi
|
||||||
|
*/
|
||||||
|
public restoreTrash(options?: RawAxiosRequestConfig) {
|
||||||
|
return TrashApiFp(this.configuration).restoreTrash(options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UserApi - axios parameter creator
|
* UserApi - axios parameter creator
|
||||||
* @export
|
* @export
|
||||||
|
|
|
@ -679,25 +679,6 @@ describe(AssetService.name, () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('restoreAll', () => {
|
|
||||||
it('should require asset restore access for all ids', async () => {
|
|
||||||
await expect(
|
|
||||||
sut.deleteAll(authStub.user1, {
|
|
||||||
ids: ['asset-1'],
|
|
||||||
}),
|
|
||||||
).rejects.toBeInstanceOf(BadRequestException);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should restore a batch of assets', async () => {
|
|
||||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset1', 'asset2']));
|
|
||||||
|
|
||||||
await sut.restoreAll(authStub.user1, { ids: ['asset1', 'asset2'] });
|
|
||||||
|
|
||||||
expect(assetMock.restoreAll).toHaveBeenCalledWith(['asset1', 'asset2']);
|
|
||||||
expect(jobMock.queue.mock.calls).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('handleAssetDeletion', () => {
|
describe('handleAssetDeletion', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
when(jobMock.queue)
|
when(jobMock.queue)
|
||||||
|
|
|
@ -37,14 +37,12 @@ import {
|
||||||
MemoryLaneDto,
|
MemoryLaneDto,
|
||||||
TimeBucketAssetDto,
|
TimeBucketAssetDto,
|
||||||
TimeBucketDto,
|
TimeBucketDto,
|
||||||
TrashAction,
|
|
||||||
UpdateAssetDto,
|
UpdateAssetDto,
|
||||||
UpdateStackParentDto,
|
UpdateStackParentDto,
|
||||||
mapStats,
|
mapStats,
|
||||||
} from './dto';
|
} from './dto';
|
||||||
import {
|
import {
|
||||||
AssetResponseDto,
|
AssetResponseDto,
|
||||||
BulkIdsDto,
|
|
||||||
MapMarkerResponseDto,
|
MapMarkerResponseDto,
|
||||||
MemoryLaneResponseDto,
|
MemoryLaneResponseDto,
|
||||||
SanitizedAssetResponseDto,
|
SanitizedAssetResponseDto,
|
||||||
|
@ -451,37 +449,6 @@ export class AssetService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleTrashAction(auth: AuthDto, action: TrashAction): Promise<void> {
|
|
||||||
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) =>
|
|
||||||
this.assetRepository.getByUserId(pagination, auth.user.id, { trashedBefore: DateTime.now().toJSDate() }),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (action == TrashAction.RESTORE_ALL) {
|
|
||||||
for await (const assets of assetPagination) {
|
|
||||||
const ids = assets.map((a) => a.id);
|
|
||||||
await this.assetRepository.restoreAll(ids);
|
|
||||||
this.communicationRepository.send(ClientEvent.ASSET_RESTORE, auth.user.id, ids);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action == TrashAction.EMPTY_ALL) {
|
|
||||||
for await (const assets of assetPagination) {
|
|
||||||
await this.jobRepository.queueAll(
|
|
||||||
assets.map((asset) => ({ name: JobName.ASSET_DELETION, data: { id: asset.id } })),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async restoreAll(auth: AuthDto, dto: BulkIdsDto): Promise<void> {
|
|
||||||
const { ids } = dto;
|
|
||||||
await this.access.requirePermission(auth, Permission.ASSET_RESTORE, ids);
|
|
||||||
await this.assetRepository.restoreAll(ids);
|
|
||||||
this.communicationRepository.send(ClientEvent.ASSET_RESTORE, auth.user.id, ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateStackParent(auth: AuthDto, dto: UpdateStackParentDto): Promise<void> {
|
async updateStackParent(auth: AuthDto, dto: UpdateStackParentDto): Promise<void> {
|
||||||
const { oldParentId, newParentId } = dto;
|
const { oldParentId, newParentId } = dto;
|
||||||
await this.access.requirePermission(auth, Permission.ASSET_READ, oldParentId);
|
await this.access.requirePermission(auth, Permission.ASSET_READ, oldParentId);
|
||||||
|
|
|
@ -246,11 +246,6 @@ export class RandomAssetsDto {
|
||||||
count?: number;
|
count?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TrashAction {
|
|
||||||
EMPTY_ALL = 'empty-all',
|
|
||||||
RESTORE_ALL = 'restore-all',
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AssetBulkDeleteDto extends BulkIdsDto {
|
export class AssetBulkDeleteDto extends BulkIdsDto {
|
||||||
@Optional()
|
@Optional()
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { StorageService } from './storage';
|
||||||
import { StorageTemplateService } from './storage-template';
|
import { StorageTemplateService } from './storage-template';
|
||||||
import { SystemConfigService } from './system-config';
|
import { SystemConfigService } from './system-config';
|
||||||
import { TagService } from './tag';
|
import { TagService } from './tag';
|
||||||
|
import { TrashService } from './trash';
|
||||||
import { UserService } from './user';
|
import { UserService } from './user';
|
||||||
|
|
||||||
const providers: Provider[] = [
|
const providers: Provider[] = [
|
||||||
|
@ -48,6 +49,7 @@ const providers: Provider[] = [
|
||||||
StorageTemplateService,
|
StorageTemplateService,
|
||||||
SystemConfigService,
|
SystemConfigService,
|
||||||
TagService,
|
TagService,
|
||||||
|
TrashService,
|
||||||
UserService,
|
UserService,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -26,4 +26,5 @@ export * from './storage';
|
||||||
export * from './storage-template';
|
export * from './storage-template';
|
||||||
export * from './system-config';
|
export * from './system-config';
|
||||||
export * from './tag';
|
export * from './tag';
|
||||||
|
export * from './trash';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
|
|
1
server/src/domain/trash/index.ts
Normal file
1
server/src/domain/trash/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './trash.service';
|
87
server/src/domain/trash/trash.service.spec.ts
Normal file
87
server/src/domain/trash/trash.service.spec.ts
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
import { BadRequestException } from '@nestjs/common';
|
||||||
|
import {
|
||||||
|
IAccessRepositoryMock,
|
||||||
|
assetStub,
|
||||||
|
authStub,
|
||||||
|
newAccessRepositoryMock,
|
||||||
|
newAssetRepositoryMock,
|
||||||
|
newCommunicationRepositoryMock,
|
||||||
|
newJobRepositoryMock,
|
||||||
|
} from '@test';
|
||||||
|
import { JobName } from '..';
|
||||||
|
import { ClientEvent, IAssetRepository, ICommunicationRepository, IJobRepository } from '../repositories';
|
||||||
|
import { TrashService } from './trash.service';
|
||||||
|
|
||||||
|
describe(TrashService.name, () => {
|
||||||
|
let sut: TrashService;
|
||||||
|
let accessMock: IAccessRepositoryMock;
|
||||||
|
let assetMock: jest.Mocked<IAssetRepository>;
|
||||||
|
let jobMock: jest.Mocked<IJobRepository>;
|
||||||
|
let communicationMock: jest.Mocked<ICommunicationRepository>;
|
||||||
|
|
||||||
|
it('should work', () => {
|
||||||
|
expect(sut).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
accessMock = newAccessRepositoryMock();
|
||||||
|
assetMock = newAssetRepositoryMock();
|
||||||
|
communicationMock = newCommunicationRepositoryMock();
|
||||||
|
jobMock = newJobRepositoryMock();
|
||||||
|
|
||||||
|
sut = new TrashService(accessMock, assetMock, jobMock, communicationMock);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('restoreAssets', () => {
|
||||||
|
it('should require asset restore access for all ids', async () => {
|
||||||
|
await expect(
|
||||||
|
sut.restoreAssets(authStub.user1, {
|
||||||
|
ids: ['asset-1'],
|
||||||
|
}),
|
||||||
|
).rejects.toBeInstanceOf(BadRequestException);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should restore a batch of assets', async () => {
|
||||||
|
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset1', 'asset2']));
|
||||||
|
|
||||||
|
await sut.restoreAssets(authStub.user1, { ids: ['asset1', 'asset2'] });
|
||||||
|
|
||||||
|
expect(assetMock.restoreAll).toHaveBeenCalledWith(['asset1', 'asset2']);
|
||||||
|
expect(jobMock.queue.mock.calls).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('restore', () => {
|
||||||
|
it('should handle an empty trash', async () => {
|
||||||
|
assetMock.getByUserId.mockResolvedValue({ items: [], hasNextPage: false });
|
||||||
|
await expect(sut.restore(authStub.user1)).resolves.toBeUndefined();
|
||||||
|
expect(assetMock.restoreAll).not.toHaveBeenCalled();
|
||||||
|
expect(communicationMock.send).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should restore and notify', async () => {
|
||||||
|
assetMock.getByUserId.mockResolvedValue({ items: [assetStub.image], hasNextPage: false });
|
||||||
|
await expect(sut.restore(authStub.user1)).resolves.toBeUndefined();
|
||||||
|
expect(assetMock.restoreAll).toHaveBeenCalledWith([assetStub.image.id]);
|
||||||
|
expect(communicationMock.send).toHaveBeenCalledWith(ClientEvent.ASSET_RESTORE, authStub.user1.user.id, [
|
||||||
|
assetStub.image.id,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('empty', () => {
|
||||||
|
it('should handle an empty trash', async () => {
|
||||||
|
assetMock.getByUserId.mockResolvedValue({ items: [], hasNextPage: false });
|
||||||
|
await expect(sut.empty(authStub.user1)).resolves.toBeUndefined();
|
||||||
|
expect(jobMock.queueAll).toHaveBeenCalledWith([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should empty the trash', async () => {
|
||||||
|
assetMock.getByUserId.mockResolvedValue({ items: [assetStub.image], hasNextPage: false });
|
||||||
|
await expect(sut.empty(authStub.user1)).resolves.toBeUndefined();
|
||||||
|
expect(jobMock.queueAll).toHaveBeenCalledWith([
|
||||||
|
{ name: JobName.ASSET_DELETION, data: { id: assetStub.image.id } },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
65
server/src/domain/trash/trash.service.ts
Normal file
65
server/src/domain/trash/trash.service.ts
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import { Inject } from '@nestjs/common';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import { AccessCore, Permission } from '../access';
|
||||||
|
import { BulkIdsDto } from '../asset';
|
||||||
|
import { AuthDto } from '../auth';
|
||||||
|
import { usePagination } from '../domain.util';
|
||||||
|
import { JOBS_ASSET_PAGINATION_SIZE, JobName } from '../job';
|
||||||
|
import {
|
||||||
|
ClientEvent,
|
||||||
|
IAccessRepository,
|
||||||
|
IAssetRepository,
|
||||||
|
ICommunicationRepository,
|
||||||
|
IJobRepository,
|
||||||
|
} from '../repositories';
|
||||||
|
|
||||||
|
export class TrashService {
|
||||||
|
private access: AccessCore;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(IAccessRepository) accessRepository: IAccessRepository,
|
||||||
|
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
|
||||||
|
@Inject(IJobRepository) private jobRepository: IJobRepository,
|
||||||
|
@Inject(ICommunicationRepository) private communicationRepository: ICommunicationRepository,
|
||||||
|
) {
|
||||||
|
this.access = AccessCore.create(accessRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
async restoreAssets(auth: AuthDto, dto: BulkIdsDto): Promise<void> {
|
||||||
|
const { ids } = dto;
|
||||||
|
await this.access.requirePermission(auth, Permission.ASSET_RESTORE, ids);
|
||||||
|
await this.restoreAndSend(auth, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
async restore(auth: AuthDto): Promise<void> {
|
||||||
|
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) =>
|
||||||
|
this.assetRepository.getByUserId(pagination, auth.user.id, { trashedBefore: DateTime.now().toJSDate() }),
|
||||||
|
);
|
||||||
|
|
||||||
|
for await (const assets of assetPagination) {
|
||||||
|
const ids = assets.map((a) => a.id);
|
||||||
|
await this.restoreAndSend(auth, ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async empty(auth: AuthDto): Promise<void> {
|
||||||
|
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) =>
|
||||||
|
this.assetRepository.getByUserId(pagination, auth.user.id, { trashedBefore: DateTime.now().toJSDate() }),
|
||||||
|
);
|
||||||
|
|
||||||
|
for await (const assets of assetPagination) {
|
||||||
|
await this.jobRepository.queueAll(
|
||||||
|
assets.map((asset) => ({ name: JobName.ASSET_DELETION, data: { id: asset.id } })),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async restoreAndSend(auth: AuthDto, ids: string[]) {
|
||||||
|
if (ids.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.assetRepository.restoreAll(ids);
|
||||||
|
this.communicationRepository.send(ClientEvent.ASSET_RESTORE, auth.user.id, ids);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import {
|
||||||
SharedLinkController,
|
SharedLinkController,
|
||||||
SystemConfigController,
|
SystemConfigController,
|
||||||
TagController,
|
TagController,
|
||||||
|
TrashController,
|
||||||
UserController,
|
UserController,
|
||||||
} from './controllers';
|
} from './controllers';
|
||||||
import { ErrorInterceptor, FileUploadInterceptor } from './interceptors';
|
import { ErrorInterceptor, FileUploadInterceptor } from './interceptors';
|
||||||
|
@ -64,6 +65,7 @@ import { ErrorInterceptor, FileUploadInterceptor } from './interceptors';
|
||||||
SharedLinkController,
|
SharedLinkController,
|
||||||
SystemConfigController,
|
SystemConfigController,
|
||||||
TagController,
|
TagController,
|
||||||
|
TrashController,
|
||||||
UserController,
|
UserController,
|
||||||
PersonController,
|
PersonController,
|
||||||
],
|
],
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
TimeBucketAssetDto,
|
TimeBucketAssetDto,
|
||||||
TimeBucketDto,
|
TimeBucketDto,
|
||||||
TimeBucketResponseDto,
|
TimeBucketResponseDto,
|
||||||
TrashAction,
|
TrashService,
|
||||||
UpdateAssetDto as UpdateDto,
|
UpdateAssetDto as UpdateDto,
|
||||||
UpdateStackParentDto,
|
UpdateStackParentDto,
|
||||||
} from '@app/domain';
|
} from '@app/domain';
|
||||||
|
@ -69,6 +69,7 @@ export class AssetController {
|
||||||
constructor(
|
constructor(
|
||||||
private service: AssetService,
|
private service: AssetService,
|
||||||
private downloadService: DownloadService,
|
private downloadService: DownloadService,
|
||||||
|
private trashService: TrashService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get('map-marker')
|
@Get('map-marker')
|
||||||
|
@ -165,22 +166,31 @@ export class AssetController {
|
||||||
return this.service.deleteAll(auth, dto);
|
return this.service.deleteAll(auth, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `POST /trash/restore/assets`
|
||||||
|
*/
|
||||||
@Post('restore')
|
@Post('restore')
|
||||||
@HttpCode(HttpStatus.NO_CONTENT)
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
restoreAssets(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise<void> {
|
restoreAssetsOld(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise<void> {
|
||||||
return this.service.restoreAll(auth, dto);
|
return this.trashService.restoreAssets(auth, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `POST /trash/empty`
|
||||||
|
*/
|
||||||
@Post('trash/empty')
|
@Post('trash/empty')
|
||||||
@HttpCode(HttpStatus.NO_CONTENT)
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
emptyTrash(@Auth() auth: AuthDto): Promise<void> {
|
emptyTrashOld(@Auth() auth: AuthDto): Promise<void> {
|
||||||
return this.service.handleTrashAction(auth, TrashAction.EMPTY_ALL);
|
return this.trashService.empty(auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `POST /trash/restore`
|
||||||
|
*/
|
||||||
@Post('trash/restore')
|
@Post('trash/restore')
|
||||||
@HttpCode(HttpStatus.NO_CONTENT)
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
restoreTrash(@Auth() auth: AuthDto): Promise<void> {
|
restoreTrashOld(@Auth() auth: AuthDto): Promise<void> {
|
||||||
return this.service.handleTrashAction(auth, TrashAction.RESTORE_ALL);
|
return this.trashService.restore(auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put('stack/parent')
|
@Put('stack/parent')
|
||||||
|
|
|
@ -17,4 +17,5 @@ export * from './server-info.controller';
|
||||||
export * from './shared-link.controller';
|
export * from './shared-link.controller';
|
||||||
export * from './system-config.controller';
|
export * from './system-config.controller';
|
||||||
export * from './tag.controller';
|
export * from './tag.controller';
|
||||||
|
export * from './trash.controller';
|
||||||
export * from './user.controller';
|
export * from './user.controller';
|
||||||
|
|
31
server/src/immich/controllers/trash.controller.ts
Normal file
31
server/src/immich/controllers/trash.controller.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { AuthDto, BulkIdsDto, TrashService } from '@app/domain';
|
||||||
|
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';
|
||||||
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
|
import { Auth, Authenticated } from '../app.guard';
|
||||||
|
import { UseValidation } from '../app.utils';
|
||||||
|
|
||||||
|
@ApiTags('Trash')
|
||||||
|
@Controller('trash')
|
||||||
|
@Authenticated()
|
||||||
|
@UseValidation()
|
||||||
|
export class TrashController {
|
||||||
|
constructor(private service: TrashService) {}
|
||||||
|
|
||||||
|
@Post('empty')
|
||||||
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
|
emptyTrash(@Auth() auth: AuthDto): Promise<void> {
|
||||||
|
return this.service.empty(auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('restore')
|
||||||
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
|
restoreTrash(@Auth() auth: AuthDto): Promise<void> {
|
||||||
|
return this.service.restore(auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('restore/assets')
|
||||||
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
|
restoreAssets(@Auth() auth: AuthDto, @Body() dto: BulkIdsDto): Promise<void> {
|
||||||
|
return this.service.restoreAssets(auth, dto);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import {
|
||||||
ServerInfoApi,
|
ServerInfoApi,
|
||||||
SharedLinkApi,
|
SharedLinkApi,
|
||||||
SystemConfigApi,
|
SystemConfigApi,
|
||||||
|
TrashApi,
|
||||||
UserApi,
|
UserApi,
|
||||||
UserApiFp,
|
UserApiFp,
|
||||||
base,
|
base,
|
||||||
|
@ -46,6 +47,7 @@ class ImmichApi {
|
||||||
public personApi: PersonApi;
|
public personApi: PersonApi;
|
||||||
public systemConfigApi: SystemConfigApi;
|
public systemConfigApi: SystemConfigApi;
|
||||||
public userApi: UserApi;
|
public userApi: UserApi;
|
||||||
|
public trashApi: TrashApi;
|
||||||
|
|
||||||
private config: configuration.Configuration;
|
private config: configuration.Configuration;
|
||||||
private key?: string;
|
private key?: string;
|
||||||
|
@ -75,6 +77,7 @@ class ImmichApi {
|
||||||
this.personApi = new PersonApi(this.config);
|
this.personApi = new PersonApi(this.config);
|
||||||
this.systemConfigApi = new SystemConfigApi(this.config);
|
this.systemConfigApi = new SystemConfigApi(this.config);
|
||||||
this.userApi = new UserApi(this.config);
|
this.userApi = new UserApi(this.config);
|
||||||
|
this.trashApi = new TrashApi(this.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createUrl(path: string, params?: Record<string, unknown>) {
|
private createUrl(path: string, params?: Record<string, unknown>) {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ids = Array.from(getAssets()).map((a) => a.id);
|
const ids = Array.from(getAssets()).map((a) => a.id);
|
||||||
await api.assetApi.restoreAssets({ bulkIdsDto: { ids } });
|
await api.trashApi.restoreAssets({ bulkIdsDto: { ids } });
|
||||||
onRestore?.(ids);
|
onRestore?.(ids);
|
||||||
|
|
||||||
notificationController.show({
|
notificationController.show({
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
const handleEmptyTrash = async () => {
|
const handleEmptyTrash = async () => {
|
||||||
isShowEmptyConfirmation = false;
|
isShowEmptyConfirmation = false;
|
||||||
try {
|
try {
|
||||||
await api.assetApi.emptyTrash();
|
await api.trashApi.emptyTrash();
|
||||||
|
|
||||||
notificationController.show({
|
notificationController.show({
|
||||||
message: `Empty trash initiated. Refresh the page to see the changes`,
|
message: `Empty trash initiated. Refresh the page to see the changes`,
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
|
|
||||||
const handleRestoreTrash = async () => {
|
const handleRestoreTrash = async () => {
|
||||||
try {
|
try {
|
||||||
await api.assetApi.restoreTrash();
|
await api.trashApi.restoreTrash();
|
||||||
|
|
||||||
notificationController.show({
|
notificationController.show({
|
||||||
message: `Restore trash initiated. Refresh the page to see the changes`,
|
message: `Restore trash initiated. Refresh the page to see the changes`,
|
||||||
|
|
Loading…
Reference in a new issue