Add API endpoint that returns only assets with location information (Thanks @EPP100)
This commit is contained in:
parent
9a1e8e55f5
commit
1b1d2f0ba4
23 changed files with 727 additions and 23 deletions
3
mobile/openapi/.openapi-generator/FILES
generated
3
mobile/openapi/.openapi-generator/FILES
generated
|
@ -55,6 +55,7 @@ doc/JobStatusDto.md
|
|||
doc/LoginCredentialDto.md
|
||||
doc/LoginResponseDto.md
|
||||
doc/LogoutResponseDto.md
|
||||
doc/MapMarkerResponseDto.md
|
||||
doc/OAuthApi.md
|
||||
doc/OAuthCallbackDto.md
|
||||
doc/OAuthConfigDto.md
|
||||
|
@ -171,6 +172,7 @@ lib/model/job_status_dto.dart
|
|||
lib/model/login_credential_dto.dart
|
||||
lib/model/login_response_dto.dart
|
||||
lib/model/logout_response_dto.dart
|
||||
lib/model/map_marker_response_dto.dart
|
||||
lib/model/o_auth_callback_dto.dart
|
||||
lib/model/o_auth_config_dto.dart
|
||||
lib/model/o_auth_config_response_dto.dart
|
||||
|
@ -264,6 +266,7 @@ test/job_status_dto_test.dart
|
|||
test/login_credential_dto_test.dart
|
||||
test/login_response_dto_test.dart
|
||||
test/logout_response_dto_test.dart
|
||||
test/map_marker_response_dto_test.dart
|
||||
test/o_auth_api_test.dart
|
||||
test/o_auth_callback_dto_test.dart
|
||||
test/o_auth_config_dto_test.dart
|
||||
|
|
2
mobile/openapi/README.md
generated
2
mobile/openapi/README.md
generated
|
@ -103,6 +103,7 @@ Class | Method | HTTP request | Description
|
|||
*AssetApi* | [**getAssetThumbnail**](doc//AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{assetId} |
|
||||
*AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
|
||||
*AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
|
||||
*AssetApi* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/mapMarker |
|
||||
*AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |
|
||||
*AssetApi* | [**removeAssetsFromSharedLink**](doc//AssetApi.md#removeassetsfromsharedlink) | **PATCH** /asset/shared-link/remove |
|
||||
*AssetApi* | [**searchAsset**](doc//AssetApi.md#searchasset) | **POST** /asset/search |
|
||||
|
@ -205,6 +206,7 @@ Class | Method | HTTP request | Description
|
|||
- [LoginCredentialDto](doc//LoginCredentialDto.md)
|
||||
- [LoginResponseDto](doc//LoginResponseDto.md)
|
||||
- [LogoutResponseDto](doc//LogoutResponseDto.md)
|
||||
- [MapMarkerResponseDto](doc//MapMarkerResponseDto.md)
|
||||
- [OAuthCallbackDto](doc//OAuthCallbackDto.md)
|
||||
- [OAuthConfigDto](doc//OAuthConfigDto.md)
|
||||
- [OAuthConfigResponseDto](doc//OAuthConfigResponseDto.md)
|
||||
|
|
58
mobile/openapi/doc/AssetApi.md
generated
58
mobile/openapi/doc/AssetApi.md
generated
|
@ -27,6 +27,7 @@ Method | HTTP request | Description
|
|||
[**getAssetThumbnail**](AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{assetId} |
|
||||
[**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
|
||||
[**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
|
||||
[**getMapMarkers**](AssetApi.md#getmapmarkers) | **GET** /asset/mapMarker |
|
||||
[**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |
|
||||
[**removeAssetsFromSharedLink**](AssetApi.md#removeassetsfromsharedlink) | **PATCH** /asset/shared-link/remove |
|
||||
[**searchAsset**](AssetApi.md#searchasset) | **POST** /asset/search |
|
||||
|
@ -967,6 +968,63 @@ This endpoint does not need any parameter.
|
|||
|
||||
[[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)
|
||||
|
||||
# **getMapMarkers**
|
||||
> List<MapMarkerResponseDto> getMapMarkers(isFavorite, isArchived, skip)
|
||||
|
||||
|
||||
|
||||
Get all assets that have GPS information embedded
|
||||
|
||||
### Example
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
// TODO Configure API key authorization: cookie
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
|
||||
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
|
||||
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
|
||||
// TODO Configure HTTP Bearer authorization: bearer
|
||||
// Case 1. Use String Token
|
||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
|
||||
// Case 2. Use Function which generate token.
|
||||
// String yourTokenGeneratorFunction() { ... }
|
||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
|
||||
|
||||
final api_instance = AssetApi();
|
||||
final isFavorite = true; // bool |
|
||||
final isArchived = true; // bool |
|
||||
final skip = 8.14; // num |
|
||||
|
||||
try {
|
||||
final result = api_instance.getMapMarkers(isFavorite, isArchived, skip);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling AssetApi->getMapMarkers: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**isFavorite** | **bool**| | [optional]
|
||||
**isArchived** | **bool**| | [optional]
|
||||
**skip** | **num**| | [optional]
|
||||
|
||||
### Return type
|
||||
|
||||
[**List<MapMarkerResponseDto>**](MapMarkerResponseDto.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
[cookie](../README.md#cookie), [bearer](../README.md#bearer)
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **getUserAssetsByDeviceId**
|
||||
> List<String> getUserAssetsByDeviceId(deviceId)
|
||||
|
||||
|
|
18
mobile/openapi/doc/MapMarkerResponseDto.md
generated
Normal file
18
mobile/openapi/doc/MapMarkerResponseDto.md
generated
Normal file
|
@ -0,0 +1,18 @@
|
|||
# openapi.model.MapMarkerResponseDto
|
||||
|
||||
## Load the model package
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
```
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**id** | **String** | |
|
||||
**type** | **String** | |
|
||||
**lat** | **num** | |
|
||||
**lon** | **num** | |
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
1
mobile/openapi/lib/api.dart
generated
1
mobile/openapi/lib/api.dart
generated
|
@ -88,6 +88,7 @@ part 'model/job_status_dto.dart';
|
|||
part 'model/login_credential_dto.dart';
|
||||
part 'model/login_response_dto.dart';
|
||||
part 'model/logout_response_dto.dart';
|
||||
part 'model/map_marker_response_dto.dart';
|
||||
part 'model/o_auth_callback_dto.dart';
|
||||
part 'model/o_auth_config_dto.dart';
|
||||
part 'model/o_auth_config_response_dto.dart';
|
||||
|
|
73
mobile/openapi/lib/api/asset_api.dart
generated
73
mobile/openapi/lib/api/asset_api.dart
generated
|
@ -979,6 +979,79 @@ class AssetApi {
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Get all assets that have GPS information embedded
|
||||
///
|
||||
/// Note: This method returns the HTTP [Response].
|
||||
///
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [bool] isFavorite:
|
||||
///
|
||||
/// * [bool] isArchived:
|
||||
///
|
||||
/// * [num] skip:
|
||||
Future<Response> getMapMarkersWithHttpInfo({ bool? isFavorite, bool? isArchived, num? skip, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset/mapMarker';
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
if (isFavorite != null) {
|
||||
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
|
||||
}
|
||||
if (isArchived != null) {
|
||||
queryParams.addAll(_queryParams('', 'isArchived', isArchived));
|
||||
}
|
||||
if (skip != null) {
|
||||
queryParams.addAll(_queryParams('', 'skip', skip));
|
||||
}
|
||||
|
||||
const contentTypes = <String>[];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'GET',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Get all assets that have GPS information embedded
|
||||
///
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [bool] isFavorite:
|
||||
///
|
||||
/// * [bool] isArchived:
|
||||
///
|
||||
/// * [num] skip:
|
||||
Future<List<MapMarkerResponseDto>?> getMapMarkers({ bool? isFavorite, bool? isArchived, num? skip, }) async {
|
||||
final response = await getMapMarkersWithHttpInfo( isFavorite: isFavorite, isArchived: isArchived, skip: skip, );
|
||||
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<MapMarkerResponseDto>') as List)
|
||||
.cast<MapMarkerResponseDto>()
|
||||
.toList();
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Get all asset of a device that are in the database, ID only.
|
||||
///
|
||||
/// Note: This method returns the HTTP [Response].
|
||||
|
|
2
mobile/openapi/lib/api_client.dart
generated
2
mobile/openapi/lib/api_client.dart
generated
|
@ -275,6 +275,8 @@ class ApiClient {
|
|||
return LoginResponseDto.fromJson(value);
|
||||
case 'LogoutResponseDto':
|
||||
return LogoutResponseDto.fromJson(value);
|
||||
case 'MapMarkerResponseDto':
|
||||
return MapMarkerResponseDto.fromJson(value);
|
||||
case 'OAuthCallbackDto':
|
||||
return OAuthCallbackDto.fromJson(value);
|
||||
case 'OAuthConfigDto':
|
||||
|
|
219
mobile/openapi/lib/model/map_marker_response_dto.dart
generated
Normal file
219
mobile/openapi/lib/model/map_marker_response_dto.dart
generated
Normal file
|
@ -0,0 +1,219 @@
|
|||
//
|
||||
// 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 MapMarkerResponseDto {
|
||||
/// Returns a new [MapMarkerResponseDto] instance.
|
||||
MapMarkerResponseDto({
|
||||
required this.id,
|
||||
required this.type,
|
||||
required this.lat,
|
||||
required this.lon,
|
||||
});
|
||||
|
||||
String id;
|
||||
|
||||
MapMarkerResponseDtoTypeEnum type;
|
||||
|
||||
num lat;
|
||||
|
||||
num lon;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is MapMarkerResponseDto &&
|
||||
other.id == id &&
|
||||
other.type == type &&
|
||||
other.lat == lat &&
|
||||
other.lon == lon;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(id.hashCode) +
|
||||
(type.hashCode) +
|
||||
(lat.hashCode) +
|
||||
(lon.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'MapMarkerResponseDto[id=$id, type=$type, lat=$lat, lon=$lon]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'id'] = this.id;
|
||||
json[r'type'] = this.type;
|
||||
json[r'lat'] = this.lat;
|
||||
json[r'lon'] = this.lon;
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Returns a new [MapMarkerResponseDto] instance and imports its values from
|
||||
/// [value] if it's a [Map], null otherwise.
|
||||
// ignore: prefer_constructors_over_static_methods
|
||||
static MapMarkerResponseDto? 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 "MapMarkerResponseDto[$key]" is missing from JSON.');
|
||||
assert(json[key] != null, 'Required key "MapMarkerResponseDto[$key]" has a null value in JSON.');
|
||||
});
|
||||
return true;
|
||||
}());
|
||||
|
||||
return MapMarkerResponseDto(
|
||||
id: mapValueOfType<String>(json, r'id')!,
|
||||
type: MapMarkerResponseDtoTypeEnum.fromJson(json[r'type'])!,
|
||||
lat: json[r'lat'] == null
|
||||
? null
|
||||
: num.parse(json[r'lat'].toString()),
|
||||
lon: json[r'lon'] == null
|
||||
? null
|
||||
: num.parse(json[r'lon'].toString()),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<MapMarkerResponseDto>? listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <MapMarkerResponseDto>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = MapMarkerResponseDto.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
|
||||
static Map<String, MapMarkerResponseDto> mapFromJson(dynamic json) {
|
||||
final map = <String, MapMarkerResponseDto>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = MapMarkerResponseDto.fromJson(entry.value);
|
||||
if (value != null) {
|
||||
map[entry.key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// maps a json object with a list of MapMarkerResponseDto-objects as value to a dart map
|
||||
static Map<String, List<MapMarkerResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||
final map = <String, List<MapMarkerResponseDto>>{};
|
||||
if (json is Map && json.isNotEmpty) {
|
||||
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||
for (final entry in json.entries) {
|
||||
final value = MapMarkerResponseDto.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',
|
||||
'lat',
|
||||
'lon',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class MapMarkerResponseDtoTypeEnum {
|
||||
/// Instantiate a new enum with the provided [value].
|
||||
const MapMarkerResponseDtoTypeEnum._(this.value);
|
||||
|
||||
/// The underlying value of this enum member.
|
||||
final String value;
|
||||
|
||||
@override
|
||||
String toString() => value;
|
||||
|
||||
String toJson() => value;
|
||||
|
||||
static const IMAGE = MapMarkerResponseDtoTypeEnum._(r'IMAGE');
|
||||
static const VIDEO = MapMarkerResponseDtoTypeEnum._(r'VIDEO');
|
||||
static const AUDIO = MapMarkerResponseDtoTypeEnum._(r'AUDIO');
|
||||
static const OTHER = MapMarkerResponseDtoTypeEnum._(r'OTHER');
|
||||
|
||||
/// List of all possible values in this [enum][MapMarkerResponseDtoTypeEnum].
|
||||
static const values = <MapMarkerResponseDtoTypeEnum>[
|
||||
IMAGE,
|
||||
VIDEO,
|
||||
AUDIO,
|
||||
OTHER,
|
||||
];
|
||||
|
||||
static MapMarkerResponseDtoTypeEnum? fromJson(dynamic value) => MapMarkerResponseDtoTypeEnumTypeTransformer().decode(value);
|
||||
|
||||
static List<MapMarkerResponseDtoTypeEnum>? listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <MapMarkerResponseDtoTypeEnum>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = MapMarkerResponseDtoTypeEnum.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
}
|
||||
|
||||
/// Transformation class that can [encode] an instance of [MapMarkerResponseDtoTypeEnum] to String,
|
||||
/// and [decode] dynamic data back to [MapMarkerResponseDtoTypeEnum].
|
||||
class MapMarkerResponseDtoTypeEnumTypeTransformer {
|
||||
factory MapMarkerResponseDtoTypeEnumTypeTransformer() => _instance ??= const MapMarkerResponseDtoTypeEnumTypeTransformer._();
|
||||
|
||||
const MapMarkerResponseDtoTypeEnumTypeTransformer._();
|
||||
|
||||
String encode(MapMarkerResponseDtoTypeEnum data) => data.value;
|
||||
|
||||
/// Decodes a [dynamic value][data] to a MapMarkerResponseDtoTypeEnum.
|
||||
///
|
||||
/// 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.
|
||||
MapMarkerResponseDtoTypeEnum? decode(dynamic data, {bool allowNull = true}) {
|
||||
if (data != null) {
|
||||
switch (data) {
|
||||
case r'IMAGE': return MapMarkerResponseDtoTypeEnum.IMAGE;
|
||||
case r'VIDEO': return MapMarkerResponseDtoTypeEnum.VIDEO;
|
||||
case r'AUDIO': return MapMarkerResponseDtoTypeEnum.AUDIO;
|
||||
case r'OTHER': return MapMarkerResponseDtoTypeEnum.OTHER;
|
||||
default:
|
||||
if (!allowNull) {
|
||||
throw ArgumentError('Unknown enum value to decode: $data');
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Singleton [MapMarkerResponseDtoTypeEnumTypeTransformer] instance.
|
||||
static MapMarkerResponseDtoTypeEnumTypeTransformer? _instance;
|
||||
}
|
||||
|
||||
|
7
mobile/openapi/test/asset_api_test.dart
generated
7
mobile/openapi/test/asset_api_test.dart
generated
|
@ -117,6 +117,13 @@ void main() {
|
|||
// TODO
|
||||
});
|
||||
|
||||
// Get all assets that have GPS information embedded
|
||||
//
|
||||
//Future<List<MapMarkerResponseDto>> getMapMarkers({ bool isFavorite, bool isArchived, num skip }) async
|
||||
test('test getMapMarkers', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// Get all asset of a device that are in the database, ID only.
|
||||
//
|
||||
//Future<List<String>> getUserAssetsByDeviceId(String deviceId) async
|
||||
|
|
42
mobile/openapi/test/map_marker_response_dto_test.dart
generated
Normal file
42
mobile/openapi/test/map_marker_response_dto_test.dart
generated
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// 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 MapMarkerResponseDto
|
||||
void main() {
|
||||
// final instance = MapMarkerResponseDto();
|
||||
|
||||
group('test MapMarkerResponseDto', () {
|
||||
// String id
|
||||
test('to test the property `id`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// String type
|
||||
test('to test the property `type`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// num lat
|
||||
test('to test the property `lat`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// num lon
|
||||
test('to test the property `lon`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
|
@ -31,7 +31,7 @@ import { CheckDuplicateAssetDto } from './dto/check-duplicate-asset.dto';
|
|||
import { ApiBody, ApiConsumes, ApiHeader, ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { CuratedObjectsResponseDto } from './response-dto/curated-objects-response.dto';
|
||||
import { CuratedLocationsResponseDto } from './response-dto/curated-locations-response.dto';
|
||||
import { AssetResponseDto, ImmichReadStream } from '@app/domain';
|
||||
import { AssetResponseDto, ImmichReadStream, MapMarkerResponseDto } from '@app/domain';
|
||||
import { CheckDuplicateAssetResponseDto } from './response-dto/check-duplicate-asset-response.dto';
|
||||
import { CreateAssetDto, mapToUploadFile } from './dto/create-asset.dto';
|
||||
import { AssetFileUploadResponseDto } from './response-dto/asset-file-upload-response.dto';
|
||||
|
@ -260,6 +260,18 @@ export class AssetController {
|
|||
return await this.assetService.getAssetByTimeBucket(authUser, getAssetByTimeBucketDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all assets that have GPS information embedded
|
||||
*/
|
||||
@Authenticated()
|
||||
@Get('/mapMarker')
|
||||
getMapMarkers(
|
||||
@GetAuthUser() authUser: AuthUserDto,
|
||||
@Query(new ValidationPipe({ transform: true })) dto: AssetSearchDto,
|
||||
): Promise<MapMarkerResponseDto[]> {
|
||||
return this.assetService.getMapMarkers(authUser, dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all asset of a device that are in the database, ID only.
|
||||
*/
|
||||
|
|
|
@ -30,6 +30,8 @@ import {
|
|||
JobName,
|
||||
mapAsset,
|
||||
mapAssetWithoutExif,
|
||||
MapMarkerResponseDto,
|
||||
mapAssetMapMarker,
|
||||
} from '@app/domain';
|
||||
import { CreateAssetDto, UploadFile } from './dto/create-asset.dto';
|
||||
import { DeleteAssetResponseDto, DeleteAssetStatusEnum } from './response-dto/delete-asset-response.dto';
|
||||
|
@ -142,6 +144,14 @@ export class AssetService {
|
|||
return assets.map((asset) => mapAsset(asset));
|
||||
}
|
||||
|
||||
public async getMapMarkers(authUser: AuthUserDto, dto: AssetSearchDto): Promise<MapMarkerResponseDto[]> {
|
||||
const assets = await this._assetRepository.getAllByUserId(authUser.id, dto);
|
||||
|
||||
return assets
|
||||
.map((asset) => mapAssetMapMarker(asset))
|
||||
.filter((marker) => marker != null) as MapMarkerResponseDto[];
|
||||
}
|
||||
|
||||
public async getAssetByTimeBucket(
|
||||
authUser: AuthUserDto,
|
||||
getAssetByTimeBucketDto: GetAssetByTimeBucketDto,
|
||||
|
|
|
@ -2436,6 +2436,64 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/asset/mapMarker": {
|
||||
"get": {
|
||||
"operationId": "getMapMarkers",
|
||||
"description": "Get all assets that have GPS information embedded",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "isFavorite",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "isArchived",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/MapMarkerResponseDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Asset"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/asset/{deviceId}": {
|
||||
"get": {
|
||||
"operationId": "getUserAssetsByDeviceId",
|
||||
|
@ -5187,6 +5245,35 @@
|
|||
"timeBucket"
|
||||
]
|
||||
},
|
||||
"MapMarkerResponseDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"IMAGE",
|
||||
"VIDEO",
|
||||
"AUDIO",
|
||||
"OTHER"
|
||||
]
|
||||
},
|
||||
"lat": {
|
||||
"type": "number"
|
||||
},
|
||||
"lon": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"type",
|
||||
"lat",
|
||||
"lon"
|
||||
]
|
||||
},
|
||||
"UpdateAssetDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
export * from './asset-response.dto';
|
||||
export * from './exif-response.dto';
|
||||
export * from './smart-info-response.dto';
|
||||
export * from './map-marker-response.dto';
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { AssetEntity, AssetType } from '@app/infra/entities';
|
||||
|
||||
export class MapMarkerResponseDto {
|
||||
id!: string;
|
||||
type!: AssetType;
|
||||
lat!: number;
|
||||
lon!: number;
|
||||
}
|
||||
|
||||
export function mapAssetMapMarker(entity: AssetEntity): MapMarkerResponseDto | null {
|
||||
if (!entity.exifInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const lat = entity.exifInfo.latitude;
|
||||
const lon = entity.exifInfo.longitude;
|
||||
|
||||
if (!lat || !lon) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: entity.id,
|
||||
type: entity.type,
|
||||
lon,
|
||||
lat,
|
||||
};
|
||||
}
|
11
web/package-lock.json
generated
11
web/package-lock.json
generated
|
@ -14,6 +14,7 @@
|
|||
"justified-layout": "^4.1.0",
|
||||
"leaflet": "^1.9.3",
|
||||
"leaflet.markercluster": "^1.5.3",
|
||||
"leaflet.tilelayer.colorfilter": "^1.2.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"luxon": "^3.2.1",
|
||||
"rxjs": "^7.8.0",
|
||||
|
@ -9053,6 +9054,11 @@
|
|||
"leaflet": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/leaflet.tilelayer.colorfilter": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/leaflet.tilelayer.colorfilter/-/leaflet.tilelayer.colorfilter-1.2.5.tgz",
|
||||
"integrity": "sha512-wUvqVlpEofDEDi0ocXApXAcz1l06RsNBEw3L/2ColaygDPERswgas2Jgv/DVrWrVd0HQAxDerwFqOtBI+zbw3w=="
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
|
@ -18060,6 +18066,11 @@
|
|||
"integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==",
|
||||
"requires": {}
|
||||
},
|
||||
"leaflet.tilelayer.colorfilter": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/leaflet.tilelayer.colorfilter/-/leaflet.tilelayer.colorfilter-1.2.5.tgz",
|
||||
"integrity": "sha512-wUvqVlpEofDEDi0ocXApXAcz1l06RsNBEw3L/2ColaygDPERswgas2Jgv/DVrWrVd0HQAxDerwFqOtBI+zbw3w=="
|
||||
},
|
||||
"leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
"justified-layout": "^4.1.0",
|
||||
"leaflet": "^1.9.3",
|
||||
"leaflet.markercluster": "^1.5.3",
|
||||
"leaflet.tilelayer.colorfilter": "^1.2.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"luxon": "^3.2.1",
|
||||
"rxjs": "^7.8.0",
|
||||
|
|
127
web/src/api/open-api/api.ts
generated
127
web/src/api/open-api/api.ts
generated
|
@ -1438,6 +1438,47 @@ export interface LogoutResponseDto {
|
|||
*/
|
||||
'redirectUri': string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface MapMarkerResponseDto
|
||||
*/
|
||||
export interface MapMarkerResponseDto {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof MapMarkerResponseDto
|
||||
*/
|
||||
'id': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof MapMarkerResponseDto
|
||||
*/
|
||||
'type': MapMarkerResponseDtoTypeEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof MapMarkerResponseDto
|
||||
*/
|
||||
'lat': number;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof MapMarkerResponseDto
|
||||
*/
|
||||
'lon': number;
|
||||
}
|
||||
|
||||
export const MapMarkerResponseDtoTypeEnum = {
|
||||
Image: 'IMAGE',
|
||||
Video: 'VIDEO',
|
||||
Audio: 'AUDIO',
|
||||
Other: 'OTHER'
|
||||
} as const;
|
||||
|
||||
export type MapMarkerResponseDtoTypeEnum = typeof MapMarkerResponseDtoTypeEnum[keyof typeof MapMarkerResponseDtoTypeEnum];
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
|
@ -4647,6 +4688,56 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
|||
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Get all assets that have GPS information embedded
|
||||
* @param {boolean} [isFavorite]
|
||||
* @param {boolean} [isArchived]
|
||||
* @param {number} [skip]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getMapMarkers: async (isFavorite?: boolean, isArchived?: boolean, skip?: number, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
const localVarPath = `/asset/mapMarker`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication cookie required
|
||||
|
||||
// authentication bearer required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
if (isFavorite !== undefined) {
|
||||
localVarQueryParameter['isFavorite'] = isFavorite;
|
||||
}
|
||||
|
||||
if (isArchived !== undefined) {
|
||||
localVarQueryParameter['isArchived'] = isArchived;
|
||||
}
|
||||
|
||||
if (skip !== undefined) {
|
||||
localVarQueryParameter['skip'] = skip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
@ -5198,6 +5289,18 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
|||
const localVarAxiosArgs = await localVarAxiosParamCreator.getCuratedObjects(options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
* Get all assets that have GPS information embedded
|
||||
* @param {boolean} [isFavorite]
|
||||
* @param {boolean} [isArchived]
|
||||
* @param {number} [skip]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getMapMarkers(isFavorite?: boolean, isArchived?: boolean, skip?: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<MapMarkerResponseDto>>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getMapMarkers(isFavorite, isArchived, skip, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
* Get all asset of a device that are in the database, ID only.
|
||||
* @param {string} deviceId
|
||||
|
@ -5454,6 +5557,17 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
|||
getCuratedObjects(options?: any): AxiosPromise<Array<CuratedObjectsResponseDto>> {
|
||||
return localVarFp.getCuratedObjects(options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Get all assets that have GPS information embedded
|
||||
* @param {boolean} [isFavorite]
|
||||
* @param {boolean} [isArchived]
|
||||
* @param {number} [skip]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getMapMarkers(isFavorite?: boolean, isArchived?: boolean, skip?: number, options?: any): AxiosPromise<Array<MapMarkerResponseDto>> {
|
||||
return localVarFp.getMapMarkers(isFavorite, isArchived, skip, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Get all asset of a device that are in the database, ID only.
|
||||
* @param {string} deviceId
|
||||
|
@ -5740,6 +5854,19 @@ export class AssetApi extends BaseAPI {
|
|||
return AssetApiFp(this.configuration).getCuratedObjects(options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all assets that have GPS information embedded
|
||||
* @param {boolean} [isFavorite]
|
||||
* @param {boolean} [isArchived]
|
||||
* @param {number} [skip]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof AssetApi
|
||||
*/
|
||||
public getMapMarkers(isFavorite?: boolean, isArchived?: boolean, skip?: number, options?: AxiosRequestConfig) {
|
||||
return AssetApiFp(this.configuration).getMapMarkers(isFavorite, isArchived, skip, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all asset of a device that are in the database, ID only.
|
||||
* @param {string} deviceId
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
import { onDestroy, onMount } from 'svelte';
|
||||
import 'leaflet.markercluster';
|
||||
import { getMapContext } from './map.svelte';
|
||||
import { AssetResponseDto, getFileUrl } from '@api';
|
||||
import { MapMarkerResponseDto, getFileUrl } from '@api';
|
||||
import { Marker, Icon } from 'leaflet';
|
||||
import { assetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||
|
||||
export let assets: AssetResponseDto[];
|
||||
export let markers: MapMarkerResponseDto[];
|
||||
|
||||
const map = getMapContext();
|
||||
let cluster: L.MarkerClusterGroup;
|
||||
|
@ -33,17 +33,11 @@
|
|||
spiderfyDistanceMultiplier: 3
|
||||
});
|
||||
|
||||
for (let asset of assets) {
|
||||
if (!asset.exifInfo) continue;
|
||||
|
||||
const lat = asset.exifInfo.latitude;
|
||||
const lon = asset.exifInfo.longitude;
|
||||
|
||||
if (!lat || !lon) continue;
|
||||
for (let marker of markers) {
|
||||
|
||||
const icon = new Icon({
|
||||
iconUrl: getFileUrl(asset.id, true),
|
||||
iconRetinaUrl: getFileUrl(asset.id, true),
|
||||
iconUrl: getFileUrl(marker.id, true),
|
||||
iconRetinaUrl: getFileUrl(marker.id, true),
|
||||
iconSize: [60, 60],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
|
@ -51,16 +45,16 @@
|
|||
shadowSize: [41, 41]
|
||||
});
|
||||
|
||||
const marker = new Marker([lat, lon], {
|
||||
const leafletMarker = new Marker([marker.lat, marker.lon], {
|
||||
icon,
|
||||
alt: ''
|
||||
});
|
||||
|
||||
marker.on('click', () => {
|
||||
assetInteractionStore.setViewingAsset(asset);
|
||||
leafletMarker.on('click', () => {
|
||||
assetInteractionStore.setViewingAssetId(marker.id);
|
||||
});
|
||||
|
||||
cluster.addLayer(marker);
|
||||
cluster.addLayer(leafletMarker);
|
||||
}
|
||||
|
||||
map.addLayer(cluster);
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
<script lang="ts">
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import 'leaflet.tilelayer.colorfilter';
|
||||
import { TileLayer, type TileLayerOptions } from 'leaflet';
|
||||
import { getMapContext } from './map.svelte';
|
||||
|
||||
export let urlTemplate: string;
|
||||
export let options: TileLayerOptions | undefined = undefined;
|
||||
export let options: any | undefined = undefined;
|
||||
let tileLayer: TileLayer;
|
||||
|
||||
const map = getMapContext();
|
||||
|
||||
onMount(() => {
|
||||
tileLayer = new TileLayer(urlTemplate, options).addTo(map);
|
||||
tileLayer = new L.tileLayer.colorFilter(urlTemplate, options).addTo(map);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
|
|
|
@ -53,10 +53,14 @@ function createAssetInteractionStore() {
|
|||
* Asset Viewer
|
||||
*/
|
||||
const setViewingAsset = async (asset: AssetResponseDto) => {
|
||||
const { data } = await api.assetApi.getAssetById(asset.id);
|
||||
setViewingAssetId(asset.id);
|
||||
};
|
||||
|
||||
const setViewingAssetId = async (id: string) => {
|
||||
const { data } = await api.assetApi.getAssetById(id);
|
||||
viewingAssetStoreState.set(data);
|
||||
isViewingAssetStoreState.set(true);
|
||||
};
|
||||
}
|
||||
|
||||
const setIsViewingAsset = (isViewing: boolean) => {
|
||||
isViewingAssetStoreState.set(isViewing);
|
||||
|
@ -140,6 +144,7 @@ function createAssetInteractionStore() {
|
|||
|
||||
return {
|
||||
setViewingAsset,
|
||||
setViewingAssetId,
|
||||
setIsViewingAsset,
|
||||
navigateAsset,
|
||||
addAssetToMultiselectGroup,
|
||||
|
|
|
@ -8,11 +8,11 @@ export const load = (async ({ locals: { api, user } }) => {
|
|||
}
|
||||
|
||||
try {
|
||||
const { data: assets } = await api.assetApi.getAllAssets();
|
||||
const { data: mapMarkers } = await api.assetApi.getMapMarkers();
|
||||
|
||||
return {
|
||||
user,
|
||||
assets,
|
||||
mapMarkers,
|
||||
meta: {
|
||||
title: 'Map'
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@
|
|||
<TileLayer
|
||||
urlTemplate={'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'}
|
||||
options={{
|
||||
filter: ['bright:101%','contrast:101%','saturate:79%'],
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}}
|
||||
/>
|
||||
<AssetMarkerCluster assets={data.assets} />
|
||||
<AssetMarkerCluster markers={data.mapMarkers} />
|
||||
</Map>
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue