1
0
forked from Cutlery/immich

fix tests

This commit is contained in:
Jonathan Jogenfors 2024-03-17 00:54:50 +01:00
parent 0bf31bdb44
commit 9b5a0a90ce
17 changed files with 184 additions and 66 deletions

View File

@ -139,6 +139,7 @@ Class | Method | HTTP request | Description
*LibraryApi* | [**getLibrary**](doc//LibraryApi.md#getlibrary) | **GET** /library/{id} |
*LibraryApi* | [**getLibraryStatistics**](doc//LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics |
*LibraryApi* | [**removeOfflineFiles**](doc//LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline |
*LibraryApi* | [**scanDeletedFiles**](doc//LibraryApi.md#scandeletedfiles) | **POST** /library/{id}/scanDeleted |
*LibraryApi* | [**scanLibrary**](doc//LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan |
*LibraryApi* | [**updateLibrary**](doc//LibraryApi.md#updatelibrary) | **PUT** /library/{id} |
*LibraryApi* | [**validate**](doc//LibraryApi.md#validate) | **POST** /library/{id}/validate |

View File

@ -15,6 +15,7 @@ Method | HTTP request | Description
[**getLibrary**](LibraryApi.md#getlibrary) | **GET** /library/{id} |
[**getLibraryStatistics**](LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics |
[**removeOfflineFiles**](LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline |
[**scanDeletedFiles**](LibraryApi.md#scandeletedfiles) | **POST** /library/{id}/scanDeleted |
[**scanLibrary**](LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan |
[**updateLibrary**](LibraryApi.md#updatelibrary) | **PUT** /library/{id} |
[**validate**](LibraryApi.md#validate) | **POST** /library/{id}/validate |
@ -348,6 +349,60 @@ void (empty response body)
[[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)
# **scanDeletedFiles**
> scanDeletedFiles(id)
### 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 = LibraryApi();
final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
try {
api_instance.scanDeletedFiles(id);
} catch (e) {
print('Exception when calling LibraryApi->scanDeletedFiles: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**id** | **String**| |
### Return type
void (empty response body)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: Not defined
[[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)
# **scanLibrary**
> scanLibrary(id, scanLibraryDto)

View File

@ -8,7 +8,6 @@ import 'package:openapi/api.dart';
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**checkForOffline** | **bool** | | [optional]
**refreshAllFiles** | **bool** | | [optional]
**refreshModifiedFiles** | **bool** | | [optional]

View File

@ -293,6 +293,46 @@ class LibraryApi {
}
}
/// Performs an HTTP 'POST /library/{id}/scanDeleted' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> scanDeletedFilesWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/library/{id}/scanDeleted'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [String] id (required):
Future<void> scanDeletedFiles(String id,) async {
final response = await scanDeletedFilesWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
}
/// Performs an HTTP 'POST /library/{id}/scan' operation and returns the [Response].
/// Parameters:
///

View File

@ -13,19 +13,10 @@ part of openapi.api;
class ScanLibraryDto {
/// Returns a new [ScanLibraryDto] instance.
ScanLibraryDto({
this.checkForOffline,
this.refreshAllFiles,
this.refreshModifiedFiles,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? checkForOffline;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@ -44,27 +35,20 @@ class ScanLibraryDto {
@override
bool operator ==(Object other) => identical(this, other) || other is ScanLibraryDto &&
other.checkForOffline == checkForOffline &&
other.refreshAllFiles == refreshAllFiles &&
other.refreshModifiedFiles == refreshModifiedFiles;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(checkForOffline == null ? 0 : checkForOffline!.hashCode) +
(refreshAllFiles == null ? 0 : refreshAllFiles!.hashCode) +
(refreshModifiedFiles == null ? 0 : refreshModifiedFiles!.hashCode);
@override
String toString() => 'ScanLibraryDto[checkForOffline=$checkForOffline, refreshAllFiles=$refreshAllFiles, refreshModifiedFiles=$refreshModifiedFiles]';
String toString() => 'ScanLibraryDto[refreshAllFiles=$refreshAllFiles, refreshModifiedFiles=$refreshModifiedFiles]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (this.checkForOffline != null) {
json[r'checkForOffline'] = this.checkForOffline;
} else {
// json[r'checkForOffline'] = null;
}
if (this.refreshAllFiles != null) {
json[r'refreshAllFiles'] = this.refreshAllFiles;
} else {
@ -86,7 +70,6 @@ class ScanLibraryDto {
final json = value.cast<String, dynamic>();
return ScanLibraryDto(
checkForOffline: mapValueOfType<bool>(json, r'checkForOffline'),
refreshAllFiles: mapValueOfType<bool>(json, r'refreshAllFiles'),
refreshModifiedFiles: mapValueOfType<bool>(json, r'refreshModifiedFiles'),
);

View File

@ -47,6 +47,11 @@ void main() {
// TODO
});
//Future scanDeletedFiles(String id) async
test('test scanDeletedFiles', () async {
// TODO
});
//Future scanLibrary(String id, ScanLibraryDto scanLibraryDto) async
test('test scanLibrary', () async {
// TODO

View File

@ -16,11 +16,6 @@ void main() {
// final instance = ScanLibraryDto();
group('test ScanLibraryDto', () {
// bool checkForOffline
test('to test the property `checkForOffline`', () async {
// TODO
});
// bool refreshAllFiles
test('to test the property `refreshAllFiles`', () async {
// TODO

View File

@ -3603,6 +3603,41 @@
]
}
},
"/library/{id}/scanDeleted": {
"post": {
"operationId": "scanDeletedFiles",
"parameters": [
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"204": {
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"tags": [
"Library"
]
}
},
"/library/{id}/statistics": {
"get": {
"operationId": "getLibraryStatistics",
@ -8978,9 +9013,6 @@
},
"ScanLibraryDto": {
"properties": {
"checkForOffline": {
"type": "boolean"
},
"refreshAllFiles": {
"type": "boolean"
},

View File

@ -476,7 +476,6 @@ export type UpdateLibraryDto = {
name?: string;
};
export type ScanLibraryDto = {
checkForOffline?: boolean;
refreshAllFiles?: boolean;
refreshModifiedFiles?: boolean;
};
@ -1943,6 +1942,14 @@ export function scanLibrary({ id, scanLibraryDto }: {
body: scanLibraryDto
})));
}
export function scanDeletedFiles({ id }: {
id: string;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText(`/library/${encodeURIComponent(id)}/scanDeleted`, {
...opts,
method: "POST"
}));
}
export function getLibraryStatistics({ id }: {
id: string;
}, opts?: Oazapfts.RequestOpts) {

View File

@ -74,7 +74,7 @@ export enum JobName {
LIBRARY_DELETE = 'library-delete',
LIBRARY_QUEUE_SCAN_ALL = 'library-queue-all-refresh',
LIBRARY_QUEUE_CLEANUP = 'library-queue-cleanup',
LIBRARY_SCAN_OFFLINE = 'library-scan-offline',
LIBRARY_SCAN_DELETED = 'library-scan-deleted',
LIBRARY_CHECK_OFFLINE = 'library-check-if-online',
LIBRARY_REMOVE_OFFLINE = 'library-remove-offline',
@ -151,7 +151,7 @@ export const JOBS_TO_QUEUE: Record<JobName, QueueName> = {
[JobName.LIBRARY_SCAN_ASSET]: QueueName.LIBRARY,
[JobName.LIBRARY_SCAN]: QueueName.LIBRARY,
[JobName.LIBRARY_DELETE]: QueueName.LIBRARY,
[JobName.LIBRARY_SCAN_OFFLINE]: QueueName.LIBRARY,
[JobName.LIBRARY_SCAN_DELETED]: QueueName.LIBRARY,
[JobName.LIBRARY_REMOVE_OFFLINE]: QueueName.LIBRARY,
[JobName.LIBRARY_CHECK_OFFLINE]: QueueName.LIBRARY,
[JobName.LIBRARY_QUEUE_SCAN_ALL]: QueueName.LIBRARY,

View File

@ -104,9 +104,6 @@ export class ScanLibraryDto {
@ValidateBoolean({ optional: true })
refreshAllFiles?: boolean;
@ValidateBoolean({ optional: true })
checkForOffline?: boolean;
}
export class SearchLibraryDto {

View File

@ -1440,16 +1440,28 @@ describe(LibraryService.name, () => {
],
]);
});
});
it('should queue an offline file scan', async () => {
describe('queueDeletedScan', () => {
it('should not queue a deleted scan of upload library', async () => {
libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1);
await expect(sut.queueDeletedScan(authStub.admin, libraryStub.uploadLibrary1.id)).rejects.toBeInstanceOf(
BadRequestException,
);
expect(jobMock.queue).not.toBeCalled();
});
it('should queue a deleted file scan', async () => {
libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1);
await sut.queueScan(authStub.admin, libraryStub.externalLibrary1.id, { checkForOffline: true });
await sut.queueDeletedScan(authStub.admin, libraryStub.externalLibrary1.id);
expect(jobMock.queue.mock.calls).toEqual([
[
{
name: JobName.LIBRARY_SCAN_OFFLINE,
name: JobName.LIBRARY_SCAN_DELETED,
data: {
id: libraryStub.externalLibrary1.id,
},
@ -1457,28 +1469,6 @@ describe(LibraryService.name, () => {
],
]);
});
it('should error when queuing a scan with checkOffline and refreshAll', async () => {
libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1);
await expect(
sut.queueScan(authStub.admin, libraryStub.externalLibrary1.id, {
refreshAllFiles: true,
checkForOffline: true,
}),
).rejects.toBeInstanceOf(BadRequestException);
});
it('should error when queuing a scan with checkOffline and refreshModified', async () => {
libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1);
await expect(
sut.queueScan(authStub.admin, libraryStub.externalLibrary1.id, {
refreshModifiedFiles: true,
checkForOffline: true,
}),
).rejects.toBeInstanceOf(BadRequestException);
});
});
describe('queueEmptyTrash', () => {

View File

@ -559,11 +559,7 @@ export class LibraryService extends EventEmitter {
const library = await this.repository.get(id);
if (!library || library.type !== LibraryType.EXTERNAL) {
throw new BadRequestException('Can only refresh external libraries');
}
if (dto.checkForOffline) {
await this.jobRepository.queue({ name: JobName.LIBRARY_SCAN_OFFLINE, data: { id } });
throw new BadRequestException('Can only scan external libraries');
}
await this.jobRepository.queue({
@ -576,6 +572,17 @@ export class LibraryService extends EventEmitter {
});
}
async queueDeletedScan(auth: AuthDto, id: string) {
await this.access.requirePermission(auth, Permission.LIBRARY_UPDATE, id);
const library = await this.repository.get(id);
if (!library || library.type !== LibraryType.EXTERNAL) {
throw new BadRequestException('Can only scan external libraries');
}
await this.jobRepository.queue({ name: JobName.LIBRARY_SCAN_DELETED, data: { id } });
}
async queueRemoveOffline(auth: AuthDto, id: string) {
this.logger.verbose(`Removing offline files from library: ${id}`);
await this.access.requirePermission(auth, Permission.LIBRARY_UPDATE, id);

View File

@ -92,7 +92,7 @@ export type JobItem =
| { name: JobName.LIBRARY_REMOVE_OFFLINE; data: IEntityJob }
| { name: JobName.LIBRARY_DELETE; data: IEntityJob }
| { name: JobName.LIBRARY_QUEUE_SCAN_ALL; data: IBaseJob }
| { name: JobName.LIBRARY_SCAN_OFFLINE; data: IEntityJob }
| { name: JobName.LIBRARY_SCAN_DELETED; data: IEntityJob }
| { name: JobName.LIBRARY_CHECK_OFFLINE; data: IEntityJob }
| { name: JobName.LIBRARY_QUEUE_CLEANUP; data: IBaseJob };

View File

@ -69,6 +69,12 @@ export class LibraryController {
return this.service.queueScan(auth, id, dto);
}
@Post(':id/scanDeleted')
@HttpCode(HttpStatus.NO_CONTENT)
scanDeletedFiles(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto) {
return this.service.queueDeletedScan(auth, id);
}
@Post(':id/removeOffline')
@HttpCode(HttpStatus.NO_CONTENT)
removeOfflineFiles(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto) {

View File

@ -77,7 +77,7 @@ export class AppService {
[JobName.LIBRARY_SCAN_ASSET]: (data) => this.libraryService.handleAssetRefresh(data),
[JobName.LIBRARY_SCAN]: (data) => this.libraryService.handleQueueAssetRefresh(data),
[JobName.LIBRARY_DELETE]: (data) => this.libraryService.handleDeleteLibrary(data),
[JobName.LIBRARY_SCAN_OFFLINE]: (data) => this.libraryService.handleQueueOfflineCheck(data),
[JobName.LIBRARY_SCAN_DELETED]: (data) => this.libraryService.handleQueueOfflineCheck(data),
[JobName.LIBRARY_CHECK_OFFLINE]: (data) => this.libraryService.handleOfflineCheck(data),
[JobName.LIBRARY_REMOVE_OFFLINE]: (data) => this.libraryService.handleOfflineRemoval(data),
[JobName.LIBRARY_QUEUE_SCAN_ALL]: (data) => this.libraryService.handleQueueAllScan(data),

View File

@ -32,6 +32,7 @@
type LibraryResponseDto,
type LibraryStatsResponseDto,
type UserResponseDto,
scanDeletedFiles,
} from '@immich/sdk';
import { mdiDatabase, mdiDotsVertical, mdiPlusBoxOutline, mdiSync, mdiUpload } from '@mdi/js';
import { onMount } from 'svelte';
@ -207,7 +208,7 @@
const handleScanDeleted = async (libraryId: string) => {
try {
await scanLibrary({ id: libraryId, scanLibraryDto: { checkForOffline: true } });
await scanDeletedFiles({ id: libraryId });
notificationController.show({
message: `Scanning library for deleted files`,
type: NotificationType.Info,