feat(server) Tagging system (#1046)

This commit is contained in:
Alex 2022-12-05 11:56:44 -06:00 committed by GitHub
parent 6e2763b72c
commit 5de8ea162d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 8768 additions and 167 deletions

13
.gitattributes vendored Normal file
View File

@ -0,0 +1,13 @@
mobile/openapi/**/*.md -diff -merge
mobile/openapi/**/*.md linguist-generated=true
mobile/openapi/**/*.dart -diff -merge
mobile/openapi/**/*.dart linguist-generated=true
web/src/api/open-api/**/*.md -diff -merge
web/src/api/open-api/**/*.md linguist-generated=true
web/src/api/open-api/**/*.ts -diff -merge
web/src/api/open-api/**/*.ts linguist-generated=true
mobile/openapi/.openapi-generator/FILES -diff -merge
mobile/openapi/.openapi-generator/FILES linguist-generated=true

View File

@ -27,3 +27,6 @@ prod-scale:
api:
cd ./server && npm run api:generate
attach-server:
docker exec -it docker_immich-server_1 sh

View File

@ -1,9 +0,0 @@
# TODO
Server scenario with web
[ ] 1 user exist without admin right -> make admin on first check
[ ] 2 users exist without admin right -> ask user to choose which account will be the admin
[ X ] No users exist -> prompt signup form for Admin

View File

@ -14,6 +14,7 @@ doc/AssetApi.md
doc/AssetCountByTimeBucket.md
doc/AssetCountByTimeBucketResponseDto.md
doc/AssetCountByUserIdResponseDto.md
doc/AssetEntity.md
doc/AssetFileUploadResponseDto.md
doc/AssetResponseDto.md
doc/AssetTypeEnum.md
@ -25,6 +26,7 @@ doc/CheckExistingAssetsResponseDto.md
doc/CreateAlbumDto.md
doc/CreateDeviceInfoDto.md
doc/CreateProfileImageResponseDto.md
doc/CreateTagDto.md
doc/CreateUserDto.md
doc/CuratedLocationsResponseDto.md
doc/CuratedObjectsResponseDto.md
@ -34,6 +36,7 @@ doc/DeleteAssetStatus.md
doc/DeviceInfoApi.md
doc/DeviceInfoResponseDto.md
doc/DeviceTypeEnum.md
doc/ExifEntity.md
doc/ExifResponseDto.md
doc/GetAssetByTimeBucketDto.md
doc/GetAssetCountByTimeBucketDto.md
@ -58,20 +61,27 @@ doc/ServerPingResponse.md
doc/ServerStatsResponseDto.md
doc/ServerVersionReponseDto.md
doc/SignUpDto.md
doc/SmartInfoEntity.md
doc/SmartInfoResponseDto.md
doc/SystemConfigApi.md
doc/SystemConfigKey.md
doc/SystemConfigResponseDto.md
doc/SystemConfigResponseItem.md
doc/TagApi.md
doc/TagEntity.md
doc/TagResponseDto.md
doc/TagTypeEnum.md
doc/ThumbnailFormat.md
doc/TimeGroupEnum.md
doc/UpdateAlbumDto.md
doc/UpdateAssetDto.md
doc/UpdateDeviceInfoDto.md
doc/UpdateTagDto.md
doc/UpdateUserDto.md
doc/UsageByUserDto.md
doc/UserApi.md
doc/UserCountResponseDto.md
doc/UserEntity.md
doc/UserResponseDto.md
doc/ValidateAccessTokenResponseDto.md
git_push.sh
@ -84,6 +94,7 @@ lib/api/job_api.dart
lib/api/o_auth_api.dart
lib/api/server_info_api.dart
lib/api/system_config_api.dart
lib/api/tag_api.dart
lib/api/user_api.dart
lib/api_client.dart
lib/api_exception.dart
@ -103,6 +114,7 @@ lib/model/all_job_status_response_dto.dart
lib/model/asset_count_by_time_bucket.dart
lib/model/asset_count_by_time_bucket_response_dto.dart
lib/model/asset_count_by_user_id_response_dto.dart
lib/model/asset_entity.dart
lib/model/asset_file_upload_response_dto.dart
lib/model/asset_response_dto.dart
lib/model/asset_type_enum.dart
@ -113,6 +125,7 @@ lib/model/check_existing_assets_response_dto.dart
lib/model/create_album_dto.dart
lib/model/create_device_info_dto.dart
lib/model/create_profile_image_response_dto.dart
lib/model/create_tag_dto.dart
lib/model/create_user_dto.dart
lib/model/curated_locations_response_dto.dart
lib/model/curated_objects_response_dto.dart
@ -121,6 +134,7 @@ lib/model/delete_asset_response_dto.dart
lib/model/delete_asset_status.dart
lib/model/device_info_response_dto.dart
lib/model/device_type_enum.dart
lib/model/exif_entity.dart
lib/model/exif_response_dto.dart
lib/model/get_asset_by_time_bucket_dto.dart
lib/model/get_asset_count_by_time_bucket_dto.dart
@ -142,18 +156,24 @@ lib/model/server_ping_response.dart
lib/model/server_stats_response_dto.dart
lib/model/server_version_reponse_dto.dart
lib/model/sign_up_dto.dart
lib/model/smart_info_entity.dart
lib/model/smart_info_response_dto.dart
lib/model/system_config_key.dart
lib/model/system_config_response_dto.dart
lib/model/system_config_response_item.dart
lib/model/tag_entity.dart
lib/model/tag_response_dto.dart
lib/model/tag_type_enum.dart
lib/model/thumbnail_format.dart
lib/model/time_group_enum.dart
lib/model/update_album_dto.dart
lib/model/update_asset_dto.dart
lib/model/update_device_info_dto.dart
lib/model/update_tag_dto.dart
lib/model/update_user_dto.dart
lib/model/usage_by_user_dto.dart
lib/model/user_count_response_dto.dart
lib/model/user_entity.dart
lib/model/user_response_dto.dart
lib/model/validate_access_token_response_dto.dart
pubspec.yaml

View File

@ -93,7 +93,7 @@ Class | Method | HTTP request | Description
*AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |
*AssetApi* | [**searchAsset**](doc//AssetApi.md#searchasset) | **POST** /asset/search |
*AssetApi* | [**serveFile**](doc//AssetApi.md#servefile) | **GET** /asset/file/{assetId} |
*AssetApi* | [**updateAssetById**](doc//AssetApi.md#updateassetbyid) | **PUT** /asset/assetById/{assetId} |
*AssetApi* | [**updateAsset**](doc//AssetApi.md#updateasset) | **PUT** /asset/{assetId} |
*AssetApi* | [**uploadFile**](doc//AssetApi.md#uploadfile) | **POST** /asset/upload |
*AuthenticationApi* | [**adminSignUp**](doc//AuthenticationApi.md#adminsignup) | **POST** /auth/admin-sign-up |
*AuthenticationApi* | [**login**](doc//AuthenticationApi.md#login) | **POST** /auth/login |
@ -112,6 +112,11 @@ Class | Method | HTTP request | Description
*ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping |
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config |
*SystemConfigApi* | [**updateConfig**](doc//SystemConfigApi.md#updateconfig) | **PUT** /system-config |
*TagApi* | [**create**](doc//TagApi.md#create) | **POST** /tag |
*TagApi* | [**delete**](doc//TagApi.md#delete) | **DELETE** /tag/{id} |
*TagApi* | [**findAll**](doc//TagApi.md#findall) | **GET** /tag |
*TagApi* | [**findOne**](doc//TagApi.md#findone) | **GET** /tag/{id} |
*TagApi* | [**update**](doc//TagApi.md#update) | **PATCH** /tag/{id} |
*UserApi* | [**createProfileImage**](doc//UserApi.md#createprofileimage) | **POST** /user/profile-image |
*UserApi* | [**createUser**](doc//UserApi.md#createuser) | **POST** /user |
*UserApi* | [**deleteUser**](doc//UserApi.md#deleteuser) | **DELETE** /user/{userId} |
@ -136,6 +141,7 @@ Class | Method | HTTP request | Description
- [AssetCountByTimeBucket](doc//AssetCountByTimeBucket.md)
- [AssetCountByTimeBucketResponseDto](doc//AssetCountByTimeBucketResponseDto.md)
- [AssetCountByUserIdResponseDto](doc//AssetCountByUserIdResponseDto.md)
- [AssetEntity](doc//AssetEntity.md)
- [AssetFileUploadResponseDto](doc//AssetFileUploadResponseDto.md)
- [AssetResponseDto](doc//AssetResponseDto.md)
- [AssetTypeEnum](doc//AssetTypeEnum.md)
@ -146,6 +152,7 @@ Class | Method | HTTP request | Description
- [CreateAlbumDto](doc//CreateAlbumDto.md)
- [CreateDeviceInfoDto](doc//CreateDeviceInfoDto.md)
- [CreateProfileImageResponseDto](doc//CreateProfileImageResponseDto.md)
- [CreateTagDto](doc//CreateTagDto.md)
- [CreateUserDto](doc//CreateUserDto.md)
- [CuratedLocationsResponseDto](doc//CuratedLocationsResponseDto.md)
- [CuratedObjectsResponseDto](doc//CuratedObjectsResponseDto.md)
@ -154,6 +161,7 @@ Class | Method | HTTP request | Description
- [DeleteAssetStatus](doc//DeleteAssetStatus.md)
- [DeviceInfoResponseDto](doc//DeviceInfoResponseDto.md)
- [DeviceTypeEnum](doc//DeviceTypeEnum.md)
- [ExifEntity](doc//ExifEntity.md)
- [ExifResponseDto](doc//ExifResponseDto.md)
- [GetAssetByTimeBucketDto](doc//GetAssetByTimeBucketDto.md)
- [GetAssetCountByTimeBucketDto](doc//GetAssetCountByTimeBucketDto.md)
@ -175,18 +183,24 @@ Class | Method | HTTP request | Description
- [ServerStatsResponseDto](doc//ServerStatsResponseDto.md)
- [ServerVersionReponseDto](doc//ServerVersionReponseDto.md)
- [SignUpDto](doc//SignUpDto.md)
- [SmartInfoEntity](doc//SmartInfoEntity.md)
- [SmartInfoResponseDto](doc//SmartInfoResponseDto.md)
- [SystemConfigKey](doc//SystemConfigKey.md)
- [SystemConfigResponseDto](doc//SystemConfigResponseDto.md)
- [SystemConfigResponseItem](doc//SystemConfigResponseItem.md)
- [TagEntity](doc//TagEntity.md)
- [TagResponseDto](doc//TagResponseDto.md)
- [TagTypeEnum](doc//TagTypeEnum.md)
- [ThumbnailFormat](doc//ThumbnailFormat.md)
- [TimeGroupEnum](doc//TimeGroupEnum.md)
- [UpdateAlbumDto](doc//UpdateAlbumDto.md)
- [UpdateAssetDto](doc//UpdateAssetDto.md)
- [UpdateDeviceInfoDto](doc//UpdateDeviceInfoDto.md)
- [UpdateTagDto](doc//UpdateTagDto.md)
- [UpdateUserDto](doc//UpdateUserDto.md)
- [UsageByUserDto](doc//UsageByUserDto.md)
- [UserCountResponseDto](doc//UserCountResponseDto.md)
- [UserEntity](doc//UserEntity.md)
- [UserResponseDto](doc//UserResponseDto.md)
- [ValidateAccessTokenResponseDto](doc//ValidateAccessTokenResponseDto.md)

View File

@ -26,7 +26,7 @@ Method | HTTP request | Description
[**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |
[**searchAsset**](AssetApi.md#searchasset) | **POST** /asset/search |
[**serveFile**](AssetApi.md#servefile) | **GET** /asset/file/{assetId} |
[**updateAssetById**](AssetApi.md#updateassetbyid) | **PUT** /asset/assetById/{assetId} |
[**updateAsset**](AssetApi.md#updateasset) | **PUT** /asset/{assetId} |
[**uploadFile**](AssetApi.md#uploadfile) | **POST** /asset/upload |
@ -833,8 +833,8 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **updateAssetById**
> AssetResponseDto updateAssetById(assetId, updateAssetDto)
# **updateAsset**
> AssetResponseDto updateAsset(assetId, updateAssetDto)
@ -855,10 +855,10 @@ final assetId = assetId_example; // String |
final updateAssetDto = UpdateAssetDto(); // UpdateAssetDto |
try {
final result = api_instance.updateAssetById(assetId, updateAssetDto);
final result = api_instance.updateAsset(assetId, updateAssetDto);
print(result);
} catch (e) {
print('Exception when calling AssetApi->updateAssetById: $e\n');
print('Exception when calling AssetApi->updateAsset: $e\n');
}
```

34
mobile/openapi/doc/AssetEntity.md generated Normal file
View File

@ -0,0 +1,34 @@
# openapi.model.AssetEntity
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**id** | **String** | |
**deviceAssetId** | **String** | |
**userId** | **String** | |
**deviceId** | **String** | |
**type** | **String** | |
**originalPath** | **String** | |
**resizePath** | **String** | |
**webpPath** | **String** | |
**encodedVideoPath** | **String** | |
**createdAt** | **String** | |
**modifiedAt** | **String** | |
**isFavorite** | **bool** | |
**mimeType** | **String** | |
**checksum** | [**Object**](.md) | | [optional]
**duration** | **String** | |
**isVisible** | **bool** | |
**livePhotoVideoId** | **String** | |
**exifInfo** | [**ExifEntity**](ExifEntity.md) | | [optional]
**smartInfo** | [**SmartInfoEntity**](SmartInfoEntity.md) | | [optional]
**tags** | [**List<TagEntity>**](TagEntity.md) | | [default to const []]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -25,6 +25,7 @@ Name | Type | Description | Notes
**exifInfo** | [**ExifResponseDto**](ExifResponseDto.md) | | [optional]
**smartInfo** | [**SmartInfoResponseDto**](SmartInfoResponseDto.md) | | [optional]
**livePhotoVideoId** | **String** | | [optional]
**tags** | [**List<TagResponseDto>**](TagResponseDto.md) | | [default to const []]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

16
mobile/openapi/doc/CreateTagDto.md generated Normal file
View File

@ -0,0 +1,16 @@
# openapi.model.CreateTagDto
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**type** | [**TagTypeEnum**](TagTypeEnum.md) | |
**name** | **String** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

39
mobile/openapi/doc/ExifEntity.md generated Normal file
View File

@ -0,0 +1,39 @@
# openapi.model.ExifEntity
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**id** | **String** | |
**assetId** | **String** | |
**description** | **String** | General info |
**exifImageWidth** | **num** | |
**exifImageHeight** | **num** | |
**fileSizeInByte** | **num** | |
**orientation** | **String** | |
**dateTimeOriginal** | [**DateTime**](DateTime.md) | |
**modifyDate** | [**DateTime**](DateTime.md) | |
**latitude** | **num** | |
**longitude** | **num** | |
**city** | **String** | |
**state** | **String** | |
**country** | **String** | |
**make** | **String** | Image info |
**model** | **String** | |
**imageName** | **String** | |
**lensModel** | **String** | |
**fNumber** | **num** | |
**focalLength** | **num** | |
**iso** | **num** | |
**exposureTime** | **num** | |
**fps** | **num** | Video info | [optional]
**asset** | [**AssetEntity**](AssetEntity.md) | | [optional]
**exifTextSearchableColumn** | **String** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

19
mobile/openapi/doc/SmartInfoEntity.md generated Normal file
View File

@ -0,0 +1,19 @@
# openapi.model.SmartInfoEntity
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**id** | **String** | |
**assetId** | **String** | |
**tags** | **List<String>** | | [default to const []]
**objects** | **List<String>** | | [default to const []]
**asset** | [**AssetEntity**](AssetEntity.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

221
mobile/openapi/doc/TagApi.md generated Normal file
View File

@ -0,0 +1,221 @@
# openapi.api.TagApi
## Load the API package
```dart
import 'package:openapi/api.dart';
```
All URIs are relative to */api*
Method | HTTP request | Description
------------- | ------------- | -------------
[**create**](TagApi.md#create) | **POST** /tag |
[**delete**](TagApi.md#delete) | **DELETE** /tag/{id} |
[**findAll**](TagApi.md#findall) | **GET** /tag |
[**findOne**](TagApi.md#findone) | **GET** /tag/{id} |
[**update**](TagApi.md#update) | **PATCH** /tag/{id} |
# **create**
> TagEntity create(createTagDto)
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = TagApi();
final createTagDto = CreateTagDto(); // CreateTagDto |
try {
final result = api_instance.create(createTagDto);
print(result);
} catch (e) {
print('Exception when calling TagApi->create: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**createTagDto** | [**CreateTagDto**](CreateTagDto.md)| |
### Return type
[**TagEntity**](TagEntity.md)
### Authorization
No authorization required
### 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)
# **delete**
> TagEntity delete(id)
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = TagApi();
final id = id_example; // String |
try {
final result = api_instance.delete(id);
print(result);
} catch (e) {
print('Exception when calling TagApi->delete: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**id** | **String**| |
### Return type
[**TagEntity**](TagEntity.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **findAll**
> List<TagEntity> findAll()
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = TagApi();
try {
final result = api_instance.findAll();
print(result);
} catch (e) {
print('Exception when calling TagApi->findAll: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
[**List<TagEntity>**](TagEntity.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **findOne**
> TagEntity findOne(id)
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = TagApi();
final id = id_example; // String |
try {
final result = api_instance.findOne(id);
print(result);
} catch (e) {
print('Exception when calling TagApi->findOne: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**id** | **String**| |
### Return type
[**TagEntity**](TagEntity.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **update**
> Object update(id, updateTagDto)
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = TagApi();
final id = id_example; // String |
final updateTagDto = UpdateTagDto(); // UpdateTagDto |
try {
final result = api_instance.update(id, updateTagDto);
print(result);
} catch (e) {
print('Exception when calling TagApi->update: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**id** | **String**| |
**updateTagDto** | [**UpdateTagDto**](UpdateTagDto.md)| |
### Return type
[**Object**](Object.md)
### Authorization
No authorization required
### 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)

21
mobile/openapi/doc/TagEntity.md generated Normal file
View File

@ -0,0 +1,21 @@
# openapi.model.TagEntity
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**id** | **String** | |
**type** | **String** | |
**name** | **String** | |
**userId** | **String** | |
**renameTagId** | **String** | |
**assets** | [**List<AssetEntity>**](AssetEntity.md) | | [default to const []]
**user** | [**UserEntity**](UserEntity.md) | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

17
mobile/openapi/doc/TagResponseDto.md generated Normal file
View File

@ -0,0 +1,17 @@
# openapi.model.TagResponseDto
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**id** | **String** | |
**type** | [**TagTypeEnum**](TagTypeEnum.md) | |
**name** | **String** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

14
mobile/openapi/doc/TagTypeEnum.md generated Normal file
View File

@ -0,0 +1,14 @@
# openapi.model.TagTypeEnum
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -8,7 +8,8 @@ import 'package:openapi/api.dart';
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**isFavorite** | **bool** | |
**tagIds** | **List<String>** | | [optional] [default to const []]
**isFavorite** | **bool** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

16
mobile/openapi/doc/UpdateTagDto.md generated Normal file
View File

@ -0,0 +1,16 @@
# openapi.model.UpdateTagDto
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**name** | **String** | | [optional]
**renameTagId** | **String** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

27
mobile/openapi/doc/UserEntity.md generated Normal file
View File

@ -0,0 +1,27 @@
# openapi.model.UserEntity
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**id** | **String** | |
**firstName** | **String** | |
**lastName** | **String** | |
**isAdmin** | **bool** | |
**email** | **String** | |
**password** | **String** | | [optional]
**salt** | **String** | | [optional]
**oauthId** | **String** | |
**profileImagePath** | **String** | |
**shouldChangePassword** | **bool** | |
**createdAt** | **String** | |
**deletedAt** | [**DateTime**](DateTime.md) | | [optional]
**tags** | [**List<TagEntity>**](TagEntity.md) | | [default to const []]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -35,6 +35,7 @@ part 'api/job_api.dart';
part 'api/o_auth_api.dart';
part 'api/server_info_api.dart';
part 'api/system_config_api.dart';
part 'api/tag_api.dart';
part 'api/user_api.dart';
part 'model/add_assets_dto.dart';
@ -47,6 +48,7 @@ part 'model/all_job_status_response_dto.dart';
part 'model/asset_count_by_time_bucket.dart';
part 'model/asset_count_by_time_bucket_response_dto.dart';
part 'model/asset_count_by_user_id_response_dto.dart';
part 'model/asset_entity.dart';
part 'model/asset_file_upload_response_dto.dart';
part 'model/asset_response_dto.dart';
part 'model/asset_type_enum.dart';
@ -57,6 +59,7 @@ part 'model/check_existing_assets_response_dto.dart';
part 'model/create_album_dto.dart';
part 'model/create_device_info_dto.dart';
part 'model/create_profile_image_response_dto.dart';
part 'model/create_tag_dto.dart';
part 'model/create_user_dto.dart';
part 'model/curated_locations_response_dto.dart';
part 'model/curated_objects_response_dto.dart';
@ -65,6 +68,7 @@ part 'model/delete_asset_response_dto.dart';
part 'model/delete_asset_status.dart';
part 'model/device_info_response_dto.dart';
part 'model/device_type_enum.dart';
part 'model/exif_entity.dart';
part 'model/exif_response_dto.dart';
part 'model/get_asset_by_time_bucket_dto.dart';
part 'model/get_asset_count_by_time_bucket_dto.dart';
@ -86,18 +90,24 @@ part 'model/server_ping_response.dart';
part 'model/server_stats_response_dto.dart';
part 'model/server_version_reponse_dto.dart';
part 'model/sign_up_dto.dart';
part 'model/smart_info_entity.dart';
part 'model/smart_info_response_dto.dart';
part 'model/system_config_key.dart';
part 'model/system_config_response_dto.dart';
part 'model/system_config_response_item.dart';
part 'model/tag_entity.dart';
part 'model/tag_response_dto.dart';
part 'model/tag_type_enum.dart';
part 'model/thumbnail_format.dart';
part 'model/time_group_enum.dart';
part 'model/update_album_dto.dart';
part 'model/update_asset_dto.dart';
part 'model/update_device_info_dto.dart';
part 'model/update_tag_dto.dart';
part 'model/update_user_dto.dart';
part 'model/usage_by_user_dto.dart';
part 'model/user_count_response_dto.dart';
part 'model/user_entity.dart';
part 'model/user_response_dto.dart';
part 'model/validate_access_token_response_dto.dart';

View File

@ -924,9 +924,9 @@ class AssetApi {
/// * [String] assetId (required):
///
/// * [UpdateAssetDto] updateAssetDto (required):
Future<Response> updateAssetByIdWithHttpInfo(String assetId, UpdateAssetDto updateAssetDto,) async {
Future<Response> updateAssetWithHttpInfo(String assetId, UpdateAssetDto updateAssetDto,) async {
// ignore: prefer_const_declarations
final path = r'/asset/assetById/{assetId}'
final path = r'/asset/{assetId}'
.replaceAll('{assetId}', assetId);
// ignore: prefer_final_locals
@ -959,8 +959,8 @@ class AssetApi {
/// * [String] assetId (required):
///
/// * [UpdateAssetDto] updateAssetDto (required):
Future<AssetResponseDto?> updateAssetById(String assetId, UpdateAssetDto updateAssetDto,) async {
final response = await updateAssetByIdWithHttpInfo(assetId, updateAssetDto,);
Future<AssetResponseDto?> updateAsset(String assetId, UpdateAssetDto updateAssetDto,) async {
final response = await updateAssetWithHttpInfo(assetId, updateAssetDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}

257
mobile/openapi/lib/api/tag_api.dart generated Normal file
View File

@ -0,0 +1,257 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class TagApi {
TagApi([ApiClient? apiClient]) : apiClient = apiClient ?? defaultApiClient;
final ApiClient apiClient;
/// Performs an HTTP 'POST /tag' operation and returns the [Response].
/// Parameters:
///
/// * [CreateTagDto] createTagDto (required):
Future<Response> createWithHttpInfo(CreateTagDto createTagDto,) async {
// ignore: prefer_const_declarations
final path = r'/tag';
// ignore: prefer_final_locals
Object? postBody = createTagDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [CreateTagDto] createTagDto (required):
Future<TagEntity?> create(CreateTagDto createTagDto,) async {
final response = await createWithHttpInfo(createTagDto,);
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), 'TagEntity',) as TagEntity;
}
return null;
}
/// Performs an HTTP 'DELETE /tag/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> deleteWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/tag/{id}'
.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,
'DELETE',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [String] id (required):
Future<TagEntity?> delete(String id,) async {
final response = await deleteWithHttpInfo(id,);
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), 'TagEntity',) as TagEntity;
}
return null;
}
/// Performs an HTTP 'GET /tag' operation and returns the [Response].
Future<Response> findAllWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/tag';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<List<TagEntity>?> findAll() async {
final response = await findAllWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<TagEntity>') as List)
.cast<TagEntity>()
.toList();
}
return null;
}
/// Performs an HTTP 'GET /tag/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> findOneWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/tag/{id}'
.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,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [String] id (required):
Future<TagEntity?> findOne(String id,) async {
final response = await findOneWithHttpInfo(id,);
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), 'TagEntity',) as TagEntity;
}
return null;
}
/// Performs an HTTP 'PATCH /tag/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
///
/// * [UpdateTagDto] updateTagDto (required):
Future<Response> updateWithHttpInfo(String id, UpdateTagDto updateTagDto,) async {
// ignore: prefer_const_declarations
final path = r'/tag/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody = updateTagDto;
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):
///
/// * [UpdateTagDto] updateTagDto (required):
Future<Object?> update(String id, UpdateTagDto updateTagDto,) async {
final response = await updateWithHttpInfo(id, updateTagDto,);
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), 'Object',) as Object;
}
return null;
}
}

View File

@ -212,6 +212,8 @@ class ApiClient {
return AssetCountByTimeBucketResponseDto.fromJson(value);
case 'AssetCountByUserIdResponseDto':
return AssetCountByUserIdResponseDto.fromJson(value);
case 'AssetEntity':
return AssetEntity.fromJson(value);
case 'AssetFileUploadResponseDto':
return AssetFileUploadResponseDto.fromJson(value);
case 'AssetResponseDto':
@ -232,6 +234,8 @@ class ApiClient {
return CreateDeviceInfoDto.fromJson(value);
case 'CreateProfileImageResponseDto':
return CreateProfileImageResponseDto.fromJson(value);
case 'CreateTagDto':
return CreateTagDto.fromJson(value);
case 'CreateUserDto':
return CreateUserDto.fromJson(value);
case 'CuratedLocationsResponseDto':
@ -248,6 +252,8 @@ class ApiClient {
return DeviceInfoResponseDto.fromJson(value);
case 'DeviceTypeEnum':
return DeviceTypeEnumTypeTransformer().decode(value);
case 'ExifEntity':
return ExifEntity.fromJson(value);
case 'ExifResponseDto':
return ExifResponseDto.fromJson(value);
case 'GetAssetByTimeBucketDto':
@ -290,6 +296,8 @@ class ApiClient {
return ServerVersionReponseDto.fromJson(value);
case 'SignUpDto':
return SignUpDto.fromJson(value);
case 'SmartInfoEntity':
return SmartInfoEntity.fromJson(value);
case 'SmartInfoResponseDto':
return SmartInfoResponseDto.fromJson(value);
case 'SystemConfigKey':
@ -298,6 +306,12 @@ class ApiClient {
return SystemConfigResponseDto.fromJson(value);
case 'SystemConfigResponseItem':
return SystemConfigResponseItem.fromJson(value);
case 'TagEntity':
return TagEntity.fromJson(value);
case 'TagResponseDto':
return TagResponseDto.fromJson(value);
case 'TagTypeEnum':
return TagTypeEnumTypeTransformer().decode(value);
case 'ThumbnailFormat':
return ThumbnailFormatTypeTransformer().decode(value);
case 'TimeGroupEnum':
@ -308,12 +322,16 @@ class ApiClient {
return UpdateAssetDto.fromJson(value);
case 'UpdateDeviceInfoDto':
return UpdateDeviceInfoDto.fromJson(value);
case 'UpdateTagDto':
return UpdateTagDto.fromJson(value);
case 'UpdateUserDto':
return UpdateUserDto.fromJson(value);
case 'UsageByUserDto':
return UsageByUserDto.fromJson(value);
case 'UserCountResponseDto':
return UserCountResponseDto.fromJson(value);
case 'UserEntity':
return UserEntity.fromJson(value);
case 'UserResponseDto':
return UserResponseDto.fromJson(value);
case 'ValidateAccessTokenResponseDto':

View File

@ -73,6 +73,9 @@ String parameterToString(dynamic value) {
if (value is SystemConfigKey) {
return SystemConfigKeyTypeTransformer().encode(value).toString();
}
if (value is TagTypeEnum) {
return TagTypeEnumTypeTransformer().encode(value).toString();
}
if (value is ThumbnailFormat) {
return ThumbnailFormatTypeTransformer().encode(value).toString();
}

View File

@ -43,51 +43,48 @@ class AlbumResponseDto {
List<AssetResponseDto> assets;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is AlbumResponseDto &&
other.assetCount == assetCount &&
other.id == id &&
other.ownerId == ownerId &&
other.albumName == albumName &&
other.createdAt == createdAt &&
other.albumThumbnailAssetId == albumThumbnailAssetId &&
other.shared == shared &&
other.sharedUsers == sharedUsers &&
other.assets == assets;
bool operator ==(Object other) => identical(this, other) || other is AlbumResponseDto &&
other.assetCount == assetCount &&
other.id == id &&
other.ownerId == ownerId &&
other.albumName == albumName &&
other.createdAt == createdAt &&
other.albumThumbnailAssetId == albumThumbnailAssetId &&
other.shared == shared &&
other.sharedUsers == sharedUsers &&
other.assets == assets;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(assetCount.hashCode) +
(id.hashCode) +
(ownerId.hashCode) +
(albumName.hashCode) +
(createdAt.hashCode) +
(albumThumbnailAssetId == null ? 0 : albumThumbnailAssetId!.hashCode) +
(shared.hashCode) +
(sharedUsers.hashCode) +
(assets.hashCode);
// ignore: unnecessary_parenthesis
(assetCount.hashCode) +
(id.hashCode) +
(ownerId.hashCode) +
(albumName.hashCode) +
(createdAt.hashCode) +
(albumThumbnailAssetId == null ? 0 : albumThumbnailAssetId!.hashCode) +
(shared.hashCode) +
(sharedUsers.hashCode) +
(assets.hashCode);
@override
String toString() =>
'AlbumResponseDto[assetCount=$assetCount, id=$id, ownerId=$ownerId, albumName=$albumName, createdAt=$createdAt, albumThumbnailAssetId=$albumThumbnailAssetId, shared=$shared, sharedUsers=$sharedUsers, assets=$assets]';
String toString() => 'AlbumResponseDto[assetCount=$assetCount, id=$id, ownerId=$ownerId, albumName=$albumName, createdAt=$createdAt, albumThumbnailAssetId=$albumThumbnailAssetId, shared=$shared, sharedUsers=$sharedUsers, assets=$assets]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'assetCount'] = assetCount;
_json[r'id'] = id;
_json[r'ownerId'] = ownerId;
_json[r'albumName'] = albumName;
_json[r'createdAt'] = createdAt;
_json[r'assetCount'] = assetCount;
_json[r'id'] = id;
_json[r'ownerId'] = ownerId;
_json[r'albumName'] = albumName;
_json[r'createdAt'] = createdAt;
if (albumThumbnailAssetId != null) {
_json[r'albumThumbnailAssetId'] = albumThumbnailAssetId;
} else {
_json[r'albumThumbnailAssetId'] = null;
}
_json[r'shared'] = shared;
_json[r'sharedUsers'] = sharedUsers;
_json[r'assets'] = assets;
_json[r'shared'] = shared;
_json[r'sharedUsers'] = sharedUsers;
_json[r'assets'] = assets;
return _json;
}
@ -101,13 +98,13 @@ class AlbumResponseDto {
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
// assert(() {
// requiredKeys.forEach((key) {
// assert(json.containsKey(key), 'Required key "AlbumResponseDto[$key]" is missing from JSON.');
// assert(json[key] != null, 'Required key "AlbumResponseDto[$key]" has a null value in JSON.');
// });
// return true;
// }());
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "AlbumResponseDto[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "AlbumResponseDto[$key]" has a null value in JSON.');
});
return true;
}());
return AlbumResponseDto(
assetCount: mapValueOfType<int>(json, r'assetCount')!,
@ -115,8 +112,7 @@ class AlbumResponseDto {
ownerId: mapValueOfType<String>(json, r'ownerId')!,
albumName: mapValueOfType<String>(json, r'albumName')!,
createdAt: mapValueOfType<String>(json, r'createdAt')!,
albumThumbnailAssetId:
mapValueOfType<String>(json, r'albumThumbnailAssetId'),
albumThumbnailAssetId: mapValueOfType<String>(json, r'albumThumbnailAssetId'),
shared: mapValueOfType<bool>(json, r'shared')!,
sharedUsers: UserResponseDto.listFromJson(json[r'sharedUsers'])!,
assets: AssetResponseDto.listFromJson(json[r'assets'])!,
@ -125,10 +121,7 @@ class AlbumResponseDto {
return null;
}
static List<AlbumResponseDto>? listFromJson(
dynamic json, {
bool growable = false,
}) {
static List<AlbumResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <AlbumResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
@ -156,18 +149,12 @@ class AlbumResponseDto {
}
// maps a json object with a list of AlbumResponseDto-objects as value to a dart map
static Map<String, List<AlbumResponseDto>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
static Map<String, List<AlbumResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AlbumResponseDto>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AlbumResponseDto.listFromJson(
entry.value,
growable: growable,
);
final value = AlbumResponseDto.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
@ -189,3 +176,4 @@ class AlbumResponseDto {
'assets',
};
}

384
mobile/openapi/lib/model/asset_entity.dart generated Normal file
View File

@ -0,0 +1,384 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class AssetEntity {
/// Returns a new [AssetEntity] instance.
AssetEntity({
required this.id,
required this.deviceAssetId,
required this.userId,
required this.deviceId,
required this.type,
required this.originalPath,
required this.resizePath,
required this.webpPath,
required this.encodedVideoPath,
required this.createdAt,
required this.modifiedAt,
required this.isFavorite,
required this.mimeType,
this.checksum,
required this.duration,
required this.isVisible,
required this.livePhotoVideoId,
this.exifInfo,
this.smartInfo,
this.tags = const [],
});
String id;
String deviceAssetId;
String userId;
String deviceId;
AssetEntityTypeEnum type;
String originalPath;
String? resizePath;
String? webpPath;
String encodedVideoPath;
String createdAt;
String modifiedAt;
bool isFavorite;
String? mimeType;
Object? checksum;
String? duration;
bool isVisible;
String? livePhotoVideoId;
///
/// 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.
///
ExifEntity? exifInfo;
///
/// 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.
///
SmartInfoEntity? smartInfo;
List<TagEntity> tags;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetEntity &&
other.id == id &&
other.deviceAssetId == deviceAssetId &&
other.userId == userId &&
other.deviceId == deviceId &&
other.type == type &&
other.originalPath == originalPath &&
other.resizePath == resizePath &&
other.webpPath == webpPath &&
other.encodedVideoPath == encodedVideoPath &&
other.createdAt == createdAt &&
other.modifiedAt == modifiedAt &&
other.isFavorite == isFavorite &&
other.mimeType == mimeType &&
other.checksum == checksum &&
other.duration == duration &&
other.isVisible == isVisible &&
other.livePhotoVideoId == livePhotoVideoId &&
other.exifInfo == exifInfo &&
other.smartInfo == smartInfo &&
other.tags == tags;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(id.hashCode) +
(deviceAssetId.hashCode) +
(userId.hashCode) +
(deviceId.hashCode) +
(type.hashCode) +
(originalPath.hashCode) +
(resizePath == null ? 0 : resizePath!.hashCode) +
(webpPath == null ? 0 : webpPath!.hashCode) +
(encodedVideoPath.hashCode) +
(createdAt.hashCode) +
(modifiedAt.hashCode) +
(isFavorite.hashCode) +
(mimeType == null ? 0 : mimeType!.hashCode) +
(checksum == null ? 0 : checksum!.hashCode) +
(duration == null ? 0 : duration!.hashCode) +
(isVisible.hashCode) +
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
(exifInfo == null ? 0 : exifInfo!.hashCode) +
(smartInfo == null ? 0 : smartInfo!.hashCode) +
(tags.hashCode);
@override
String toString() => 'AssetEntity[id=$id, deviceAssetId=$deviceAssetId, userId=$userId, deviceId=$deviceId, type=$type, originalPath=$originalPath, resizePath=$resizePath, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, createdAt=$createdAt, modifiedAt=$modifiedAt, isFavorite=$isFavorite, mimeType=$mimeType, checksum=$checksum, duration=$duration, isVisible=$isVisible, livePhotoVideoId=$livePhotoVideoId, exifInfo=$exifInfo, smartInfo=$smartInfo, tags=$tags]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'id'] = id;
_json[r'deviceAssetId'] = deviceAssetId;
_json[r'userId'] = userId;
_json[r'deviceId'] = deviceId;
_json[r'type'] = type;
_json[r'originalPath'] = originalPath;
if (resizePath != null) {
_json[r'resizePath'] = resizePath;
} else {
_json[r'resizePath'] = null;
}
if (webpPath != null) {
_json[r'webpPath'] = webpPath;
} else {
_json[r'webpPath'] = null;
}
_json[r'encodedVideoPath'] = encodedVideoPath;
_json[r'createdAt'] = createdAt;
_json[r'modifiedAt'] = modifiedAt;
_json[r'isFavorite'] = isFavorite;
if (mimeType != null) {
_json[r'mimeType'] = mimeType;
} else {
_json[r'mimeType'] = null;
}
if (checksum != null) {
_json[r'checksum'] = checksum;
} else {
_json[r'checksum'] = null;
}
if (duration != null) {
_json[r'duration'] = duration;
} else {
_json[r'duration'] = null;
}
_json[r'isVisible'] = isVisible;
if (livePhotoVideoId != null) {
_json[r'livePhotoVideoId'] = livePhotoVideoId;
} else {
_json[r'livePhotoVideoId'] = null;
}
if (exifInfo != null) {
_json[r'exifInfo'] = exifInfo;
} else {
_json[r'exifInfo'] = null;
}
if (smartInfo != null) {
_json[r'smartInfo'] = smartInfo;
} else {
_json[r'smartInfo'] = null;
}
_json[r'tags'] = tags;
return _json;
}
/// Returns a new [AssetEntity] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static AssetEntity? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "AssetEntity[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "AssetEntity[$key]" has a null value in JSON.');
});
return true;
}());
return AssetEntity(
id: mapValueOfType<String>(json, r'id')!,
deviceAssetId: mapValueOfType<String>(json, r'deviceAssetId')!,
userId: mapValueOfType<String>(json, r'userId')!,
deviceId: mapValueOfType<String>(json, r'deviceId')!,
type: AssetEntityTypeEnum.fromJson(json[r'type'])!,
originalPath: mapValueOfType<String>(json, r'originalPath')!,
resizePath: mapValueOfType<String>(json, r'resizePath'),
webpPath: mapValueOfType<String>(json, r'webpPath'),
encodedVideoPath: mapValueOfType<String>(json, r'encodedVideoPath')!,
createdAt: mapValueOfType<String>(json, r'createdAt')!,
modifiedAt: mapValueOfType<String>(json, r'modifiedAt')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
mimeType: mapValueOfType<String>(json, r'mimeType'),
checksum: mapValueOfType<Object>(json, r'checksum'),
duration: mapValueOfType<String>(json, r'duration'),
isVisible: mapValueOfType<bool>(json, r'isVisible')!,
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
exifInfo: ExifEntity.fromJson(json[r'exifInfo']),
smartInfo: SmartInfoEntity.fromJson(json[r'smartInfo']),
tags: TagEntity.listFromJson(json[r'tags'])!,
);
}
return null;
}
static List<AssetEntity>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetEntity>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AssetEntity.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, AssetEntity> mapFromJson(dynamic json) {
final map = <String, AssetEntity>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AssetEntity.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of AssetEntity-objects as value to a dart map
static Map<String, List<AssetEntity>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AssetEntity>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AssetEntity.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'id',
'deviceAssetId',
'userId',
'deviceId',
'type',
'originalPath',
'resizePath',
'webpPath',
'encodedVideoPath',
'createdAt',
'modifiedAt',
'isFavorite',
'mimeType',
'duration',
'isVisible',
'livePhotoVideoId',
'tags',
};
}
class AssetEntityTypeEnum {
/// Instantiate a new enum with the provided [value].
const AssetEntityTypeEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const IMAGE = AssetEntityTypeEnum._(r'IMAGE');
static const VIDEO = AssetEntityTypeEnum._(r'VIDEO');
static const AUDIO = AssetEntityTypeEnum._(r'AUDIO');
static const OTHER = AssetEntityTypeEnum._(r'OTHER');
/// List of all possible values in this [enum][AssetEntityTypeEnum].
static const values = <AssetEntityTypeEnum>[
IMAGE,
VIDEO,
AUDIO,
OTHER,
];
static AssetEntityTypeEnum? fromJson(dynamic value) => AssetEntityTypeEnumTypeTransformer().decode(value);
static List<AssetEntityTypeEnum>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetEntityTypeEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AssetEntityTypeEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [AssetEntityTypeEnum] to String,
/// and [decode] dynamic data back to [AssetEntityTypeEnum].
class AssetEntityTypeEnumTypeTransformer {
factory AssetEntityTypeEnumTypeTransformer() => _instance ??= const AssetEntityTypeEnumTypeTransformer._();
const AssetEntityTypeEnumTypeTransformer._();
String encode(AssetEntityTypeEnum data) => data.value;
/// Decodes a [dynamic value][data] to a AssetEntityTypeEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetEntityTypeEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data.toString()) {
case r'IMAGE': return AssetEntityTypeEnum.IMAGE;
case r'VIDEO': return AssetEntityTypeEnum.VIDEO;
case r'AUDIO': return AssetEntityTypeEnum.AUDIO;
case r'OTHER': return AssetEntityTypeEnum.OTHER;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [AssetEntityTypeEnumTypeTransformer] instance.
static AssetEntityTypeEnumTypeTransformer? _instance;
}

View File

@ -30,6 +30,7 @@ class AssetResponseDto {
this.exifInfo,
this.smartInfo,
this.livePhotoVideoId,
this.tags = const [],
});
AssetTypeEnum type;
@ -78,6 +79,8 @@ class AssetResponseDto {
String? livePhotoVideoId;
List<TagResponseDto> tags;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetResponseDto &&
other.type == type &&
@ -96,7 +99,8 @@ class AssetResponseDto {
other.encodedVideoPath == encodedVideoPath &&
other.exifInfo == exifInfo &&
other.smartInfo == smartInfo &&
other.livePhotoVideoId == livePhotoVideoId;
other.livePhotoVideoId == livePhotoVideoId &&
other.tags == tags;
@override
int get hashCode =>
@ -117,10 +121,11 @@ class AssetResponseDto {
(encodedVideoPath == null ? 0 : encodedVideoPath!.hashCode) +
(exifInfo == null ? 0 : exifInfo!.hashCode) +
(smartInfo == null ? 0 : smartInfo!.hashCode) +
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode);
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
(tags.hashCode);
@override
String toString() => 'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, resizePath=$resizePath, createdAt=$createdAt, modifiedAt=$modifiedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo, livePhotoVideoId=$livePhotoVideoId]';
String toString() => 'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, resizePath=$resizePath, createdAt=$createdAt, modifiedAt=$modifiedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo, livePhotoVideoId=$livePhotoVideoId, tags=$tags]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
@ -169,6 +174,7 @@ class AssetResponseDto {
} else {
_json[r'livePhotoVideoId'] = null;
}
_json[r'tags'] = tags;
return _json;
}
@ -208,6 +214,7 @@ class AssetResponseDto {
exifInfo: ExifResponseDto.fromJson(json[r'exifInfo']),
smartInfo: SmartInfoResponseDto.fromJson(json[r'smartInfo']),
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
tags: TagResponseDto.listFromJson(json[r'tags'])!,
);
}
return null;
@ -270,6 +277,7 @@ class AssetResponseDto {
'mimeType',
'duration',
'webpPath',
'tags',
};
}

View File

@ -0,0 +1,119 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class CreateTagDto {
/// Returns a new [CreateTagDto] instance.
CreateTagDto({
required this.type,
required this.name,
});
TagTypeEnum type;
String name;
@override
bool operator ==(Object other) => identical(this, other) || other is CreateTagDto &&
other.type == type &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(type.hashCode) +
(name.hashCode);
@override
String toString() => 'CreateTagDto[type=$type, name=$name]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'type'] = type;
_json[r'name'] = name;
return _json;
}
/// Returns a new [CreateTagDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static CreateTagDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "CreateTagDto[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "CreateTagDto[$key]" has a null value in JSON.');
});
return true;
}());
return CreateTagDto(
type: TagTypeEnum.fromJson(json[r'type'])!,
name: mapValueOfType<String>(json, r'name')!,
);
}
return null;
}
static List<CreateTagDto>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <CreateTagDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = CreateTagDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, CreateTagDto> mapFromJson(dynamic json) {
final map = <String, CreateTagDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = CreateTagDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of CreateTagDto-objects as value to a dart map
static Map<String, List<CreateTagDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<CreateTagDto>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = CreateTagDto.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'type',
'name',
};
}

414
mobile/openapi/lib/model/exif_entity.dart generated Normal file
View File

@ -0,0 +1,414 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class ExifEntity {
/// Returns a new [ExifEntity] instance.
ExifEntity({
required this.id,
required this.assetId,
required this.description,
required this.exifImageWidth,
required this.exifImageHeight,
required this.fileSizeInByte,
required this.orientation,
required this.dateTimeOriginal,
required this.modifyDate,
required this.latitude,
required this.longitude,
required this.city,
required this.state,
required this.country,
required this.make,
required this.model,
required this.imageName,
required this.lensModel,
required this.fNumber,
required this.focalLength,
required this.iso,
required this.exposureTime,
this.fps,
this.asset,
required this.exifTextSearchableColumn,
});
String id;
String assetId;
/// General info
String description;
num? exifImageWidth;
num? exifImageHeight;
num? fileSizeInByte;
String? orientation;
DateTime? dateTimeOriginal;
DateTime? modifyDate;
num? latitude;
num? longitude;
String? city;
String? state;
String? country;
/// Image info
String? make;
String? model;
String? imageName;
String? lensModel;
num? fNumber;
num? focalLength;
num? iso;
num? exposureTime;
/// Video info
num? fps;
///
/// 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.
///
AssetEntity? asset;
String exifTextSearchableColumn;
@override
bool operator ==(Object other) => identical(this, other) || other is ExifEntity &&
other.id == id &&
other.assetId == assetId &&
other.description == description &&
other.exifImageWidth == exifImageWidth &&
other.exifImageHeight == exifImageHeight &&
other.fileSizeInByte == fileSizeInByte &&
other.orientation == orientation &&
other.dateTimeOriginal == dateTimeOriginal &&
other.modifyDate == modifyDate &&
other.latitude == latitude &&
other.longitude == longitude &&
other.city == city &&
other.state == state &&
other.country == country &&
other.make == make &&
other.model == model &&
other.imageName == imageName &&
other.lensModel == lensModel &&
other.fNumber == fNumber &&
other.focalLength == focalLength &&
other.iso == iso &&
other.exposureTime == exposureTime &&
other.fps == fps &&
other.asset == asset &&
other.exifTextSearchableColumn == exifTextSearchableColumn;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(id.hashCode) +
(assetId.hashCode) +
(description.hashCode) +
(exifImageWidth == null ? 0 : exifImageWidth!.hashCode) +
(exifImageHeight == null ? 0 : exifImageHeight!.hashCode) +
(fileSizeInByte == null ? 0 : fileSizeInByte!.hashCode) +
(orientation == null ? 0 : orientation!.hashCode) +
(dateTimeOriginal == null ? 0 : dateTimeOriginal!.hashCode) +
(modifyDate == null ? 0 : modifyDate!.hashCode) +
(latitude == null ? 0 : latitude!.hashCode) +
(longitude == null ? 0 : longitude!.hashCode) +
(city == null ? 0 : city!.hashCode) +
(state == null ? 0 : state!.hashCode) +
(country == null ? 0 : country!.hashCode) +
(make == null ? 0 : make!.hashCode) +
(model == null ? 0 : model!.hashCode) +
(imageName == null ? 0 : imageName!.hashCode) +
(lensModel == null ? 0 : lensModel!.hashCode) +
(fNumber == null ? 0 : fNumber!.hashCode) +
(focalLength == null ? 0 : focalLength!.hashCode) +
(iso == null ? 0 : iso!.hashCode) +
(exposureTime == null ? 0 : exposureTime!.hashCode) +
(fps == null ? 0 : fps!.hashCode) +
(asset == null ? 0 : asset!.hashCode) +
(exifTextSearchableColumn.hashCode);
@override
String toString() => 'ExifEntity[id=$id, assetId=$assetId, description=$description, exifImageWidth=$exifImageWidth, exifImageHeight=$exifImageHeight, fileSizeInByte=$fileSizeInByte, orientation=$orientation, dateTimeOriginal=$dateTimeOriginal, modifyDate=$modifyDate, latitude=$latitude, longitude=$longitude, city=$city, state=$state, country=$country, make=$make, model=$model, imageName=$imageName, lensModel=$lensModel, fNumber=$fNumber, focalLength=$focalLength, iso=$iso, exposureTime=$exposureTime, fps=$fps, asset=$asset, exifTextSearchableColumn=$exifTextSearchableColumn]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'id'] = id;
_json[r'assetId'] = assetId;
_json[r'description'] = description;
if (exifImageWidth != null) {
_json[r'exifImageWidth'] = exifImageWidth;
} else {
_json[r'exifImageWidth'] = null;
}
if (exifImageHeight != null) {
_json[r'exifImageHeight'] = exifImageHeight;
} else {
_json[r'exifImageHeight'] = null;
}
if (fileSizeInByte != null) {
_json[r'fileSizeInByte'] = fileSizeInByte;
} else {
_json[r'fileSizeInByte'] = null;
}
if (orientation != null) {
_json[r'orientation'] = orientation;
} else {
_json[r'orientation'] = null;
}
if (dateTimeOriginal != null) {
_json[r'dateTimeOriginal'] = dateTimeOriginal!.toUtc().toIso8601String();
} else {
_json[r'dateTimeOriginal'] = null;
}
if (modifyDate != null) {
_json[r'modifyDate'] = modifyDate!.toUtc().toIso8601String();
} else {
_json[r'modifyDate'] = null;
}
if (latitude != null) {
_json[r'latitude'] = latitude;
} else {
_json[r'latitude'] = null;
}
if (longitude != null) {
_json[r'longitude'] = longitude;
} else {
_json[r'longitude'] = null;
}
if (city != null) {
_json[r'city'] = city;
} else {
_json[r'city'] = null;
}
if (state != null) {
_json[r'state'] = state;
} else {
_json[r'state'] = null;
}
if (country != null) {
_json[r'country'] = country;
} else {
_json[r'country'] = null;
}
if (make != null) {
_json[r'make'] = make;
} else {
_json[r'make'] = null;
}
if (model != null) {
_json[r'model'] = model;
} else {
_json[r'model'] = null;
}
if (imageName != null) {
_json[r'imageName'] = imageName;
} else {
_json[r'imageName'] = null;
}
if (lensModel != null) {
_json[r'lensModel'] = lensModel;
} else {
_json[r'lensModel'] = null;
}
if (fNumber != null) {
_json[r'fNumber'] = fNumber;
} else {
_json[r'fNumber'] = null;
}
if (focalLength != null) {
_json[r'focalLength'] = focalLength;
} else {
_json[r'focalLength'] = null;
}
if (iso != null) {
_json[r'iso'] = iso;
} else {
_json[r'iso'] = null;
}
if (exposureTime != null) {
_json[r'exposureTime'] = exposureTime;
} else {
_json[r'exposureTime'] = null;
}
if (fps != null) {
_json[r'fps'] = fps;
} else {
_json[r'fps'] = null;
}
if (asset != null) {
_json[r'asset'] = asset;
} else {
_json[r'asset'] = null;
}
_json[r'exifTextSearchableColumn'] = exifTextSearchableColumn;
return _json;
}
/// Returns a new [ExifEntity] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static ExifEntity? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "ExifEntity[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "ExifEntity[$key]" has a null value in JSON.');
});
return true;
}());
return ExifEntity(
id: mapValueOfType<String>(json, r'id')!,
assetId: mapValueOfType<String>(json, r'assetId')!,
description: mapValueOfType<String>(json, r'description')!,
exifImageWidth: json[r'exifImageWidth'] == null
? null
: num.parse(json[r'exifImageWidth'].toString()),
exifImageHeight: json[r'exifImageHeight'] == null
? null
: num.parse(json[r'exifImageHeight'].toString()),
fileSizeInByte: json[r'fileSizeInByte'] == null
? null
: num.parse(json[r'fileSizeInByte'].toString()),
orientation: mapValueOfType<String>(json, r'orientation'),
dateTimeOriginal: mapDateTime(json, r'dateTimeOriginal', ''),
modifyDate: mapDateTime(json, r'modifyDate', ''),
latitude: json[r'latitude'] == null
? null
: num.parse(json[r'latitude'].toString()),
longitude: json[r'longitude'] == null
? null
: num.parse(json[r'longitude'].toString()),
city: mapValueOfType<String>(json, r'city'),
state: mapValueOfType<String>(json, r'state'),
country: mapValueOfType<String>(json, r'country'),
make: mapValueOfType<String>(json, r'make'),
model: mapValueOfType<String>(json, r'model'),
imageName: mapValueOfType<String>(json, r'imageName'),
lensModel: mapValueOfType<String>(json, r'lensModel'),
fNumber: json[r'fNumber'] == null
? null
: num.parse(json[r'fNumber'].toString()),
focalLength: json[r'focalLength'] == null
? null
: num.parse(json[r'focalLength'].toString()),
iso: json[r'iso'] == null
? null
: num.parse(json[r'iso'].toString()),
exposureTime: json[r'exposureTime'] == null
? null
: num.parse(json[r'exposureTime'].toString()),
fps: json[r'fps'] == null
? null
: num.parse(json[r'fps'].toString()),
asset: AssetEntity.fromJson(json[r'asset']),
exifTextSearchableColumn: mapValueOfType<String>(json, r'exifTextSearchableColumn')!,
);
}
return null;
}
static List<ExifEntity>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <ExifEntity>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = ExifEntity.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, ExifEntity> mapFromJson(dynamic json) {
final map = <String, ExifEntity>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = ExifEntity.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of ExifEntity-objects as value to a dart map
static Map<String, List<ExifEntity>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<ExifEntity>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = ExifEntity.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'id',
'assetId',
'description',
'exifImageWidth',
'exifImageHeight',
'fileSizeInByte',
'orientation',
'dateTimeOriginal',
'modifyDate',
'latitude',
'longitude',
'city',
'state',
'country',
'make',
'model',
'imageName',
'lensModel',
'fNumber',
'focalLength',
'iso',
'exposureTime',
'exifTextSearchableColumn',
};
}

View File

@ -0,0 +1,164 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class SmartInfoEntity {
/// Returns a new [SmartInfoEntity] instance.
SmartInfoEntity({
required this.id,
required this.assetId,
this.tags = const [],
this.objects = const [],
this.asset,
});
String id;
String assetId;
List<String>? tags;
List<String>? objects;
///
/// 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.
///
AssetEntity? asset;
@override
bool operator ==(Object other) => identical(this, other) || other is SmartInfoEntity &&
other.id == id &&
other.assetId == assetId &&
other.tags == tags &&
other.objects == objects &&
other.asset == asset;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(id.hashCode) +
(assetId.hashCode) +
(tags == null ? 0 : tags!.hashCode) +
(objects == null ? 0 : objects!.hashCode) +
(asset == null ? 0 : asset!.hashCode);
@override
String toString() => 'SmartInfoEntity[id=$id, assetId=$assetId, tags=$tags, objects=$objects, asset=$asset]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'id'] = id;
_json[r'assetId'] = assetId;
if (tags != null) {
_json[r'tags'] = tags;
} else {
_json[r'tags'] = null;
}
if (objects != null) {
_json[r'objects'] = objects;
} else {
_json[r'objects'] = null;
}
if (asset != null) {
_json[r'asset'] = asset;
} else {
_json[r'asset'] = null;
}
return _json;
}
/// Returns a new [SmartInfoEntity] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SmartInfoEntity? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "SmartInfoEntity[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "SmartInfoEntity[$key]" has a null value in JSON.');
});
return true;
}());
return SmartInfoEntity(
id: mapValueOfType<String>(json, r'id')!,
assetId: mapValueOfType<String>(json, r'assetId')!,
tags: json[r'tags'] is List
? (json[r'tags'] as List).cast<String>()
: const [],
objects: json[r'objects'] is List
? (json[r'objects'] as List).cast<String>()
: const [],
asset: AssetEntity.fromJson(json[r'asset']),
);
}
return null;
}
static List<SmartInfoEntity>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <SmartInfoEntity>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SmartInfoEntity.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SmartInfoEntity> mapFromJson(dynamic json) {
final map = <String, SmartInfoEntity>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SmartInfoEntity.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SmartInfoEntity-objects as value to a dart map
static Map<String, List<SmartInfoEntity>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SmartInfoEntity>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SmartInfoEntity.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'id',
'assetId',
'tags',
'objects',
};
}

236
mobile/openapi/lib/model/tag_entity.dart generated Normal file
View File

@ -0,0 +1,236 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class TagEntity {
/// Returns a new [TagEntity] instance.
TagEntity({
required this.id,
required this.type,
required this.name,
required this.userId,
required this.renameTagId,
this.assets = const [],
required this.user,
});
String id;
TagEntityTypeEnum type;
String name;
String userId;
String renameTagId;
List<AssetEntity> assets;
UserEntity user;
@override
bool operator ==(Object other) => identical(this, other) || other is TagEntity &&
other.id == id &&
other.type == type &&
other.name == name &&
other.userId == userId &&
other.renameTagId == renameTagId &&
other.assets == assets &&
other.user == user;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(id.hashCode) +
(type.hashCode) +
(name.hashCode) +
(userId.hashCode) +
(renameTagId.hashCode) +
(assets.hashCode) +
(user.hashCode);
@override
String toString() => 'TagEntity[id=$id, type=$type, name=$name, userId=$userId, renameTagId=$renameTagId, assets=$assets, user=$user]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'id'] = id;
_json[r'type'] = type;
_json[r'name'] = name;
_json[r'userId'] = userId;
_json[r'renameTagId'] = renameTagId;
_json[r'assets'] = assets;
_json[r'user'] = user;
return _json;
}
/// Returns a new [TagEntity] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static TagEntity? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "TagEntity[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "TagEntity[$key]" has a null value in JSON.');
});
return true;
}());
return TagEntity(
id: mapValueOfType<String>(json, r'id')!,
type: TagEntityTypeEnum.fromJson(json[r'type'])!,
name: mapValueOfType<String>(json, r'name')!,
userId: mapValueOfType<String>(json, r'userId')!,
renameTagId: mapValueOfType<String>(json, r'renameTagId')!,
assets: AssetEntity.listFromJson(json[r'assets'])!,
user: UserEntity.fromJson(json[r'user'])!,
);
}
return null;
}
static List<TagEntity>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <TagEntity>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = TagEntity.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, TagEntity> mapFromJson(dynamic json) {
final map = <String, TagEntity>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = TagEntity.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of TagEntity-objects as value to a dart map
static Map<String, List<TagEntity>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<TagEntity>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = TagEntity.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'id',
'type',
'name',
'userId',
'renameTagId',
'assets',
'user',
};
}
class TagEntityTypeEnum {
/// Instantiate a new enum with the provided [value].
const TagEntityTypeEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const OBJECT = TagEntityTypeEnum._(r'OBJECT');
static const FACE = TagEntityTypeEnum._(r'FACE');
static const CUSTOM = TagEntityTypeEnum._(r'CUSTOM');
/// List of all possible values in this [enum][TagEntityTypeEnum].
static const values = <TagEntityTypeEnum>[
OBJECT,
FACE,
CUSTOM,
];
static TagEntityTypeEnum? fromJson(dynamic value) => TagEntityTypeEnumTypeTransformer().decode(value);
static List<TagEntityTypeEnum>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <TagEntityTypeEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = TagEntityTypeEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [TagEntityTypeEnum] to String,
/// and [decode] dynamic data back to [TagEntityTypeEnum].
class TagEntityTypeEnumTypeTransformer {
factory TagEntityTypeEnumTypeTransformer() => _instance ??= const TagEntityTypeEnumTypeTransformer._();
const TagEntityTypeEnumTypeTransformer._();
String encode(TagEntityTypeEnum data) => data.value;
/// Decodes a [dynamic value][data] to a TagEntityTypeEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
TagEntityTypeEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data.toString()) {
case r'OBJECT': return TagEntityTypeEnum.OBJECT;
case r'FACE': return TagEntityTypeEnum.FACE;
case r'CUSTOM': return TagEntityTypeEnum.CUSTOM;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [TagEntityTypeEnumTypeTransformer] instance.
static TagEntityTypeEnumTypeTransformer? _instance;
}

View File

@ -0,0 +1,127 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class TagResponseDto {
/// Returns a new [TagResponseDto] instance.
TagResponseDto({
required this.id,
required this.type,
required this.name,
});
String id;
TagTypeEnum type;
String name;
@override
bool operator ==(Object other) => identical(this, other) || other is TagResponseDto &&
other.id == id &&
other.type == type &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(id.hashCode) +
(type.hashCode) +
(name.hashCode);
@override
String toString() => 'TagResponseDto[id=$id, type=$type, name=$name]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'id'] = id;
_json[r'type'] = type;
_json[r'name'] = name;
return _json;
}
/// Returns a new [TagResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static TagResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "TagResponseDto[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "TagResponseDto[$key]" has a null value in JSON.');
});
return true;
}());
return TagResponseDto(
id: mapValueOfType<String>(json, r'id')!,
type: TagTypeEnum.fromJson(json[r'type'])!,
name: mapValueOfType<String>(json, r'name')!,
);
}
return null;
}
static List<TagResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <TagResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = TagResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, TagResponseDto> mapFromJson(dynamic json) {
final map = <String, TagResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = TagResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of TagResponseDto-objects as value to a dart map
static Map<String, List<TagResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<TagResponseDto>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = TagResponseDto.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'id',
'type',
'name',
};
}

View File

@ -0,0 +1,88 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class TagTypeEnum {
/// Instantiate a new enum with the provided [value].
const TagTypeEnum._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const OBJECT = TagTypeEnum._(r'OBJECT');
static const FACE = TagTypeEnum._(r'FACE');
static const CUSTOM = TagTypeEnum._(r'CUSTOM');
/// List of all possible values in this [enum][TagTypeEnum].
static const values = <TagTypeEnum>[
OBJECT,
FACE,
CUSTOM,
];
static TagTypeEnum? fromJson(dynamic value) => TagTypeEnumTypeTransformer().decode(value);
static List<TagTypeEnum>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <TagTypeEnum>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = TagTypeEnum.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [TagTypeEnum] to String,
/// and [decode] dynamic data back to [TagTypeEnum].
class TagTypeEnumTypeTransformer {
factory TagTypeEnumTypeTransformer() => _instance ??= const TagTypeEnumTypeTransformer._();
const TagTypeEnumTypeTransformer._();
String encode(TagTypeEnum data) => data.value;
/// Decodes a [dynamic value][data] to a TagTypeEnum.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
TagTypeEnum? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data.toString()) {
case r'OBJECT': return TagTypeEnum.OBJECT;
case r'FACE': return TagTypeEnum.FACE;
case r'CUSTOM': return TagTypeEnum.CUSTOM;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [TagTypeEnumTypeTransformer] instance.
static TagTypeEnumTypeTransformer? _instance;
}

View File

@ -13,26 +13,42 @@ part of openapi.api;
class UpdateAssetDto {
/// Returns a new [UpdateAssetDto] instance.
UpdateAssetDto({
required this.isFavorite,
this.tagIds = const [],
this.isFavorite,
});
bool isFavorite;
List<String> tagIds;
///
/// 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? isFavorite;
@override
bool operator ==(Object other) => identical(this, other) || other is UpdateAssetDto &&
other.tagIds == tagIds &&
other.isFavorite == isFavorite;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(isFavorite.hashCode);
(tagIds.hashCode) +
(isFavorite == null ? 0 : isFavorite!.hashCode);
@override
String toString() => 'UpdateAssetDto[isFavorite=$isFavorite]';
String toString() => 'UpdateAssetDto[tagIds=$tagIds, isFavorite=$isFavorite]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'tagIds'] = tagIds;
if (isFavorite != null) {
_json[r'isFavorite'] = isFavorite;
} else {
_json[r'isFavorite'] = null;
}
return _json;
}
@ -55,7 +71,10 @@ class UpdateAssetDto {
}());
return UpdateAssetDto(
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
tagIds: json[r'tagIds'] is List
? (json[r'tagIds'] as List).cast<String>()
: const [],
isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
);
}
return null;
@ -105,7 +124,6 @@ class UpdateAssetDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'isFavorite',
};
}

View File

@ -0,0 +1,137 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class UpdateTagDto {
/// Returns a new [UpdateTagDto] instance.
UpdateTagDto({
this.name,
this.renameTagId,
});
///
/// 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.
///
String? name;
///
/// 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.
///
String? renameTagId;
@override
bool operator ==(Object other) => identical(this, other) || other is UpdateTagDto &&
other.name == name &&
other.renameTagId == renameTagId;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(name == null ? 0 : name!.hashCode) +
(renameTagId == null ? 0 : renameTagId!.hashCode);
@override
String toString() => 'UpdateTagDto[name=$name, renameTagId=$renameTagId]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (name != null) {
_json[r'name'] = name;
} else {
_json[r'name'] = null;
}
if (renameTagId != null) {
_json[r'renameTagId'] = renameTagId;
} else {
_json[r'renameTagId'] = null;
}
return _json;
}
/// Returns a new [UpdateTagDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UpdateTagDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "UpdateTagDto[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "UpdateTagDto[$key]" has a null value in JSON.');
});
return true;
}());
return UpdateTagDto(
name: mapValueOfType<String>(json, r'name'),
renameTagId: mapValueOfType<String>(json, r'renameTagId'),
);
}
return null;
}
static List<UpdateTagDto>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <UpdateTagDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UpdateTagDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, UpdateTagDto> mapFromJson(dynamic json) {
final map = <String, UpdateTagDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UpdateTagDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of UpdateTagDto-objects as value to a dart map
static Map<String, List<UpdateTagDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UpdateTagDto>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UpdateTagDto.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
};
}

234
mobile/openapi/lib/model/user_entity.dart generated Normal file
View File

@ -0,0 +1,234 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class UserEntity {
/// Returns a new [UserEntity] instance.
UserEntity({
required this.id,
required this.firstName,
required this.lastName,
required this.isAdmin,
required this.email,
this.password,
this.salt,
required this.oauthId,
required this.profileImagePath,
required this.shouldChangePassword,
required this.createdAt,
this.deletedAt,
this.tags = const [],
});
String id;
String firstName;
String lastName;
bool isAdmin;
String email;
///
/// 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.
///
String? password;
///
/// 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.
///
String? salt;
String oauthId;
String profileImagePath;
bool shouldChangePassword;
String createdAt;
///
/// 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.
///
DateTime? deletedAt;
List<TagEntity> tags;
@override
bool operator ==(Object other) => identical(this, other) || other is UserEntity &&
other.id == id &&
other.firstName == firstName &&
other.lastName == lastName &&
other.isAdmin == isAdmin &&
other.email == email &&
other.password == password &&
other.salt == salt &&
other.oauthId == oauthId &&
other.profileImagePath == profileImagePath &&
other.shouldChangePassword == shouldChangePassword &&
other.createdAt == createdAt &&
other.deletedAt == deletedAt &&
other.tags == tags;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(id.hashCode) +
(firstName.hashCode) +
(lastName.hashCode) +
(isAdmin.hashCode) +
(email.hashCode) +
(password == null ? 0 : password!.hashCode) +
(salt == null ? 0 : salt!.hashCode) +
(oauthId.hashCode) +
(profileImagePath.hashCode) +
(shouldChangePassword.hashCode) +
(createdAt.hashCode) +
(deletedAt == null ? 0 : deletedAt!.hashCode) +
(tags.hashCode);
@override
String toString() => 'UserEntity[id=$id, firstName=$firstName, lastName=$lastName, isAdmin=$isAdmin, email=$email, password=$password, salt=$salt, oauthId=$oauthId, profileImagePath=$profileImagePath, shouldChangePassword=$shouldChangePassword, createdAt=$createdAt, deletedAt=$deletedAt, tags=$tags]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
_json[r'id'] = id;
_json[r'firstName'] = firstName;
_json[r'lastName'] = lastName;
_json[r'isAdmin'] = isAdmin;
_json[r'email'] = email;
if (password != null) {
_json[r'password'] = password;
} else {
_json[r'password'] = null;
}
if (salt != null) {
_json[r'salt'] = salt;
} else {
_json[r'salt'] = null;
}
_json[r'oauthId'] = oauthId;
_json[r'profileImagePath'] = profileImagePath;
_json[r'shouldChangePassword'] = shouldChangePassword;
_json[r'createdAt'] = createdAt;
if (deletedAt != null) {
_json[r'deletedAt'] = deletedAt!.toUtc().toIso8601String();
} else {
_json[r'deletedAt'] = null;
}
_json[r'tags'] = tags;
return _json;
}
/// Returns a new [UserEntity] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UserEntity? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "UserEntity[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "UserEntity[$key]" has a null value in JSON.');
});
return true;
}());
return UserEntity(
id: mapValueOfType<String>(json, r'id')!,
firstName: mapValueOfType<String>(json, r'firstName')!,
lastName: mapValueOfType<String>(json, r'lastName')!,
isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
email: mapValueOfType<String>(json, r'email')!,
password: mapValueOfType<String>(json, r'password'),
salt: mapValueOfType<String>(json, r'salt'),
oauthId: mapValueOfType<String>(json, r'oauthId')!,
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
createdAt: mapValueOfType<String>(json, r'createdAt')!,
deletedAt: mapDateTime(json, r'deletedAt', ''),
tags: TagEntity.listFromJson(json[r'tags'])!,
);
}
return null;
}
static List<UserEntity>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <UserEntity>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UserEntity.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, UserEntity> mapFromJson(dynamic json) {
final map = <String, UserEntity>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UserEntity.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of UserEntity-objects as value to a dart map
static Map<String, List<UserEntity>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UserEntity>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UserEntity.listFromJson(entry.value, growable: growable,);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'id',
'firstName',
'lastName',
'isAdmin',
'email',
'oauthId',
'profileImagePath',
'shouldChangePassword',
'createdAt',
'tags',
};
}

122
mobile/openapi/test/asset_entity_test.dart generated Normal file
View File

@ -0,0 +1,122 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for AssetEntity
void main() {
// final instance = AssetEntity();
group('test AssetEntity', () {
// String id
test('to test the property `id`', () async {
// TODO
});
// String deviceAssetId
test('to test the property `deviceAssetId`', () async {
// TODO
});
// String userId
test('to test the property `userId`', () async {
// TODO
});
// String deviceId
test('to test the property `deviceId`', () async {
// TODO
});
// String type
test('to test the property `type`', () async {
// TODO
});
// String originalPath
test('to test the property `originalPath`', () async {
// TODO
});
// String resizePath
test('to test the property `resizePath`', () async {
// TODO
});
// String webpPath
test('to test the property `webpPath`', () async {
// TODO
});
// String encodedVideoPath
test('to test the property `encodedVideoPath`', () async {
// TODO
});
// String createdAt
test('to test the property `createdAt`', () async {
// TODO
});
// String modifiedAt
test('to test the property `modifiedAt`', () async {
// TODO
});
// bool isFavorite
test('to test the property `isFavorite`', () async {
// TODO
});
// String mimeType
test('to test the property `mimeType`', () async {
// TODO
});
// Object checksum
test('to test the property `checksum`', () async {
// TODO
});
// String duration
test('to test the property `duration`', () async {
// TODO
});
// bool isVisible
test('to test the property `isVisible`', () async {
// TODO
});
// String livePhotoVideoId
test('to test the property `livePhotoVideoId`', () async {
// TODO
});
// ExifEntity exifInfo
test('to test the property `exifInfo`', () async {
// TODO
});
// SmartInfoEntity smartInfo
test('to test the property `smartInfo`', () async {
// TODO
});
// List<TagEntity> tags (default value: const [])
test('to test the property `tags`', () async {
// TODO
});
});
}

View File

@ -0,0 +1,32 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for CreateTagDto
void main() {
// final instance = CreateTagDto();
group('test CreateTagDto', () {
// TagTypeEnum type
test('to test the property `type`', () async {
// TODO
});
// String name
test('to test the property `name`', () async {
// TODO
});
});
}

150
mobile/openapi/test/exif_entity_test.dart generated Normal file
View File

@ -0,0 +1,150 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for ExifEntity
void main() {
// final instance = ExifEntity();
group('test ExifEntity', () {
// String id
test('to test the property `id`', () async {
// TODO
});
// String assetId
test('to test the property `assetId`', () async {
// TODO
});
// General info
// String description
test('to test the property `description`', () async {
// TODO
});
// num exifImageWidth
test('to test the property `exifImageWidth`', () async {
// TODO
});
// num exifImageHeight
test('to test the property `exifImageHeight`', () async {
// TODO
});
// num fileSizeInByte
test('to test the property `fileSizeInByte`', () async {
// TODO
});
// String orientation
test('to test the property `orientation`', () async {
// TODO
});
// DateTime dateTimeOriginal
test('to test the property `dateTimeOriginal`', () async {
// TODO
});
// DateTime modifyDate
test('to test the property `modifyDate`', () async {
// TODO
});
// num latitude
test('to test the property `latitude`', () async {
// TODO
});
// num longitude
test('to test the property `longitude`', () async {
// TODO
});
// String city
test('to test the property `city`', () async {
// TODO
});
// String state
test('to test the property `state`', () async {
// TODO
});
// String country
test('to test the property `country`', () async {
// TODO
});
// Image info
// String make
test('to test the property `make`', () async {
// TODO
});
// String model
test('to test the property `model`', () async {
// TODO
});
// String imageName
test('to test the property `imageName`', () async {
// TODO
});
// String lensModel
test('to test the property `lensModel`', () async {
// TODO
});
// num fNumber
test('to test the property `fNumber`', () async {
// TODO
});
// num focalLength
test('to test the property `focalLength`', () async {
// TODO
});
// num iso
test('to test the property `iso`', () async {
// TODO
});
// num exposureTime
test('to test the property `exposureTime`', () async {
// TODO
});
// Video info
// num fps
test('to test the property `fps`', () async {
// TODO
});
// AssetEntity asset
test('to test the property `asset`', () async {
// TODO
});
// String exifTextSearchableColumn
test('to test the property `exifTextSearchableColumn`', () async {
// TODO
});
});
}

View File

@ -0,0 +1,47 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for SmartInfoEntity
void main() {
// final instance = SmartInfoEntity();
group('test SmartInfoEntity', () {
// String id
test('to test the property `id`', () async {
// TODO
});
// String assetId
test('to test the property `assetId`', () async {
// TODO
});
// List<String> tags (default value: const [])
test('to test the property `tags`', () async {
// TODO
});
// List<String> objects (default value: const [])
test('to test the property `objects`', () async {
// TODO
});
// AssetEntity asset
test('to test the property `asset`', () async {
// TODO
});
});
}

46
mobile/openapi/test/tag_api_test.dart generated Normal file
View File

@ -0,0 +1,46 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
/// tests for TagApi
void main() {
// final instance = TagApi();
group('tests for TagApi', () {
//Future<TagEntity> create(CreateTagDto createTagDto) async
test('test create', () async {
// TODO
});
//Future<List<TagEntity>> findAll() async
test('test findAll', () async {
// TODO
});
//Future<Object> findOne(String id) async
test('test findOne', () async {
// TODO
});
//Future<String> remove(String id) async
test('test remove', () async {
// TODO
});
//Future<String> update(String id, UpdateTagDto updateTagDto) async
test('test update', () async {
// TODO
});
});
}

52
mobile/openapi/test/tag_entity_test.dart generated Normal file
View File

@ -0,0 +1,52 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for TagEntity
void main() {
// final instance = TagEntity();
group('test TagEntity', () {
// String id
test('to test the property `id`', () async {
// TODO
});
// String type
test('to test the property `type`', () async {
// TODO
});
// String name
test('to test the property `name`', () async {
// TODO
});
// String renameTagId
test('to test the property `renameTagId`', () async {
// TODO
});
// List<AssetEntity> assets (default value: const [])
test('to test the property `assets`', () async {
// TODO
});
// UserEntity user
test('to test the property `user`', () async {
// TODO
});
});
}

View File

@ -0,0 +1,37 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for TagResponseDto
void main() {
// final instance = TagResponseDto();
group('test TagResponseDto', () {
// String id
test('to test the property `id`', () async {
// TODO
});
// TagTypeEnum type
test('to test the property `type`', () async {
// TODO
});
// String name
test('to test the property `name`', () async {
// TODO
});
});
}

View File

@ -0,0 +1,21 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for TagTypeEnum
void main() {
group('test TagTypeEnum', () {
});
}

View File

@ -0,0 +1,32 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for UpdateTagDto
void main() {
// final instance = UpdateTagDto();
group('test UpdateTagDto', () {
// String name
test('to test the property `name`', () async {
// TODO
});
// String renameTagId
test('to test the property `renameTagId`', () async {
// TODO
});
});
}

View File

@ -0,0 +1,82 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for UserEntity
void main() {
// final instance = UserEntity();
group('test UserEntity', () {
// String id
test('to test the property `id`', () async {
// TODO
});
// String firstName
test('to test the property `firstName`', () async {
// TODO
});
// String lastName
test('to test the property `lastName`', () async {
// TODO
});
// bool isAdmin
test('to test the property `isAdmin`', () async {
// TODO
});
// String email
test('to test the property `email`', () async {
// TODO
});
// String password
test('to test the property `password`', () async {
// TODO
});
// String salt
test('to test the property `salt`', () async {
// TODO
});
// String profileImagePath
test('to test the property `profileImagePath`', () async {
// TODO
});
// bool shouldChangePassword
test('to test the property `shouldChangePassword`', () async {
// TODO
});
// String createdAt
test('to test the property `createdAt`', () async {
// TODO
});
// DateTime deletedAt
test('to test the property `deletedAt`', () async {
// TODO
});
// List<TagEntity> tags (default value: const [])
test('to test the property `tags`', () async {
// TODO
});
});
}

View File

@ -1,32 +1,29 @@
import { Module } from '@nestjs/common';
import { forwardRef, Module } from '@nestjs/common';
import { AlbumService } from './album.service';
import { AlbumController } from './album.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AssetEntity } from '@app/database/entities/asset.entity';
import { UserEntity } from '@app/database/entities/user.entity';
import { AlbumEntity } from '../../../../../libs/database/src/entities/album.entity';
import { AssetAlbumEntity } from '@app/database/entities/asset-album.entity';
import { UserAlbumEntity } from '@app/database/entities/user-album.entity';
import { AlbumRepository, ALBUM_REPOSITORY } from './album-repository';
import { AssetRepository, ASSET_REPOSITORY } from '../asset/asset-repository';
import { DownloadModule } from '../../modules/download/download.module';
import { AssetModule } from '../asset/asset.module';
import { UserModule } from '../user/user.module';
const ALBUM_REPOSITORY_PROVIDER = {
provide: ALBUM_REPOSITORY,
useClass: AlbumRepository,
};
@Module({
imports: [
TypeOrmModule.forFeature([AssetEntity, UserEntity, AlbumEntity, AssetAlbumEntity, UserAlbumEntity]),
TypeOrmModule.forFeature([AlbumEntity, AssetAlbumEntity, UserAlbumEntity]),
DownloadModule,
UserModule,
forwardRef(() => AssetModule),
],
controllers: [AlbumController],
providers: [
AlbumService,
{
provide: ALBUM_REPOSITORY,
useClass: AlbumRepository,
},
{
provide: ASSET_REPOSITORY,
useClass: AssetRepository,
},
],
providers: [AlbumService, ALBUM_REPOSITORY_PROVIDER],
exports: [ALBUM_REPOSITORY_PROVIDER],
})
export class AlbumModule {}

View File

@ -1,7 +1,7 @@
import { SearchPropertiesDto } from './dto/search-properties.dto';
import { CuratedLocationsResponseDto } from './response-dto/curated-locations-response.dto';
import { AssetEntity, AssetType } from '@app/database/entities/asset.entity';
import { BadRequestException, Injectable } from '@nestjs/common';
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm/repository/Repository';
import { CreateAssetDto } from './dto/create-asset.dto';
@ -14,6 +14,7 @@ import { CheckExistingAssetsDto } from './dto/check-existing-assets.dto';
import { CheckExistingAssetsResponseDto } from './response-dto/check-existing-assets-response.dto';
import { In } from 'typeorm/find-options/operator/In';
import { UpdateAssetDto } from './dto/update-asset.dto';
import { ITagRepository, TAG_REPOSITORY } from '../tag/tag.repository';
export interface IAssetRepository {
create(
@ -25,7 +26,7 @@ export interface IAssetRepository {
checksum?: Buffer,
livePhotoAssetEntity?: AssetEntity,
): Promise<AssetEntity>;
update(asset: AssetEntity, dto: UpdateAssetDto): Promise<AssetEntity>;
update(userId: string, asset: AssetEntity, dto: UpdateAssetDto): Promise<AssetEntity>;
getAllByUserId(userId: string, skip?: number): Promise<AssetEntity[]>;
getAllByDeviceId(userId: string, deviceId: string): Promise<string[]>;
getById(assetId: string): Promise<AssetEntity>;
@ -53,6 +54,8 @@ export class AssetRepository implements IAssetRepository {
constructor(
@InjectRepository(AssetEntity)
private assetRepository: Repository<AssetEntity>,
@Inject(TAG_REPOSITORY) private _tagRepository: ITagRepository,
) {}
async getAssetWithNoSmartInfo(): Promise<AssetEntity[]> {
@ -222,7 +225,7 @@ export class AssetRepository implements IAssetRepository {
where: {
id: assetId,
},
relations: ['exifInfo'],
relations: ['exifInfo', 'tags'],
});
}
@ -237,9 +240,9 @@ export class AssetRepository implements IAssetRepository {
.andWhere('asset.resizePath is not NULL')
.andWhere('asset.isVisible = true')
.leftJoinAndSelect('asset.exifInfo', 'exifInfo')
.leftJoinAndSelect('asset.tags', 'tags')
.skip(skip || 0)
.orderBy('asset.createdAt', 'DESC');
return await query.getMany();
}
@ -286,9 +289,14 @@ export class AssetRepository implements IAssetRepository {
/**
* Update asset
*/
async update(asset: AssetEntity, dto: UpdateAssetDto): Promise<AssetEntity> {
async update(userId: string, asset: AssetEntity, dto: UpdateAssetDto): Promise<AssetEntity> {
asset.isFavorite = dto.isFavorite ?? asset.isFavorite;
if (dto.tagIds) {
const tags = await this._tagRepository.getByIds(userId, dto.tagIds);
asset.tags = tags;
}
return await this.assetRepository.save(asset);
}
@ -347,10 +355,10 @@ export class AssetRepository implements IAssetRepository {
async countByIdAndUser(assetId: string, userId: string): Promise<number> {
return await this.assetRepository.count({
where: {
id: assetId,
userId
}
where: {
id: assetId,
userId,
},
});
}
}

View File

@ -216,14 +216,14 @@ export class AssetController {
/**
* Update an asset
*/
@Put('/assetById/:assetId')
async updateAssetById(
@Put('/:assetId')
async updateAsset(
@GetAuthUser() authUser: AuthUserDto,
@Param('assetId') assetId: string,
@Body() dto: UpdateAssetDto,
@Body(ValidationPipe) dto: UpdateAssetDto,
): Promise<AssetResponseDto> {
await this.assetService.checkAssetsAccess(authUser, [assetId], true);
return await this.assetService.updateAssetById(assetId, dto);
return await this.assetService.updateAsset(authUser, assetId, dto);
}
@Delete('/')

View File

@ -1,4 +1,4 @@
import { Module } from '@nestjs/common';
import { forwardRef, Module } from '@nestjs/common';
import { AssetService } from './asset.service';
import { AssetController } from './asset.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
@ -10,18 +10,25 @@ import { CommunicationModule } from '../communication/communication.module';
import { QueueNameEnum } from '@app/job/constants/queue-name.constant';
import { AssetRepository, ASSET_REPOSITORY } from './asset-repository';
import { DownloadModule } from '../../modules/download/download.module';
import { ALBUM_REPOSITORY, AlbumRepository } from '../album/album-repository';
import { AlbumEntity } from '@app/database/entities/album.entity';
import { UserAlbumEntity } from '@app/database/entities/user-album.entity';
import { UserEntity } from '@app/database/entities/user.entity';
import { AssetAlbumEntity } from '@app/database/entities/asset-album.entity';
import { TagModule } from '../tag/tag.module';
import { AlbumModule } from '../album/album.module';
import { UserModule } from '../user/user.module';
const ASSET_REPOSITORY_PROVIDER = {
provide: ASSET_REPOSITORY,
useClass: AssetRepository,
};
@Module({
imports: [
TypeOrmModule.forFeature([AssetEntity]),
CommunicationModule,
BackgroundTaskModule,
DownloadModule,
TypeOrmModule.forFeature([AssetEntity, AlbumEntity, UserAlbumEntity, UserEntity, AssetAlbumEntity]),
UserModule,
AlbumModule,
TagModule,
forwardRef(() => AlbumModule),
BullModule.registerQueue({
name: QueueNameEnum.ASSET_UPLOADED,
defaultJobOptions: {
@ -40,18 +47,7 @@ import { AssetAlbumEntity } from '@app/database/entities/asset-album.entity';
}),
],
controllers: [AssetController],
providers: [
AssetService,
BackgroundTaskService,
{
provide: ASSET_REPOSITORY,
useClass: AssetRepository,
},
{
provide: ALBUM_REPOSITORY,
useClass: AlbumRepository,
},
],
exports: [AssetService],
providers: [AssetService, BackgroundTaskService, ASSET_REPOSITORY_PROVIDER],
exports: [ASSET_REPOSITORY_PROVIDER],
})
export class AssetModule {}

View File

@ -231,13 +231,13 @@ export class AssetService {
return mapAsset(asset);
}
public async updateAssetById(assetId: string, dto: UpdateAssetDto): Promise<AssetResponseDto> {
public async updateAsset(authUser: AuthUserDto, assetId: string, dto: UpdateAssetDto): Promise<AssetResponseDto> {
const asset = await this._assetRepository.getById(assetId);
if (!asset) {
throw new BadRequestException('Asset not found');
}
const updatedAsset = await this._assetRepository.update(asset, dto);
const updatedAsset = await this._assetRepository.update(authUser.id, asset, dto);
return mapAsset(updatedAsset);
}

View File

@ -1,6 +1,24 @@
import { IsBoolean } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { IsArray, IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator';
export class UpdateAssetDto {
@IsOptional()
@IsBoolean()
isFavorite!: boolean;
isFavorite?: boolean;
@IsOptional()
@IsArray()
@IsString({ each: true })
@IsNotEmpty({ each: true })
@ApiProperty({
isArray: true,
type: String,
title: 'Array of tag IDs to add to the asset',
example: [
'bf973405-3f2a-48d2-a687-2ed4167164be',
'dd41870b-5d00-46d2-924e-1d8489a0aa0f',
'fad77c3f-deef-4e7e-9608-14c1aa4e559a',
],
})
tagIds?: string[];
}

View File

@ -1,5 +1,6 @@
import { AssetEntity, AssetType } from '@app/database/entities/asset.entity';
import { ApiProperty } from '@nestjs/swagger';
import { mapTag, TagResponseDto } from '../../tag/response-dto/tag-response.dto';
import { ExifResponseDto, mapExif } from './exif-response.dto';
import { SmartInfoResponseDto, mapSmartInfo } from './smart-info-response.dto';
@ -23,6 +24,7 @@ export class AssetResponseDto {
exifInfo?: ExifResponseDto;
smartInfo?: SmartInfoResponseDto;
livePhotoVideoId?: string | null;
tags!: TagResponseDto[];
}
export function mapAsset(entity: AssetEntity): AssetResponseDto {
@ -44,5 +46,6 @@ export function mapAsset(entity: AssetEntity): AssetResponseDto {
exifInfo: entity.exifInfo ? mapExif(entity.exifInfo) : undefined,
smartInfo: entity.smartInfo ? mapSmartInfo(entity.smartInfo) : undefined,
livePhotoVideoId: entity.livePhotoVideoId,
tags: entity.tags?.map(mapTag),
};
}

View File

@ -5,18 +5,21 @@ import { ImmichJwtService } from '../../modules/immich-jwt/immich-jwt.service';
import { ImmichJwtModule } from '../../modules/immich-jwt/immich-jwt.module';
import { JwtModule } from '@nestjs/jwt';
import { jwtConfig } from '../../config/jwt.config';
import { UserEntity } from '@app/database/entities/user.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
import { BullModule } from '@nestjs/bull';
import { QueueNameEnum } from '@app/job';
import { AssetEntity } from '@app/database/entities/asset.entity';
import { ExifEntity } from '@app/database/entities/exif.entity';
import { AssetRepository, ASSET_REPOSITORY } from '../asset/asset-repository';
import { TagModule } from '../tag/tag.module';
import { AssetModule } from '../asset/asset.module';
import { UserModule } from '../user/user.module';
@Module({
imports: [
TypeOrmModule.forFeature([UserEntity, AssetEntity, ExifEntity]),
TypeOrmModule.forFeature([ExifEntity]),
ImmichJwtModule,
TagModule,
AssetModule,
UserModule,
JwtModule.register(jwtConfig),
BullModule.registerQueue(
{
@ -70,13 +73,6 @@ import { AssetRepository, ASSET_REPOSITORY } from '../asset/asset-repository';
),
],
controllers: [JobController],
providers: [
JobService,
ImmichJwtService,
{
provide: ASSET_REPOSITORY,
useClass: AssetRepository,
},
],
providers: [JobService, ImmichJwtService],
})
export class JobModule {}

View File

@ -0,0 +1,14 @@
import { TagType } from '@app/database/entities/tag.entity';
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
export class CreateTagDto {
@IsString()
@IsNotEmpty()
name!: string;
@IsEnum(TagType)
@IsNotEmpty()
@ApiProperty({ enumName: 'TagTypeEnum', enum: TagType })
type!: TagType;
}

View File

@ -0,0 +1,11 @@
import { IsOptional, IsString } from 'class-validator';
export class UpdateTagDto {
@IsString()
@IsOptional()
name?: string;
@IsString()
@IsOptional()
renameTagId?: string;
}

View File

@ -0,0 +1,20 @@
import { TagEntity, TagType } from '@app/database/entities/tag.entity';
import { ApiProperty } from '@nestjs/swagger';
export class TagResponseDto {
@ApiProperty()
id!: string;
@ApiProperty({ enumName: 'TagTypeEnum', enum: TagType })
type!: string;
name!: string;
}
export function mapTag(entity: TagEntity): TagResponseDto {
return {
id: entity.id,
type: entity.type,
name: entity.name,
};
}

View File

@ -0,0 +1,44 @@
import { Controller, Get, Post, Body, Patch, Param, Delete, ValidationPipe } from '@nestjs/common';
import { TagService } from './tag.service';
import { CreateTagDto } from './dto/create-tag.dto';
import { UpdateTagDto } from './dto/update-tag.dto';
import { Authenticated } from '../../decorators/authenticated.decorator';
import { ApiTags } from '@nestjs/swagger';
import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
import { TagEntity } from '@app/database/entities/tag.entity';
@Authenticated()
@ApiTags('Tag')
@Controller('tag')
export class TagController {
constructor(private readonly tagService: TagService) {}
@Post()
create(@GetAuthUser() authUser: AuthUserDto, @Body(ValidationPipe) createTagDto: CreateTagDto): Promise<TagEntity> {
return this.tagService.create(authUser, createTagDto);
}
@Get()
findAll(@GetAuthUser() authUser: AuthUserDto) {
return this.tagService.findAll(authUser);
}
@Get(':id')
findOne(@GetAuthUser() authUser: AuthUserDto, @Param('id') id: string) {
return this.tagService.findOne(authUser, id);
}
@Patch(':id')
update(
@GetAuthUser() authUser: AuthUserDto,
@Param('id') id: string,
@Body(ValidationPipe) updateTagDto: UpdateTagDto,
) {
return this.tagService.update(authUser, id, updateTagDto);
}
@Delete(':id')
delete(@GetAuthUser() authUser: AuthUserDto, @Param('id') id: string) {
return this.tagService.remove(authUser, id);
}
}

View File

@ -0,0 +1,18 @@
import { Module } from '@nestjs/common';
import { TagService } from './tag.service';
import { TagController } from './tag.controller';
import { TagEntity } from '@app/database/entities/tag.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TagRepository, TAG_REPOSITORY } from './tag.repository';
const TAG_REPOSITORY_PROVIDER = {
provide: TAG_REPOSITORY,
useClass: TagRepository,
};
@Module({
imports: [TypeOrmModule.forFeature([TagEntity])],
controllers: [TagController],
providers: [TagService, TAG_REPOSITORY_PROVIDER],
exports: [TAG_REPOSITORY_PROVIDER],
})
export class TagModule {}

View File

@ -0,0 +1,61 @@
import { TagEntity, TagType } from '@app/database/entities/tag.entity';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { UpdateTagDto } from './dto/update-tag.dto';
export interface ITagRepository {
create(userId: string, tagType: TagType, tagName: string): Promise<TagEntity>;
getByIds(userId: string, tagIds: string[]): Promise<TagEntity[]>;
getById(tagId: string, userId: string): Promise<TagEntity | null>;
getByUserId(userId: string): Promise<TagEntity[]>;
update(tag: TagEntity, updateTagDto: UpdateTagDto): Promise<TagEntity | null>;
remove(tag: TagEntity): Promise<TagEntity>;
}
export const TAG_REPOSITORY = 'TAG_REPOSITORY';
@Injectable()
export class TagRepository implements ITagRepository {
constructor(
@InjectRepository(TagEntity)
private tagRepository: Repository<TagEntity>,
) {}
async create(userId: string, tagType: TagType, tagName: string): Promise<TagEntity> {
const tag = new TagEntity();
tag.name = tagName;
tag.type = tagType;
tag.userId = userId;
return this.tagRepository.save(tag);
}
async getById(tagId: string, userId: string): Promise<TagEntity | null> {
return await this.tagRepository.findOne({ where: { id: tagId, userId }, relations: ['user'] });
}
async getByIds(userId: string, tagIds: string[]): Promise<TagEntity[]> {
return await this.tagRepository.find({
where: { id: In(tagIds), userId },
relations: {
user: true,
},
});
}
async getByUserId(userId: string): Promise<TagEntity[]> {
return await this.tagRepository.find({ where: { userId } });
}
async update(tag: TagEntity, updateTagDto: UpdateTagDto): Promise<TagEntity> {
tag.name = updateTagDto.name ?? tag.name;
tag.renameTagId = updateTagDto.renameTagId ?? tag.renameTagId;
return this.tagRepository.save(tag);
}
async remove(tag: TagEntity): Promise<TagEntity> {
return await this.tagRepository.remove(tag);
}
}

View File

@ -0,0 +1,91 @@
import { TagEntity, TagType } from '@app/database/entities/tag.entity';
import { UserEntity } from '@app/database/entities/user.entity';
import { AuthUserDto } from '../../decorators/auth-user.decorator';
import { ITagRepository } from './tag.repository';
import { TagService } from './tag.service';
describe('TagService', () => {
let sut: TagService;
let tagRepositoryMock: jest.Mocked<ITagRepository>;
const user1AuthUser: AuthUserDto = Object.freeze({
id: '1111',
email: 'testuser@email.com',
});
const user1: UserEntity = Object.freeze({
id: '1111',
firstName: 'Alex',
lastName: 'Tran',
isAdmin: true,
email: 'testuser@email.com',
profileImagePath: '',
shouldChangePassword: true,
createdAt: '2022-12-02T19:29:23.603Z',
deletedAt: undefined,
tags: [],
oauthId: 'oauth-id-1',
});
// const user2: UserEntity = Object.freeze({
// id: '2222',
// firstName: 'Alex',
// lastName: 'Tran',
// isAdmin: true,
// email: 'testuser2@email.com',
// profileImagePath: '',
// shouldChangePassword: true,
// createdAt: '2022-12-02T19:29:23.603Z',
// deletedAt: undefined,
// tags: [],
// oauthId: 'oauth-id-2',
// });
const user1Tag1: TagEntity = Object.freeze({
name: 'user 1 tag 1',
type: TagType.CUSTOM,
userId: user1.id,
user: user1,
renameTagId: '',
id: 'user1-tag-1-id',
assets: [],
});
// const user1Tag2: TagEntity = Object.freeze({
// name: 'user 1 tag 2',
// type: TagType.CUSTOM,
// userId: user1.id,
// user: user1,
// renameTagId: '',
// id: 'user1-tag-2-id',
// assets: [],
// });
beforeAll(() => {
tagRepositoryMock = {
create: jest.fn(),
getByIds: jest.fn(),
getById: jest.fn(),
getByUserId: jest.fn(),
remove: jest.fn(),
update: jest.fn(),
};
sut = new TagService(tagRepositoryMock);
});
it('creates tag', async () => {
const createTagDto = {
name: 'user 1 tag 1',
type: TagType.CUSTOM,
};
tagRepositoryMock.create.mockResolvedValue(user1Tag1);
const result = await sut.create(user1AuthUser, createTagDto);
expect(result.userId).toEqual(user1AuthUser.id);
expect(result.name).toEqual(createTagDto.name);
expect(result.type).toEqual(createTagDto.type);
});
});

View File

@ -0,0 +1,48 @@
import { TagEntity } from '@app/database/entities/tag.entity';
import { BadRequestException, Inject, Injectable, Logger } from '@nestjs/common';
import { AuthUserDto } from '../../decorators/auth-user.decorator';
import { CreateTagDto } from './dto/create-tag.dto';
import { UpdateTagDto } from './dto/update-tag.dto';
import { ITagRepository, TAG_REPOSITORY } from './tag.repository';
@Injectable()
export class TagService {
readonly logger = new Logger(TagService.name);
constructor(@Inject(TAG_REPOSITORY) private _tagRepository: ITagRepository) {}
async create(authUser: AuthUserDto, createTagDto: CreateTagDto) {
try {
return await this._tagRepository.create(authUser.id, createTagDto.type, createTagDto.name);
} catch (e: any) {
this.logger.error(e, e.stack);
throw new BadRequestException(`Failed to create tag: ${e.detail}`);
}
}
async findAll(authUser: AuthUserDto) {
return await this._tagRepository.getByUserId(authUser.id);
}
async findOne(authUser: AuthUserDto, id: string): Promise<TagEntity> {
const tag = await this._tagRepository.getById(id, authUser.id);
if (!tag) {
throw new BadRequestException('Tag not found');
}
return tag;
}
async update(authUser: AuthUserDto, id: string, updateTagDto: UpdateTagDto) {
const tag = await this.findOne(authUser, id);
return this._tagRepository.update(tag, updateTagDto);
}
async remove(authUser: AuthUserDto, id: string) {
const tag = await this.findOne(authUser, id);
return this._tagRepository.remove(tag);
}
}

View File

@ -31,6 +31,7 @@ describe('UserService', () => {
shouldChangePassword: false,
profileImagePath: '',
createdAt: '2021-01-01',
tags: [],
});
const immichUser: UserEntity = Object.freeze({
@ -45,6 +46,7 @@ describe('UserService', () => {
shouldChangePassword: false,
profileImagePath: '',
createdAt: '2021-01-01',
tags: [],
});
const updatedImmichUser: UserEntity = Object.freeze({
@ -59,6 +61,7 @@ describe('UserService', () => {
shouldChangePassword: true,
profileImagePath: '',
createdAt: '2021-01-01',
tags: [],
});
beforeAll(() => {

View File

@ -18,6 +18,7 @@ import { DatabaseModule } from '@app/database';
import { JobModule } from './api-v1/job/job.module';
import { SystemConfigModule } from './api-v1/system-config/system-config.module';
import { OAuthModule } from './api-v1/oauth/oauth.module';
import { TagModule } from './api-v1/tag/tag.module';
@Module({
imports: [
@ -63,6 +64,8 @@ import { OAuthModule } from './api-v1/oauth/oauth.module';
JobModule,
SystemConfigModule,
TagModule,
],
controllers: [AppController],
providers: [],

View File

@ -55,7 +55,7 @@ async function bootstrap() {
if (process.env.NODE_ENV == 'development') {
// Generate API Documentation only in development mode
const outputPath = path.resolve(process.cwd(), 'immich-openapi-specs.json');
writeFileSync(outputPath, JSON.stringify(apiDocument), { encoding: 'utf8' });
writeFileSync(outputPath, JSON.stringify(apiDocument, null, 2), { encoding: 'utf8' });
Logger.log(
`Running Immich Server in DEVELOPMENT environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
'ImmichServer',

View File

@ -56,6 +56,7 @@ describe('ImmichJwtService', () => {
profileImagePath: '',
shouldChangePassword: false,
createdAt: 'today',
tags: [],
};
const dto: LoginResponseDto = {

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,7 @@
import { Column, Entity, Index, OneToOne, PrimaryGeneratedColumn, Unique } from 'typeorm';
import { Column, Entity, Index, JoinTable, ManyToMany, OneToOne, PrimaryGeneratedColumn, Unique } from 'typeorm';
import { ExifEntity } from './exif.entity';
import { SmartInfoEntity } from './smart-info.entity';
import { TagEntity } from './tag.entity';
@Entity('assets')
@Unique('UQ_userid_checksum', ['userId', 'checksum'])
@ -62,6 +63,11 @@ export class AssetEntity {
@OneToOne(() => SmartInfoEntity, (smartInfoEntity) => smartInfoEntity.asset)
smartInfo?: SmartInfoEntity;
// https://github.com/typeorm/typeorm/blob/master/docs/many-to-many-relations.md
@ManyToMany(() => TagEntity, (tag) => tag.assets, { cascade: true })
@JoinTable({ name: 'tag_asset' })
tags!: TagEntity[];
}
export enum AssetType {

View File

@ -0,0 +1,45 @@
import { Column, Entity, ManyToMany, ManyToOne, PrimaryGeneratedColumn, Unique } from 'typeorm';
import { AssetEntity } from './asset.entity';
import { UserEntity } from './user.entity';
@Entity('tags')
@Unique('UQ_tag_name_userId', ['name', 'userId'])
export class TagEntity {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column()
type!: TagType;
@Column()
name!: string;
@Column()
userId!: string;
@Column({ type: 'uuid', comment: 'The new renamed tagId', nullable: true })
renameTagId!: string;
@ManyToMany(() => AssetEntity, (asset) => asset.tags)
assets!: AssetEntity[];
@ManyToOne(() => UserEntity, (user) => user.tags)
user!: UserEntity;
}
export enum TagType {
/**
* Tag that is detected by the ML model for object detection will use this type
*/
OBJECT = 'OBJECT',
/**
* Face that is detected by the ML model for facial detection (TBD/NOT YET IMPLEMENTED) will use this type
*/
FACE = 'FACE',
/**
* Tag that is created by the user will use this type
*/
CUSTOM = 'CUSTOM',
}

View File

@ -1,4 +1,5 @@
import { Column, CreateDateColumn, DeleteDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { Column, CreateDateColumn, DeleteDateColumn, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { TagEntity } from './tag.entity';
@Entity('users')
export class UserEntity {
@ -37,4 +38,7 @@ export class UserEntity {
@DeleteDateColumn()
deletedAt?: Date;
@OneToMany(() => TagEntity, (tag) => tag.user)
tags!: TagEntity[];
}

View File

@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class CreateTagsTable1670257571385 implements MigrationInterface {
name = 'CreateTagsTable1670257571385'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "tags" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" character varying NOT NULL, "name" character varying NOT NULL, "userId" uuid NOT NULL, "renameTagId" uuid, CONSTRAINT "UQ_tag_name_userId" UNIQUE ("name", "userId"), CONSTRAINT "PK_e7dc17249a1148a1970748eda99" PRIMARY KEY ("id")); COMMENT ON COLUMN "tags"."renameTagId" IS 'The new renamed tagId'`);
await queryRunner.query(`CREATE TABLE "tag_asset" ("assetsId" uuid NOT NULL, "tagsId" uuid NOT NULL, CONSTRAINT "PK_ef5346fe522b5fb3bc96454747e" PRIMARY KEY ("assetsId", "tagsId"))`);
await queryRunner.query(`CREATE INDEX "IDX_f8e8a9e893cb5c54907f1b798e" ON "tag_asset" ("assetsId") `);
await queryRunner.query(`CREATE INDEX "IDX_e99f31ea4cdf3a2c35c7287eb4" ON "tag_asset" ("tagsId") `);
await queryRunner.query(`ALTER TABLE "tags" ADD CONSTRAINT "FK_92e67dc508c705dd66c94615576" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "tag_asset" ADD CONSTRAINT "FK_f8e8a9e893cb5c54907f1b798e9" FOREIGN KEY ("assetsId") REFERENCES "assets"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "tag_asset" ADD CONSTRAINT "FK_e99f31ea4cdf3a2c35c7287eb42" FOREIGN KEY ("tagsId") REFERENCES "tags"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "tag_asset" DROP CONSTRAINT "FK_e99f31ea4cdf3a2c35c7287eb42"`);
await queryRunner.query(`ALTER TABLE "tag_asset" DROP CONSTRAINT "FK_f8e8a9e893cb5c54907f1b798e9"`);
await queryRunner.query(`ALTER TABLE "tags" DROP CONSTRAINT "FK_92e67dc508c705dd66c94615576"`);
await queryRunner.query(`DROP INDEX "public"."IDX_e99f31ea4cdf3a2c35c7287eb4"`);
await queryRunner.query(`DROP INDEX "public"."IDX_f8e8a9e893cb5c54907f1b798e"`);
await queryRunner.query(`DROP TABLE "tag_asset"`);
await queryRunner.query(`DROP TABLE "tags"`);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -183,7 +183,7 @@
};
const toggleFavorite = async () => {
const { data } = await api.assetApi.updateAssetById(asset.id, {
const { data } = await api.assetApi.updateAsset(asset.id, {
isFavorite: !asset.isFavorite
});

View File

@ -62,7 +62,9 @@
style={`width: ${getStorageUsagePercentage()}%`}
/>
</div>
<p class="text-xs">{asByteUnitString(serverInfo?.diskUseRaw)} of {asByteUnitString(serverInfo?.diskSizeRaw)} used</p>
<p class="text-xs">
{asByteUnitString(serverInfo?.diskUseRaw)} of {asByteUnitString(serverInfo?.diskSizeRaw)} used
</p>
{:else}
<div class="mt-2">
<LoadingSpinner />

View File

@ -115,9 +115,7 @@
<input
disabled
class="bg-gray-100 border w-full p-1 rounded-md text-[10px] px-2"
value={`[${getBytesWithUnit(uploadAsset.file.size)}] ${
uploadAsset.file.name
}`}
value={`[${getBytesWithUnit(uploadAsset.file.size)}] ${uploadAsset.file.name}`}
/>
<div class="w-full bg-gray-300 h-[15px] rounded-md mt-[5px] text-white relative">