mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	refactor(server): shared links (#2632)
* refactor: rename share => shared-link * refactor: shared link crud methods * chore: open api
This commit is contained in:
		
							
								
								
									
										2
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							| @@ -145,11 +145,11 @@ Class | Method | HTTP request | Description | ||||
| *ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version |  | ||||
| *ServerInfoApi* | [**getStats**](doc//ServerInfoApi.md#getstats) | **GET** /server-info/stats |  | ||||
| *ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping |  | ||||
| *ShareApi* | [**editSharedLink**](doc//ShareApi.md#editsharedlink) | **PATCH** /share/{id} |  | ||||
| *ShareApi* | [**getAllSharedLinks**](doc//ShareApi.md#getallsharedlinks) | **GET** /share |  | ||||
| *ShareApi* | [**getMySharedLink**](doc//ShareApi.md#getmysharedlink) | **GET** /share/me |  | ||||
| *ShareApi* | [**getSharedLinkById**](doc//ShareApi.md#getsharedlinkbyid) | **GET** /share/{id} |  | ||||
| *ShareApi* | [**removeSharedLink**](doc//ShareApi.md#removesharedlink) | **DELETE** /share/{id} |  | ||||
| *ShareApi* | [**updateSharedLink**](doc//ShareApi.md#updatesharedlink) | **PATCH** /share/{id} |  | ||||
| *SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config |  | ||||
| *SystemConfigApi* | [**getDefaults**](doc//SystemConfigApi.md#getdefaults) | **GET** /system-config/defaults |  | ||||
| *SystemConfigApi* | [**getStorageTemplateOptions**](doc//SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options |  | ||||
|   | ||||
							
								
								
									
										116
									
								
								mobile/openapi/doc/ShareApi.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										116
									
								
								mobile/openapi/doc/ShareApi.md
									
									
									
										generated
									
									
									
								
							| @@ -9,70 +9,13 @@ All URIs are relative to */api* | ||||
| 
 | ||||
| Method | HTTP request | Description | ||||
| ------------- | ------------- | ------------- | ||||
| [**editSharedLink**](ShareApi.md#editsharedlink) | **PATCH** /share/{id} |  | ||||
| [**getAllSharedLinks**](ShareApi.md#getallsharedlinks) | **GET** /share |  | ||||
| [**getMySharedLink**](ShareApi.md#getmysharedlink) | **GET** /share/me |  | ||||
| [**getSharedLinkById**](ShareApi.md#getsharedlinkbyid) | **GET** /share/{id} |  | ||||
| [**removeSharedLink**](ShareApi.md#removesharedlink) | **DELETE** /share/{id} |  | ||||
| [**updateSharedLink**](ShareApi.md#updatesharedlink) | **PATCH** /share/{id} |  | ||||
| 
 | ||||
| 
 | ||||
| # **editSharedLink** | ||||
| > SharedLinkResponseDto editSharedLink(id, editSharedLinkDto) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ### 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 = ShareApi(); | ||||
| final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |  | ||||
| final editSharedLinkDto = EditSharedLinkDto(); // EditSharedLinkDto |  | ||||
| 
 | ||||
| try { | ||||
|     final result = api_instance.editSharedLink(id, editSharedLinkDto); | ||||
|     print(result); | ||||
| } catch (e) { | ||||
|     print('Exception when calling ShareApi->editSharedLink: $e\n'); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Parameters | ||||
| 
 | ||||
| Name | Type | Description  | Notes | ||||
| ------------- | ------------- | ------------- | ------------- | ||||
|  **id** | **String**|  |  | ||||
|  **editSharedLinkDto** | [**EditSharedLinkDto**](EditSharedLinkDto.md)|  |  | ||||
| 
 | ||||
| ### Return type | ||||
| 
 | ||||
| [**SharedLinkResponseDto**](SharedLinkResponseDto.md) | ||||
| 
 | ||||
| ### Authorization | ||||
| 
 | ||||
| [cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) | ||||
| 
 | ||||
| ### HTTP request headers | ||||
| 
 | ||||
|  - **Content-Type**: application/json | ||||
|  - **Accept**: application/json | ||||
| 
 | ||||
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) | ||||
| 
 | ||||
| # **getAllSharedLinks** | ||||
| > List<SharedLinkResponseDto> getAllSharedLinks() | ||||
| 
 | ||||
| @@ -288,3 +231,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) | ||||
| 
 | ||||
| # **updateSharedLink** | ||||
| > SharedLinkResponseDto updateSharedLink(id, editSharedLinkDto) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ### 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 = ShareApi(); | ||||
| final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |  | ||||
| final editSharedLinkDto = EditSharedLinkDto(); // EditSharedLinkDto |  | ||||
| 
 | ||||
| try { | ||||
|     final result = api_instance.updateSharedLink(id, editSharedLinkDto); | ||||
|     print(result); | ||||
| } catch (e) { | ||||
|     print('Exception when calling ShareApi->updateSharedLink: $e\n'); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Parameters | ||||
| 
 | ||||
| Name | Type | Description  | Notes | ||||
| ------------- | ------------- | ------------- | ------------- | ||||
|  **id** | **String**|  |  | ||||
|  **editSharedLinkDto** | [**EditSharedLinkDto**](EditSharedLinkDto.md)|  |  | ||||
| 
 | ||||
| ### Return type | ||||
| 
 | ||||
| [**SharedLinkResponseDto**](SharedLinkResponseDto.md) | ||||
| 
 | ||||
| ### Authorization | ||||
| 
 | ||||
| [cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) | ||||
| 
 | ||||
| ### HTTP request headers | ||||
| 
 | ||||
|  - **Content-Type**: application/json | ||||
|  - **Accept**: application/json | ||||
| 
 | ||||
| [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) | ||||
| 
 | ||||
|   | ||||
							
								
								
									
										104
									
								
								mobile/openapi/lib/api/share_api.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										104
									
								
								mobile/openapi/lib/api/share_api.dart
									
									
									
										generated
									
									
									
								
							| @@ -16,58 +16,6 @@ class ShareApi { | ||||
| 
 | ||||
|   final ApiClient apiClient; | ||||
| 
 | ||||
|   /// Performs an HTTP 'PATCH /share/{id}' operation and returns the [Response]. | ||||
|   /// Parameters: | ||||
|   /// | ||||
|   /// * [String] id (required): | ||||
|   /// | ||||
|   /// * [EditSharedLinkDto] editSharedLinkDto (required): | ||||
|   Future<Response> editSharedLinkWithHttpInfo(String id, EditSharedLinkDto editSharedLinkDto,) async { | ||||
|     // ignore: prefer_const_declarations | ||||
|     final path = r'/share/{id}' | ||||
|       .replaceAll('{id}', id); | ||||
| 
 | ||||
|     // ignore: prefer_final_locals | ||||
|     Object? postBody = editSharedLinkDto; | ||||
| 
 | ||||
|     final queryParams = <QueryParam>[]; | ||||
|     final headerParams = <String, String>{}; | ||||
|     final formParams = <String, String>{}; | ||||
| 
 | ||||
|     const contentTypes = <String>['application/json']; | ||||
| 
 | ||||
| 
 | ||||
|     return apiClient.invokeAPI( | ||||
|       path, | ||||
|       'PATCH', | ||||
|       queryParams, | ||||
|       postBody, | ||||
|       headerParams, | ||||
|       formParams, | ||||
|       contentTypes.isEmpty ? null : contentTypes.first, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Parameters: | ||||
|   /// | ||||
|   /// * [String] id (required): | ||||
|   /// | ||||
|   /// * [EditSharedLinkDto] editSharedLinkDto (required): | ||||
|   Future<SharedLinkResponseDto?> editSharedLink(String id, EditSharedLinkDto editSharedLinkDto,) async { | ||||
|     final response = await editSharedLinkWithHttpInfo(id, editSharedLinkDto,); | ||||
|     if (response.statusCode >= HttpStatus.badRequest) { | ||||
|       throw ApiException(response.statusCode, await _decodeBodyBytes(response)); | ||||
|     } | ||||
|     // When a remote server returns no body with a status of 204, we shall not decode it. | ||||
|     // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" | ||||
|     // FormatException when trying to decode an empty string. | ||||
|     if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { | ||||
|       return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'SharedLinkResponseDto',) as SharedLinkResponseDto; | ||||
|      | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   /// Performs an HTTP 'GET /share' operation and returns the [Response]. | ||||
|   Future<Response> getAllSharedLinksWithHttpInfo() async { | ||||
|     // ignore: prefer_const_declarations | ||||
| @@ -250,4 +198,56 @@ class ShareApi { | ||||
|       throw ApiException(response.statusCode, await _decodeBodyBytes(response)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /// Performs an HTTP 'PATCH /share/{id}' operation and returns the [Response]. | ||||
|   /// Parameters: | ||||
|   /// | ||||
|   /// * [String] id (required): | ||||
|   /// | ||||
|   /// * [EditSharedLinkDto] editSharedLinkDto (required): | ||||
|   Future<Response> updateSharedLinkWithHttpInfo(String id, EditSharedLinkDto editSharedLinkDto,) async { | ||||
|     // ignore: prefer_const_declarations | ||||
|     final path = r'/share/{id}' | ||||
|       .replaceAll('{id}', id); | ||||
| 
 | ||||
|     // ignore: prefer_final_locals | ||||
|     Object? postBody = editSharedLinkDto; | ||||
| 
 | ||||
|     final queryParams = <QueryParam>[]; | ||||
|     final headerParams = <String, String>{}; | ||||
|     final formParams = <String, String>{}; | ||||
| 
 | ||||
|     const contentTypes = <String>['application/json']; | ||||
| 
 | ||||
| 
 | ||||
|     return apiClient.invokeAPI( | ||||
|       path, | ||||
|       'PATCH', | ||||
|       queryParams, | ||||
|       postBody, | ||||
|       headerParams, | ||||
|       formParams, | ||||
|       contentTypes.isEmpty ? null : contentTypes.first, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Parameters: | ||||
|   /// | ||||
|   /// * [String] id (required): | ||||
|   /// | ||||
|   /// * [EditSharedLinkDto] editSharedLinkDto (required): | ||||
|   Future<SharedLinkResponseDto?> updateSharedLink(String id, EditSharedLinkDto editSharedLinkDto,) async { | ||||
|     final response = await updateSharedLinkWithHttpInfo(id, editSharedLinkDto,); | ||||
|     if (response.statusCode >= HttpStatus.badRequest) { | ||||
|       throw ApiException(response.statusCode, await _decodeBodyBytes(response)); | ||||
|     } | ||||
|     // When a remote server returns no body with a status of 204, we shall not decode it. | ||||
|     // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" | ||||
|     // FormatException when trying to decode an empty string. | ||||
|     if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { | ||||
|       return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'SharedLinkResponseDto',) as SharedLinkResponseDto; | ||||
|      | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										10
									
								
								mobile/openapi/test/share_api_test.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								mobile/openapi/test/share_api_test.dart
									
									
									
										generated
									
									
									
								
							| @@ -17,11 +17,6 @@ void main() { | ||||
|   // final instance = ShareApi(); | ||||
| 
 | ||||
|   group('tests for ShareApi', () { | ||||
|     //Future<SharedLinkResponseDto> editSharedLink(String id, EditSharedLinkDto editSharedLinkDto) async | ||||
|     test('test editSharedLink', () async { | ||||
|       // TODO | ||||
|     }); | ||||
| 
 | ||||
|     //Future<List<SharedLinkResponseDto>> getAllSharedLinks() async | ||||
|     test('test getAllSharedLinks', () async { | ||||
|       // TODO | ||||
| @@ -42,5 +37,10 @@ void main() { | ||||
|       // TODO | ||||
|     }); | ||||
| 
 | ||||
|     //Future<SharedLinkResponseDto> updateSharedLink(String id, EditSharedLinkDto editSharedLinkDto) async | ||||
|     test('test updateSharedLink', () async { | ||||
|       // TODO | ||||
|     }); | ||||
| 
 | ||||
|   }); | ||||
| } | ||||
|   | ||||
| @@ -10,13 +10,19 @@ import { AddAssetsResponseDto } from './response-dto/add-assets-response.dto'; | ||||
| import { AddAssetsDto } from './dto/add-assets.dto'; | ||||
| import { DownloadService } from '../../modules/download/download.service'; | ||||
| import { DownloadDto } from '../asset/dto/download-library.dto'; | ||||
| import { ShareCore, ISharedLinkRepository, mapSharedLink, SharedLinkResponseDto, ICryptoRepository } from '@app/domain'; | ||||
| import { | ||||
|   SharedLinkCore, | ||||
|   ISharedLinkRepository, | ||||
|   mapSharedLink, | ||||
|   SharedLinkResponseDto, | ||||
|   ICryptoRepository, | ||||
| } from '@app/domain'; | ||||
| import { CreateAlbumShareLinkDto } from './dto/create-album-shared-link.dto'; | ||||
|  | ||||
| @Injectable() | ||||
| export class AlbumService { | ||||
|   readonly logger = new Logger(AlbumService.name); | ||||
|   private shareCore: ShareCore; | ||||
|   private shareCore: SharedLinkCore; | ||||
|  | ||||
|   constructor( | ||||
|     @Inject(IAlbumRepository) private albumRepository: IAlbumRepository, | ||||
| @@ -25,7 +31,7 @@ export class AlbumService { | ||||
|     @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository, | ||||
|     @Inject(IJobRepository) private jobRepository: IJobRepository, | ||||
|   ) { | ||||
|     this.shareCore = new ShareCore(sharedLinkRepository, cryptoRepository); | ||||
|     this.shareCore = new SharedLinkCore(sharedLinkRepository, cryptoRepository); | ||||
|   } | ||||
|  | ||||
|   private async _getAlbum({ | ||||
|   | ||||
| @@ -229,7 +229,7 @@ describe('AssetService', () => { | ||||
|  | ||||
|       expect(assetRepositoryMock.getById).toHaveBeenCalledWith(asset1.id); | ||||
|       expect(sharedLinkRepositoryMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId); | ||||
|       expect(sharedLinkRepositoryMock.save).not.toHaveBeenCalled(); | ||||
|       expect(sharedLinkRepositoryMock.update).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should add assets to a shared link', async () => { | ||||
| @@ -241,13 +241,13 @@ describe('AssetService', () => { | ||||
|       assetRepositoryMock.getById.mockResolvedValue(asset1); | ||||
|       sharedLinkRepositoryMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       sharedLinkRepositoryMock.hasAssetAccess.mockResolvedValue(true); | ||||
|       sharedLinkRepositoryMock.save.mockResolvedValue(sharedLinkStub.valid); | ||||
|       sharedLinkRepositoryMock.update.mockResolvedValue(sharedLinkStub.valid); | ||||
|  | ||||
|       await expect(sut.addAssetsToSharedLink(authDto, dto)).resolves.toEqual(sharedLinkResponseStub.valid); | ||||
|  | ||||
|       expect(assetRepositoryMock.getById).toHaveBeenCalledWith(asset1.id); | ||||
|       expect(sharedLinkRepositoryMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId); | ||||
|       expect(sharedLinkRepositoryMock.save).toHaveBeenCalled(); | ||||
|       expect(sharedLinkRepositoryMock.update).toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should remove assets from a shared link', async () => { | ||||
| @@ -259,13 +259,13 @@ describe('AssetService', () => { | ||||
|       assetRepositoryMock.getById.mockResolvedValue(asset1); | ||||
|       sharedLinkRepositoryMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       sharedLinkRepositoryMock.hasAssetAccess.mockResolvedValue(true); | ||||
|       sharedLinkRepositoryMock.save.mockResolvedValue(sharedLinkStub.valid); | ||||
|       sharedLinkRepositoryMock.update.mockResolvedValue(sharedLinkStub.valid); | ||||
|  | ||||
|       await expect(sut.removeAssetsFromSharedLink(authDto, dto)).resolves.toEqual(sharedLinkResponseStub.valid); | ||||
|  | ||||
|       expect(assetRepositoryMock.getById).toHaveBeenCalledWith(asset1.id); | ||||
|       expect(sharedLinkRepositoryMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId); | ||||
|       expect(sharedLinkRepositoryMock.save).toHaveBeenCalled(); | ||||
|       expect(sharedLinkRepositoryMock.update).toHaveBeenCalled(); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   | ||||
| @@ -54,7 +54,7 @@ import { ICryptoRepository, IJobRepository } from '@app/domain'; | ||||
| import { DownloadService } from '../../modules/download/download.service'; | ||||
| import { DownloadDto } from './dto/download-library.dto'; | ||||
| import { IAlbumRepository } from '../album/album-repository'; | ||||
| import { ShareCore } from '@app/domain'; | ||||
| import { SharedLinkCore } from '@app/domain'; | ||||
| import { IPartnerRepository } from '@app/domain'; | ||||
| import { ISharedLinkRepository } from '@app/domain'; | ||||
| import { DownloadFilesDto } from './dto/download-files.dto'; | ||||
| @@ -80,7 +80,7 @@ interface ServableFile { | ||||
| @Injectable() | ||||
| export class AssetService { | ||||
|   readonly logger = new Logger(AssetService.name); | ||||
|   private shareCore: ShareCore; | ||||
|   private shareCore: SharedLinkCore; | ||||
|   private assetCore: AssetCore; | ||||
|   private partnerCore: PartnerCore; | ||||
|  | ||||
| @@ -97,7 +97,7 @@ export class AssetService { | ||||
|     @Inject(IPartnerRepository) private partnerRepository: IPartnerRepository, | ||||
|   ) { | ||||
|     this.assetCore = new AssetCore(_assetRepository, jobRepository); | ||||
|     this.shareCore = new ShareCore(sharedLinkRepository, cryptoRepository); | ||||
|     this.shareCore = new SharedLinkCore(sharedLinkRepository, cryptoRepository); | ||||
|     this.partnerCore = new PartnerCore(partnerRepository); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { AuthUserDto, EditSharedLinkDto, SharedLinkResponseDto, ShareService } from '@app/domain'; | ||||
| import { AuthUserDto, EditSharedLinkDto, SharedLinkResponseDto, SharedLinkService } from '@app/domain'; | ||||
| import { Body, Controller, Delete, Get, Param, Patch } from '@nestjs/common'; | ||||
| import { ApiTags } from '@nestjs/swagger'; | ||||
| import { GetAuthUser } from '../decorators/auth-user.decorator'; | ||||
| @@ -11,7 +11,7 @@ import { UUIDParamDto } from './dto/uuid-param.dto'; | ||||
| @Authenticated() | ||||
| @UseValidation() | ||||
| export class SharedLinkController { | ||||
|   constructor(private readonly service: ShareService) {} | ||||
|   constructor(private readonly service: SharedLinkService) {} | ||||
|  | ||||
|   @Get() | ||||
|   getAllSharedLinks(@GetAuthUser() authUser: AuthUserDto): Promise<SharedLinkResponseDto[]> { | ||||
| @@ -29,20 +29,20 @@ export class SharedLinkController { | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
|     @Param() { id }: UUIDParamDto, | ||||
|   ): Promise<SharedLinkResponseDto> { | ||||
|     return this.service.getById(authUser, id, true); | ||||
|     return this.service.get(authUser, id); | ||||
|   } | ||||
|  | ||||
|   @Patch(':id') | ||||
|   updateSharedLink( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
|     @Param() { id }: UUIDParamDto, | ||||
|     @Body() dto: EditSharedLinkDto, | ||||
|   ): Promise<SharedLinkResponseDto> { | ||||
|     return this.service.update(authUser, id, dto); | ||||
|   } | ||||
|  | ||||
|   @Delete(':id') | ||||
|   removeSharedLink(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<void> { | ||||
|     return this.service.remove(authUser, id); | ||||
|   } | ||||
|  | ||||
|   @Patch(':id') | ||||
|   editSharedLink( | ||||
|     @GetAuthUser() authUser: AuthUserDto, | ||||
|     @Param() { id }: UUIDParamDto, | ||||
|     @Body() dto: EditSharedLinkDto, | ||||
|   ): Promise<SharedLinkResponseDto> { | ||||
|     return this.service.edit(authUser, id, dto); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1565,41 +1565,8 @@ | ||||
|           } | ||||
|         ] | ||||
|       }, | ||||
|       "delete": { | ||||
|         "operationId": "removeSharedLink", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "name": "id", | ||||
|             "required": true, | ||||
|             "in": "path", | ||||
|             "schema": { | ||||
|               "format": "uuid", | ||||
|               "type": "string" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "200": { | ||||
|             "description": "" | ||||
|           } | ||||
|         }, | ||||
|         "tags": [ | ||||
|           "share" | ||||
|         ], | ||||
|         "security": [ | ||||
|           { | ||||
|             "bearer": [] | ||||
|           }, | ||||
|           { | ||||
|             "cookie": [] | ||||
|           }, | ||||
|           { | ||||
|             "api_key": [] | ||||
|           } | ||||
|         ] | ||||
|       }, | ||||
|       "patch": { | ||||
|         "operationId": "editSharedLink", | ||||
|         "operationId": "updateSharedLink", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "name": "id", | ||||
| @@ -1647,6 +1614,39 @@ | ||||
|             "api_key": [] | ||||
|           } | ||||
|         ] | ||||
|       }, | ||||
|       "delete": { | ||||
|         "operationId": "removeSharedLink", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "name": "id", | ||||
|             "required": true, | ||||
|             "in": "path", | ||||
|             "schema": { | ||||
|               "format": "uuid", | ||||
|               "type": "string" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "200": { | ||||
|             "description": "" | ||||
|           } | ||||
|         }, | ||||
|         "tags": [ | ||||
|           "share" | ||||
|         ], | ||||
|         "security": [ | ||||
|           { | ||||
|             "bearer": [] | ||||
|           }, | ||||
|           { | ||||
|             "cookie": [] | ||||
|           }, | ||||
|           { | ||||
|             "api_key": [] | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|     }, | ||||
|     "/system-config": { | ||||
|   | ||||
| @@ -20,7 +20,7 @@ import { | ||||
| } from '../../test'; | ||||
| import { IKeyRepository } from '../api-key'; | ||||
| import { ICryptoRepository } from '../crypto/crypto.repository'; | ||||
| import { ISharedLinkRepository } from '../share'; | ||||
| import { ISharedLinkRepository } from '../shared-link'; | ||||
| import { ISystemConfigRepository } from '../system-config'; | ||||
| import { IUserRepository } from '../user'; | ||||
| import { IUserTokenRepository } from '../user-token'; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ import { AuthUserDto, ChangePasswordDto, LoginCredentialDto, SignUpDto } from '. | ||||
| import { AdminSignupResponseDto, LoginResponseDto, LogoutResponseDto, mapAdminSignupResponse } from './response-dto'; | ||||
| import { IUserTokenRepository, UserTokenCore } from '../user-token'; | ||||
| import cookieParser from 'cookie'; | ||||
| import { ISharedLinkRepository, ShareCore } from '../share'; | ||||
| import { ISharedLinkRepository, SharedLinkCore } from '../shared-link'; | ||||
| import { APIKeyCore } from '../api-key/api-key.core'; | ||||
| import { IKeyRepository } from '../api-key'; | ||||
| import { AuthDeviceResponseDto, mapUserToken } from './response-dto'; | ||||
| @@ -29,7 +29,7 @@ export class AuthService { | ||||
|   private authCore: AuthCore; | ||||
|   private oauthCore: OAuthCore; | ||||
|   private userCore: UserCore; | ||||
|   private shareCore: ShareCore; | ||||
|   private shareCore: SharedLinkCore; | ||||
|   private keyCore: APIKeyCore; | ||||
|  | ||||
|   private logger = new Logger(AuthService.name); | ||||
| @@ -48,7 +48,7 @@ export class AuthService { | ||||
|     this.authCore = new AuthCore(cryptoRepository, configRepository, userTokenRepository, initialConfig); | ||||
|     this.oauthCore = new OAuthCore(configRepository, initialConfig); | ||||
|     this.userCore = new UserCore(userRepository, cryptoRepository); | ||||
|     this.shareCore = new ShareCore(shareRepository, cryptoRepository); | ||||
|     this.shareCore = new SharedLinkCore(shareRepository, cryptoRepository); | ||||
|     this.keyCore = new APIKeyCore(cryptoRepository, keyRepository); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ import { PartnerService } from './partner'; | ||||
| import { PersonService } from './person'; | ||||
| import { SearchService } from './search'; | ||||
| import { ServerInfoService } from './server-info'; | ||||
| import { ShareService } from './share'; | ||||
| import { SharedLinkService } from './shared-link'; | ||||
| import { SmartInfoService } from './smart-info'; | ||||
| import { StorageService } from './storage'; | ||||
| import { StorageTemplateService } from './storage-template'; | ||||
| @@ -34,7 +34,7 @@ const providers: Provider[] = [ | ||||
|   PartnerService, | ||||
|   SearchService, | ||||
|   ServerInfoService, | ||||
|   ShareService, | ||||
|   SharedLinkService, | ||||
|   SmartInfoService, | ||||
|   StorageService, | ||||
|   StorageTemplateService, | ||||
|   | ||||
| @@ -17,7 +17,7 @@ export * from './person'; | ||||
| export * from './search'; | ||||
| export * from './server-info'; | ||||
| export * from './partner'; | ||||
| export * from './share'; | ||||
| export * from './shared-link'; | ||||
| export * from './smart-info'; | ||||
| export * from './storage'; | ||||
| export * from './storage-template'; | ||||
|   | ||||
| @@ -1,127 +0,0 @@ | ||||
| import { BadRequestException, ForbiddenException } from '@nestjs/common'; | ||||
| import { | ||||
|   authStub, | ||||
|   newCryptoRepositoryMock, | ||||
|   newSharedLinkRepositoryMock, | ||||
|   sharedLinkResponseStub, | ||||
|   sharedLinkStub, | ||||
| } from '../../test'; | ||||
| import { ICryptoRepository } from '../crypto'; | ||||
| import { ShareService } from './share.service'; | ||||
| import { ISharedLinkRepository } from './shared-link.repository'; | ||||
|  | ||||
| describe(ShareService.name, () => { | ||||
|   let sut: ShareService; | ||||
|   let cryptoMock: jest.Mocked<ICryptoRepository>; | ||||
|   let shareMock: jest.Mocked<ISharedLinkRepository>; | ||||
|  | ||||
|   beforeEach(async () => { | ||||
|     cryptoMock = newCryptoRepositoryMock(); | ||||
|     shareMock = newSharedLinkRepositoryMock(); | ||||
|  | ||||
|     sut = new ShareService(cryptoMock, shareMock); | ||||
|   }); | ||||
|  | ||||
|   it('should work', () => { | ||||
|     expect(sut).toBeDefined(); | ||||
|   }); | ||||
|  | ||||
|   describe('getAll', () => { | ||||
|     it('should return all keys for a user', async () => { | ||||
|       shareMock.getAll.mockResolvedValue([sharedLinkStub.expired, sharedLinkStub.valid]); | ||||
|       await expect(sut.getAll(authStub.user1)).resolves.toEqual([ | ||||
|         sharedLinkResponseStub.expired, | ||||
|         sharedLinkResponseStub.valid, | ||||
|       ]); | ||||
|       expect(shareMock.getAll).toHaveBeenCalledWith(authStub.user1.id); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('getMine', () => { | ||||
|     it('should only work for a public user', async () => { | ||||
|       await expect(sut.getMine(authStub.admin)).rejects.toBeInstanceOf(ForbiddenException); | ||||
|       expect(shareMock.get).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should return the key for the public user (auth dto)', async () => { | ||||
|       const authDto = authStub.adminSharedLink; | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       await expect(sut.getMine(authDto)).resolves.toEqual(sharedLinkResponseStub.valid); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('get', () => { | ||||
|     it('should not work on a missing key', async () => { | ||||
|       shareMock.get.mockResolvedValue(null); | ||||
|       await expect(sut.getById(authStub.user1, sharedLinkStub.valid.id, true)).rejects.toBeInstanceOf( | ||||
|         BadRequestException, | ||||
|       ); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.remove).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should get a key by id', async () => { | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       await expect(sut.getById(authStub.user1, sharedLinkStub.valid.id, false)).resolves.toEqual( | ||||
|         sharedLinkResponseStub.valid, | ||||
|       ); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|     }); | ||||
|  | ||||
|     it('should include exif', async () => { | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.readonly); | ||||
|       await expect(sut.getById(authStub.user1, sharedLinkStub.readonly.id, true)).resolves.toEqual( | ||||
|         sharedLinkResponseStub.readonly, | ||||
|       ); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.readonly.id); | ||||
|     }); | ||||
|  | ||||
|     it('should exclude exif', async () => { | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.readonly); | ||||
|       await expect(sut.getById(authStub.user1, sharedLinkStub.readonly.id, false)).resolves.toEqual( | ||||
|         sharedLinkResponseStub.readonlyNoExif, | ||||
|       ); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.readonly.id); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('remove', () => { | ||||
|     it('should not work on a missing key', async () => { | ||||
|       shareMock.get.mockResolvedValue(null); | ||||
|       await expect(sut.remove(authStub.user1, sharedLinkStub.valid.id)).rejects.toBeInstanceOf(BadRequestException); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.remove).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should remove a key', async () => { | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       await sut.remove(authStub.user1, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.remove).toHaveBeenCalledWith(sharedLinkStub.valid); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('edit', () => { | ||||
|     it('should not work on a missing key', async () => { | ||||
|       shareMock.get.mockResolvedValue(null); | ||||
|       await expect(sut.edit(authStub.user1, sharedLinkStub.valid.id, {})).rejects.toBeInstanceOf(BadRequestException); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.save).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should edit a key', async () => { | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       shareMock.save.mockResolvedValue(sharedLinkStub.valid); | ||||
|       const dto = { allowDownload: false }; | ||||
|       await sut.edit(authStub.user1, sharedLinkStub.valid.id, dto); | ||||
|       // await expect(sut.edit(authStub.user1, sharedLinkStub.valid.id, dto)).rejects.toBeInstanceOf(BadRequestException); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.save).toHaveBeenCalledWith({ | ||||
|         id: sharedLinkStub.valid.id, | ||||
|         userId: authStub.user1.id, | ||||
|         allowDownload: false, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| @@ -1,60 +0,0 @@ | ||||
| import { BadRequestException, ForbiddenException, Inject, Injectable, Logger } from '@nestjs/common'; | ||||
| import { AuthUserDto } from '../auth'; | ||||
| import { ICryptoRepository } from '../crypto'; | ||||
| import { EditSharedLinkDto } from './dto'; | ||||
| import { mapSharedLink, mapSharedLinkWithNoExif, SharedLinkResponseDto } from './response-dto'; | ||||
| import { ShareCore } from './share.core'; | ||||
| import { ISharedLinkRepository } from './shared-link.repository'; | ||||
|  | ||||
| @Injectable() | ||||
| export class ShareService { | ||||
|   readonly logger = new Logger(ShareService.name); | ||||
|   private shareCore: ShareCore; | ||||
|  | ||||
|   constructor( | ||||
|     @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository, | ||||
|     @Inject(ISharedLinkRepository) sharedLinkRepository: ISharedLinkRepository, | ||||
|   ) { | ||||
|     this.shareCore = new ShareCore(sharedLinkRepository, cryptoRepository); | ||||
|   } | ||||
|  | ||||
|   async getAll(authUser: AuthUserDto): Promise<SharedLinkResponseDto[]> { | ||||
|     const links = await this.shareCore.getAll(authUser.id); | ||||
|     return links.map(mapSharedLink); | ||||
|   } | ||||
|  | ||||
|   async getMine(authUser: AuthUserDto): Promise<SharedLinkResponseDto> { | ||||
|     if (!authUser.isPublicUser || !authUser.sharedLinkId) { | ||||
|       throw new ForbiddenException(); | ||||
|     } | ||||
|  | ||||
|     let allowExif = true; | ||||
|     if (authUser.isShowExif != undefined) { | ||||
|       allowExif = authUser.isShowExif; | ||||
|     } | ||||
|  | ||||
|     return this.getById(authUser, authUser.sharedLinkId, allowExif); | ||||
|   } | ||||
|  | ||||
|   async getById(authUser: AuthUserDto, id: string, allowExif: boolean): Promise<SharedLinkResponseDto> { | ||||
|     const link = await this.shareCore.get(authUser.id, id); | ||||
|     if (!link) { | ||||
|       throw new BadRequestException('Shared link not found'); | ||||
|     } | ||||
|  | ||||
|     if (allowExif) { | ||||
|       return mapSharedLink(link); | ||||
|     } else { | ||||
|       return mapSharedLinkWithNoExif(link); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async remove(authUser: AuthUserDto, id: string): Promise<void> { | ||||
|     await this.shareCore.remove(authUser.id, id); | ||||
|   } | ||||
|  | ||||
|   async edit(authUser: AuthUserDto, id: string, dto: EditSharedLinkDto) { | ||||
|     const link = await this.shareCore.save(authUser.id, id, dto); | ||||
|     return mapSharedLink(link); | ||||
|   } | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| export * from './dto'; | ||||
| export * from './response-dto'; | ||||
| export * from './share.core'; | ||||
| export * from './share.service'; | ||||
| export * from './shared-link.core'; | ||||
| export * from './shared-link.service'; | ||||
| export * from './shared-link.repository'; | ||||
| @@ -5,19 +5,12 @@ import { ICryptoRepository } from '../crypto'; | ||||
| import { CreateSharedLinkDto } from './dto'; | ||||
| import { ISharedLinkRepository } from './shared-link.repository'; | ||||
| 
 | ||||
| export class ShareCore { | ||||
|   readonly logger = new Logger(ShareCore.name); | ||||
| export class SharedLinkCore { | ||||
|   readonly logger = new Logger(SharedLinkCore.name); | ||||
| 
 | ||||
|   constructor(private repository: ISharedLinkRepository, private cryptoRepository: ICryptoRepository) {} | ||||
| 
 | ||||
|   getAll(userId: string): Promise<SharedLinkEntity[]> { | ||||
|     return this.repository.getAll(userId); | ||||
|   } | ||||
| 
 | ||||
|   get(userId: string, id: string): Promise<SharedLinkEntity | null> { | ||||
|     return this.repository.get(userId, id); | ||||
|   } | ||||
| 
 | ||||
|   // TODO: move to SharedLinkController/SharedLinkService
 | ||||
|   create(userId: string, dto: CreateSharedLinkDto): Promise<SharedLinkEntity> { | ||||
|     return this.repository.create({ | ||||
|       key: Buffer.from(this.cryptoRepository.randomBytes(50)), | ||||
| @@ -34,42 +27,24 @@ export class ShareCore { | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   async save(userId: string, id: string, entity: Partial<SharedLinkEntity>): Promise<SharedLinkEntity> { | ||||
|     const link = await this.get(userId, id); | ||||
|     if (!link) { | ||||
|       throw new BadRequestException('Shared link not found'); | ||||
|     } | ||||
| 
 | ||||
|     return this.repository.save({ ...entity, userId, id }); | ||||
|   } | ||||
| 
 | ||||
|   async remove(userId: string, id: string): Promise<void> { | ||||
|     const link = await this.get(userId, id); | ||||
|     if (!link) { | ||||
|       throw new BadRequestException('Shared link not found'); | ||||
|     } | ||||
| 
 | ||||
|     await this.repository.remove(link); | ||||
|   } | ||||
| 
 | ||||
|   async addAssets(userId: string, id: string, assets: AssetEntity[]) { | ||||
|     const link = await this.get(userId, id); | ||||
|     const link = await this.repository.get(userId, id); | ||||
|     if (!link) { | ||||
|       throw new BadRequestException('Shared link not found'); | ||||
|     } | ||||
| 
 | ||||
|     return this.repository.save({ ...link, assets: [...link.assets, ...assets] }); | ||||
|     return this.repository.update({ ...link, assets: [...link.assets, ...assets] }); | ||||
|   } | ||||
| 
 | ||||
|   async removeAssets(userId: string, id: string, assets: AssetEntity[]) { | ||||
|     const link = await this.get(userId, id); | ||||
|     const link = await this.repository.get(userId, id); | ||||
|     if (!link) { | ||||
|       throw new BadRequestException('Shared link not found'); | ||||
|     } | ||||
| 
 | ||||
|     const newAssets = link.assets.filter((asset) => assets.find((a) => a.id === asset.id)); | ||||
| 
 | ||||
|     return this.repository.save({ ...link, assets: newAssets }); | ||||
|     return this.repository.update({ ...link, assets: newAssets }); | ||||
|   } | ||||
| 
 | ||||
|   async hasAssetAccess(id: string, assetId: string): Promise<boolean> { | ||||
| @@ -7,7 +7,7 @@ export interface ISharedLinkRepository { | ||||
|   get(userId: string, id: string): Promise<SharedLinkEntity | null>; | ||||
|   getByKey(key: Buffer): Promise<SharedLinkEntity | null>; | ||||
|   create(entity: Omit<SharedLinkEntity, 'id' | 'user'>): Promise<SharedLinkEntity>; | ||||
|   update(entity: Partial<SharedLinkEntity>): Promise<SharedLinkEntity>; | ||||
|   remove(entity: SharedLinkEntity): Promise<void>; | ||||
|   save(entity: Partial<SharedLinkEntity>): Promise<SharedLinkEntity>; | ||||
|   hasAssetAccess(id: string, assetId: string): Promise<boolean>; | ||||
| } | ||||
							
								
								
									
										103
									
								
								server/libs/domain/src/shared-link/shared-link.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								server/libs/domain/src/shared-link/shared-link.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| import { BadRequestException, ForbiddenException } from '@nestjs/common'; | ||||
| import { authStub, newSharedLinkRepositoryMock, sharedLinkResponseStub, sharedLinkStub } from '../../test'; | ||||
| import { SharedLinkService } from './shared-link.service'; | ||||
| import { ISharedLinkRepository } from './shared-link.repository'; | ||||
|  | ||||
| describe(SharedLinkService.name, () => { | ||||
|   let sut: SharedLinkService; | ||||
|   let shareMock: jest.Mocked<ISharedLinkRepository>; | ||||
|  | ||||
|   beforeEach(async () => { | ||||
|     shareMock = newSharedLinkRepositoryMock(); | ||||
|  | ||||
|     sut = new SharedLinkService(shareMock); | ||||
|   }); | ||||
|  | ||||
|   it('should work', () => { | ||||
|     expect(sut).toBeDefined(); | ||||
|   }); | ||||
|  | ||||
|   describe('getAll', () => { | ||||
|     it('should return all shared links for a user', async () => { | ||||
|       shareMock.getAll.mockResolvedValue([sharedLinkStub.expired, sharedLinkStub.valid]); | ||||
|       await expect(sut.getAll(authStub.user1)).resolves.toEqual([ | ||||
|         sharedLinkResponseStub.expired, | ||||
|         sharedLinkResponseStub.valid, | ||||
|       ]); | ||||
|       expect(shareMock.getAll).toHaveBeenCalledWith(authStub.user1.id); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('getMine', () => { | ||||
|     it('should only work for a public user', async () => { | ||||
|       await expect(sut.getMine(authStub.admin)).rejects.toBeInstanceOf(ForbiddenException); | ||||
|       expect(shareMock.get).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should return the shared link for the public user', async () => { | ||||
|       const authDto = authStub.adminSharedLink; | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       await expect(sut.getMine(authDto)).resolves.toEqual(sharedLinkResponseStub.valid); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId); | ||||
|     }); | ||||
|  | ||||
|     it('should return not return exif', async () => { | ||||
|       const authDto = authStub.adminSharedLinkNoExif; | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.readonlyNoExif); | ||||
|       await expect(sut.getMine(authDto)).resolves.toEqual(sharedLinkResponseStub.readonlyNoExif); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('get', () => { | ||||
|     it('should throw an error for an invalid shared link', async () => { | ||||
|       shareMock.get.mockResolvedValue(null); | ||||
|       await expect(sut.get(authStub.user1, 'missing-id')).rejects.toBeInstanceOf(BadRequestException); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, 'missing-id'); | ||||
|       expect(shareMock.update).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should get a shared link by id', async () => { | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       await expect(sut.get(authStub.user1, sharedLinkStub.valid.id)).resolves.toEqual(sharedLinkResponseStub.valid); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('update', () => { | ||||
|     it('should throw an error for an invalid shared link', async () => { | ||||
|       shareMock.get.mockResolvedValue(null); | ||||
|       await expect(sut.update(authStub.user1, 'missing-id', {})).rejects.toBeInstanceOf(BadRequestException); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, 'missing-id'); | ||||
|       expect(shareMock.update).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should update a shared link', async () => { | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       shareMock.update.mockResolvedValue(sharedLinkStub.valid); | ||||
|       await sut.update(authStub.user1, sharedLinkStub.valid.id, { allowDownload: false }); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.update).toHaveBeenCalledWith({ | ||||
|         id: sharedLinkStub.valid.id, | ||||
|         userId: authStub.user1.id, | ||||
|         allowDownload: false, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('remove', () => { | ||||
|     it('should throw an error for an invalid shared link', async () => { | ||||
|       shareMock.get.mockResolvedValue(null); | ||||
|       await expect(sut.remove(authStub.user1, 'missing-id')).rejects.toBeInstanceOf(BadRequestException); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, 'missing-id'); | ||||
|       expect(shareMock.update).not.toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it('should remove a key', async () => { | ||||
|       shareMock.get.mockResolvedValue(sharedLinkStub.valid); | ||||
|       await sut.remove(authStub.user1, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id); | ||||
|       expect(shareMock.remove).toHaveBeenCalledWith(sharedLinkStub.valid); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										63
									
								
								server/libs/domain/src/shared-link/shared-link.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								server/libs/domain/src/shared-link/shared-link.service.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| import { SharedLinkEntity } from '@app/infra/entities'; | ||||
| import { BadRequestException, ForbiddenException, Inject, Injectable } from '@nestjs/common'; | ||||
| import { AuthUserDto } from '../auth'; | ||||
| import { EditSharedLinkDto } from './dto'; | ||||
| import { mapSharedLink, mapSharedLinkWithNoExif, SharedLinkResponseDto } from './response-dto'; | ||||
| import { ISharedLinkRepository } from './shared-link.repository'; | ||||
|  | ||||
| @Injectable() | ||||
| export class SharedLinkService { | ||||
|   constructor(@Inject(ISharedLinkRepository) private repository: ISharedLinkRepository) {} | ||||
|  | ||||
|   async getAll(authUser: AuthUserDto): Promise<SharedLinkResponseDto[]> { | ||||
|     return this.repository.getAll(authUser.id).then((links) => links.map(mapSharedLink)); | ||||
|   } | ||||
|  | ||||
|   async getMine(authUser: AuthUserDto): Promise<SharedLinkResponseDto> { | ||||
|     const { sharedLinkId: id, isPublicUser, isShowExif } = authUser; | ||||
|  | ||||
|     if (!isPublicUser || !id) { | ||||
|       throw new ForbiddenException(); | ||||
|     } | ||||
|  | ||||
|     const sharedLink = await this.findOrFail(authUser, id); | ||||
|  | ||||
|     return this.map(sharedLink, { withExif: isShowExif ?? true }); | ||||
|   } | ||||
|  | ||||
|   async get(authUser: AuthUserDto, id: string): Promise<SharedLinkResponseDto> { | ||||
|     const sharedLink = await this.findOrFail(authUser, id); | ||||
|     return this.map(sharedLink, { withExif: true }); | ||||
|   } | ||||
|  | ||||
|   async update(authUser: AuthUserDto, id: string, dto: EditSharedLinkDto) { | ||||
|     await this.findOrFail(authUser, id); | ||||
|     const sharedLink = await this.repository.update({ | ||||
|       id, | ||||
|       userId: authUser.id, | ||||
|       description: dto.description, | ||||
|       expiresAt: dto.expiresAt, | ||||
|       allowUpload: dto.allowUpload, | ||||
|       allowDownload: dto.allowDownload, | ||||
|       showExif: dto.showExif, | ||||
|     }); | ||||
|     return this.map(sharedLink, { withExif: true }); | ||||
|   } | ||||
|  | ||||
|   async remove(authUser: AuthUserDto, id: string): Promise<void> { | ||||
|     const sharedLink = await this.findOrFail(authUser, id); | ||||
|     await this.repository.remove(sharedLink); | ||||
|   } | ||||
|  | ||||
|   private async findOrFail(authUser: AuthUserDto, id: string) { | ||||
|     const sharedLink = await this.repository.get(authUser.id, id); | ||||
|     if (!sharedLink) { | ||||
|       throw new BadRequestException('Shared link not found'); | ||||
|     } | ||||
|     return sharedLink; | ||||
|   } | ||||
|  | ||||
|   private map(sharedLink: SharedLinkEntity, { withExif }: { withExif: boolean }) { | ||||
|     return withExif ? mapSharedLink(sharedLink) : mapSharedLinkWithNoExif(sharedLink); | ||||
|   } | ||||
| } | ||||
| @@ -71,6 +71,16 @@ export const authStub = { | ||||
|     isShowExif: true, | ||||
|     sharedLinkId: '123', | ||||
|   }), | ||||
|   adminSharedLinkNoExif: Object.freeze<AuthUserDto>({ | ||||
|     id: 'admin_id', | ||||
|     email: 'admin@test.com', | ||||
|     isAdmin: true, | ||||
|     isAllowUpload: true, | ||||
|     isAllowDownload: true, | ||||
|     isPublicUser: true, | ||||
|     isShowExif: false, | ||||
|     sharedLinkId: '123', | ||||
|   }), | ||||
|   readonlySharedLink: Object.freeze<AuthUserDto>({ | ||||
|     id: 'admin_id', | ||||
|     email: 'admin@test.com', | ||||
| @@ -690,7 +700,7 @@ export const sharedLinkStub = { | ||||
|     showExif: true, | ||||
|     assets: [], | ||||
|   } as SharedLinkEntity), | ||||
|   readonly: Object.freeze<SharedLinkEntity>({ | ||||
|   readonlyNoExif: Object.freeze<SharedLinkEntity>({ | ||||
|     id: '123', | ||||
|     userId: authStub.admin.id, | ||||
|     user: userEntityStub.admin, | ||||
| @@ -700,7 +710,7 @@ export const sharedLinkStub = { | ||||
|     expiresAt: tomorrow, | ||||
|     allowUpload: false, | ||||
|     allowDownload: false, | ||||
|     showExif: true, | ||||
|     showExif: false, | ||||
|     assets: [], | ||||
|     album: { | ||||
|       id: 'album-123', | ||||
| @@ -834,7 +844,7 @@ export const sharedLinkResponseStub = { | ||||
|     description: undefined, | ||||
|     allowUpload: false, | ||||
|     allowDownload: false, | ||||
|     showExif: true, | ||||
|     showExif: false, | ||||
|     album: albumResponse, | ||||
|     assets: [{ ...assetResponse, exifInfo: undefined }], | ||||
|   }), | ||||
|   | ||||
| @@ -7,7 +7,7 @@ export const newSharedLinkRepositoryMock = (): jest.Mocked<ISharedLinkRepository | ||||
|     getByKey: jest.fn(), | ||||
|     create: jest.fn(), | ||||
|     remove: jest.fn(), | ||||
|     save: jest.fn(), | ||||
|     update: jest.fn(), | ||||
|     hasAssetAccess: jest.fn(), | ||||
|   }; | ||||
| }; | ||||
|   | ||||
| @@ -1,16 +1,12 @@ | ||||
| import { ISharedLinkRepository } from '@app/domain'; | ||||
| import { Injectable, Logger } from '@nestjs/common'; | ||||
| import { Injectable } from '@nestjs/common'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
| import { Repository } from 'typeorm'; | ||||
| import { SharedLinkEntity } from '../entities'; | ||||
|  | ||||
| @Injectable() | ||||
| export class SharedLinkRepository implements ISharedLinkRepository { | ||||
|   readonly logger = new Logger(SharedLinkRepository.name); | ||||
|   constructor( | ||||
|     @InjectRepository(SharedLinkEntity) | ||||
|     private readonly repository: Repository<SharedLinkEntity>, | ||||
|   ) {} | ||||
|   constructor(@InjectRepository(SharedLinkEntity) private repository: Repository<SharedLinkEntity>) {} | ||||
|  | ||||
|   get(userId: string, id: string): Promise<SharedLinkEntity | null> { | ||||
|     return this.repository.findOne({ | ||||
| @@ -78,40 +74,45 @@ export class SharedLinkRepository implements ISharedLinkRepository { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   create(entity: Omit<SharedLinkEntity, 'id'>): Promise<SharedLinkEntity> { | ||||
|     return this.repository.save(entity); | ||||
|   create(entity: Partial<SharedLinkEntity>): Promise<SharedLinkEntity> { | ||||
|     return this.save(entity); | ||||
|   } | ||||
|  | ||||
|   update(entity: Partial<SharedLinkEntity>): Promise<SharedLinkEntity> { | ||||
|     return this.save(entity); | ||||
|   } | ||||
|  | ||||
|   async remove(entity: SharedLinkEntity): Promise<void> { | ||||
|     await this.repository.remove(entity); | ||||
|   } | ||||
|  | ||||
|   async save(entity: SharedLinkEntity): Promise<SharedLinkEntity> { | ||||
|     await this.repository.save(entity); | ||||
|     return this.repository.findOneOrFail({ where: { id: entity.id } }); | ||||
|   } | ||||
|  | ||||
|   async hasAssetAccess(id: string, assetId: string): Promise<boolean> { | ||||
|     const count1 = await this.repository.count({ | ||||
|       where: { | ||||
|         id, | ||||
|         assets: { | ||||
|           id: assetId, | ||||
|     return ( | ||||
|       // album asset | ||||
|       (await this.repository.exist({ | ||||
|         where: { | ||||
|           id, | ||||
|           album: { | ||||
|             assets: { | ||||
|               id: assetId, | ||||
|             }, | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
|  | ||||
|     const count2 = await this.repository.count({ | ||||
|       where: { | ||||
|         id, | ||||
|         album: { | ||||
|       })) || | ||||
|       // individual asset | ||||
|       (await this.repository.exist({ | ||||
|         where: { | ||||
|           id, | ||||
|           assets: { | ||||
|             id: assetId, | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
|       })) | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|     return Boolean(count1 + count2); | ||||
|   private async save(entity: Partial<SharedLinkEntity>): Promise<SharedLinkEntity> { | ||||
|     await this.repository.save(entity); | ||||
|     return this.repository.findOneOrFail({ where: { id: entity.id } }); | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										202
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										202
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							| @@ -9984,54 +9984,6 @@ export class ServerInfoApi extends BaseAPI { | ||||
|  */ | ||||
| export const ShareApiAxiosParamCreator = function (configuration?: Configuration) { | ||||
|     return { | ||||
|         /** | ||||
|          *  | ||||
|          * @param {string} id  | ||||
|          * @param {EditSharedLinkDto} editSharedLinkDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         editSharedLink: async (id: string, editSharedLinkDto: EditSharedLinkDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => { | ||||
|             // verify required parameter 'id' is not null or undefined
 | ||||
|             assertParamExists('editSharedLink', 'id', id) | ||||
|             // verify required parameter 'editSharedLinkDto' is not null or undefined
 | ||||
|             assertParamExists('editSharedLink', 'editSharedLinkDto', editSharedLinkDto) | ||||
|             const localVarPath = `/share/{id}` | ||||
|                 .replace(`{${"id"}}`, encodeURIComponent(String(id))); | ||||
|             // 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: 'PATCH', ...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(editSharedLinkDto, localVarRequestOptions, configuration) | ||||
| 
 | ||||
|             return { | ||||
|                 url: toPathString(localVarUrlObj), | ||||
|                 options: localVarRequestOptions, | ||||
|             }; | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {*} [options] Override http request option. | ||||
| @@ -10192,6 +10144,54 @@ export const ShareApiAxiosParamCreator = function (configuration?: Configuration | ||||
|             let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; | ||||
|             localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; | ||||
| 
 | ||||
|             return { | ||||
|                 url: toPathString(localVarUrlObj), | ||||
|                 options: localVarRequestOptions, | ||||
|             }; | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {string} id  | ||||
|          * @param {EditSharedLinkDto} editSharedLinkDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         updateSharedLink: async (id: string, editSharedLinkDto: EditSharedLinkDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => { | ||||
|             // verify required parameter 'id' is not null or undefined
 | ||||
|             assertParamExists('updateSharedLink', 'id', id) | ||||
|             // verify required parameter 'editSharedLinkDto' is not null or undefined
 | ||||
|             assertParamExists('updateSharedLink', 'editSharedLinkDto', editSharedLinkDto) | ||||
|             const localVarPath = `/share/{id}` | ||||
|                 .replace(`{${"id"}}`, encodeURIComponent(String(id))); | ||||
|             // 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: 'PATCH', ...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(editSharedLinkDto, localVarRequestOptions, configuration) | ||||
| 
 | ||||
|             return { | ||||
|                 url: toPathString(localVarUrlObj), | ||||
|                 options: localVarRequestOptions, | ||||
| @@ -10207,17 +10207,6 @@ export const ShareApiAxiosParamCreator = function (configuration?: Configuration | ||||
| export const ShareApiFp = function(configuration?: Configuration) { | ||||
|     const localVarAxiosParamCreator = ShareApiAxiosParamCreator(configuration) | ||||
|     return { | ||||
|         /** | ||||
|          *  | ||||
|          * @param {string} id  | ||||
|          * @param {EditSharedLinkDto} editSharedLinkDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         async editSharedLink(id: string, editSharedLinkDto: EditSharedLinkDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<SharedLinkResponseDto>> { | ||||
|             const localVarAxiosArgs = await localVarAxiosParamCreator.editSharedLink(id, editSharedLinkDto, options); | ||||
|             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {*} [options] Override http request option. | ||||
| @@ -10257,6 +10246,17 @@ export const ShareApiFp = function(configuration?: Configuration) { | ||||
|             const localVarAxiosArgs = await localVarAxiosParamCreator.removeSharedLink(id, options); | ||||
|             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {string} id  | ||||
|          * @param {EditSharedLinkDto} editSharedLinkDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         async updateSharedLink(id: string, editSharedLinkDto: EditSharedLinkDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<SharedLinkResponseDto>> { | ||||
|             const localVarAxiosArgs = await localVarAxiosParamCreator.updateSharedLink(id, editSharedLinkDto, options); | ||||
|             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); | ||||
|         }, | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| @@ -10267,16 +10267,6 @@ export const ShareApiFp = function(configuration?: Configuration) { | ||||
| export const ShareApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { | ||||
|     const localVarFp = ShareApiFp(configuration) | ||||
|     return { | ||||
|         /** | ||||
|          *  | ||||
|          * @param {string} id  | ||||
|          * @param {EditSharedLinkDto} editSharedLinkDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         editSharedLink(id: string, editSharedLinkDto: EditSharedLinkDto, options?: any): AxiosPromise<SharedLinkResponseDto> { | ||||
|             return localVarFp.editSharedLink(id, editSharedLinkDto, options).then((request) => request(axios, basePath)); | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {*} [options] Override http request option. | ||||
| @@ -10312,30 +10302,19 @@ export const ShareApiFactory = function (configuration?: Configuration, basePath | ||||
|         removeSharedLink(id: string, options?: any): AxiosPromise<void> { | ||||
|             return localVarFp.removeSharedLink(id, options).then((request) => request(axios, basePath)); | ||||
|         }, | ||||
|         /** | ||||
|          *  | ||||
|          * @param {string} id  | ||||
|          * @param {EditSharedLinkDto} editSharedLinkDto  | ||||
|          * @param {*} [options] Override http request option. | ||||
|          * @throws {RequiredError} | ||||
|          */ | ||||
|         updateSharedLink(id: string, editSharedLinkDto: EditSharedLinkDto, options?: any): AxiosPromise<SharedLinkResponseDto> { | ||||
|             return localVarFp.updateSharedLink(id, editSharedLinkDto, options).then((request) => request(axios, basePath)); | ||||
|         }, | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Request parameters for editSharedLink operation in ShareApi. | ||||
|  * @export | ||||
|  * @interface ShareApiEditSharedLinkRequest | ||||
|  */ | ||||
| export interface ShareApiEditSharedLinkRequest { | ||||
|     /** | ||||
|      *  | ||||
|      * @type {string} | ||||
|      * @memberof ShareApiEditSharedLink | ||||
|      */ | ||||
|     readonly id: string | ||||
| 
 | ||||
|     /** | ||||
|      *  | ||||
|      * @type {EditSharedLinkDto} | ||||
|      * @memberof ShareApiEditSharedLink | ||||
|      */ | ||||
|     readonly editSharedLinkDto: EditSharedLinkDto | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Request parameters for getMySharedLink operation in ShareApi. | ||||
|  * @export | ||||
| @@ -10378,6 +10357,27 @@ export interface ShareApiRemoveSharedLinkRequest { | ||||
|     readonly id: string | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Request parameters for updateSharedLink operation in ShareApi. | ||||
|  * @export | ||||
|  * @interface ShareApiUpdateSharedLinkRequest | ||||
|  */ | ||||
| export interface ShareApiUpdateSharedLinkRequest { | ||||
|     /** | ||||
|      *  | ||||
|      * @type {string} | ||||
|      * @memberof ShareApiUpdateSharedLink | ||||
|      */ | ||||
|     readonly id: string | ||||
| 
 | ||||
|     /** | ||||
|      *  | ||||
|      * @type {EditSharedLinkDto} | ||||
|      * @memberof ShareApiUpdateSharedLink | ||||
|      */ | ||||
|     readonly editSharedLinkDto: EditSharedLinkDto | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * ShareApi - object-oriented interface | ||||
|  * @export | ||||
| @@ -10385,17 +10385,6 @@ export interface ShareApiRemoveSharedLinkRequest { | ||||
|  * @extends {BaseAPI} | ||||
|  */ | ||||
| export class ShareApi extends BaseAPI { | ||||
|     /** | ||||
|      *  | ||||
|      * @param {ShareApiEditSharedLinkRequest} requestParameters Request parameters. | ||||
|      * @param {*} [options] Override http request option. | ||||
|      * @throws {RequiredError} | ||||
|      * @memberof ShareApi | ||||
|      */ | ||||
|     public editSharedLink(requestParameters: ShareApiEditSharedLinkRequest, options?: AxiosRequestConfig) { | ||||
|         return ShareApiFp(this.configuration).editSharedLink(requestParameters.id, requestParameters.editSharedLinkDto, options).then((request) => request(this.axios, this.basePath)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      *  | ||||
|      * @param {*} [options] Override http request option. | ||||
| @@ -10438,6 +10427,17 @@ export class ShareApi extends BaseAPI { | ||||
|     public removeSharedLink(requestParameters: ShareApiRemoveSharedLinkRequest, options?: AxiosRequestConfig) { | ||||
|         return ShareApiFp(this.configuration).removeSharedLink(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      *  | ||||
|      * @param {ShareApiUpdateSharedLinkRequest} requestParameters Request parameters. | ||||
|      * @param {*} [options] Override http request option. | ||||
|      * @throws {RequiredError} | ||||
|      * @memberof ShareApi | ||||
|      */ | ||||
|     public updateSharedLink(requestParameters: ShareApiUpdateSharedLinkRequest, options?: AxiosRequestConfig) { | ||||
|         return ShareApiFp(this.configuration).updateSharedLink(requestParameters.id, requestParameters.editSharedLinkDto, options).then((request) => request(this.axios, this.basePath)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|   | ||||
| @@ -137,7 +137,7 @@ | ||||
| 					? new Date(currentTime + expirationTime).toISOString() | ||||
| 					: null; | ||||
|  | ||||
| 				await api.shareApi.editSharedLink({ | ||||
| 				await api.shareApi.updateSharedLink({ | ||||
| 					id: editingLink.id, | ||||
| 					editSharedLinkDto: { | ||||
| 						description, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user