This commit is contained in:
Matthias Rupp 2023-05-06 21:18:24 -11:00
parent e85eb4e179
commit 0e516d1685
14 changed files with 68 additions and 40 deletions

View file

@ -252,7 +252,7 @@ export class AssetRepository implements IAssetRepository {
exifInfo: {
latitude: Not(IsNull()),
longitude: Not(IsNull()),
}
},
},
relations: {
exifInfo: true,

View file

@ -31,7 +31,9 @@ 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, MapMarkerResponseDto, GetMapMarkerDto } from '@app/domain';
import { AssetResponseDto, ImmichReadStream } from '@app/domain';
import { GetMapMarkerDto } from './dto/get-map-marker.dto';
import { MapMarkerResponseDto } from './response-dto/map-marker-response.dto';
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';

View file

@ -142,6 +142,7 @@ describe('AssetService', () => {
getAll: jest.fn(),
getAllVideos: jest.fn(),
getAllByUserId: jest.fn(),
getMapMarkerByUserId: jest.fn(),
getAllByDeviceId: jest.fn(),
getAssetCountByTimeBucket: jest.fn(),
getById: jest.fn(),
@ -498,14 +499,31 @@ describe('AssetService', () => {
describe('get map markers', () => {
it('should get geo information of assets', async () => {
assetRepositoryMock.getAllByUserId.mockResolvedValue(_getAssets());
assetRepositoryMock.getMapMarkerByUserId.mockResolvedValue(
_getAssets().filter((asset) => asset.exifInfo?.latitude != null),
);
const markers = await sut.getMapMarkers(authStub.admin, {});
const markers = await sut.getMapMarkers(authStub.admin, false);
expect(markers).toHaveLength(1);
expect(markers[0].lat).toBe(_getAsset_1().exifInfo?.latitude);
expect(markers[0].lon).toBe(_getAsset_1().exifInfo?.longitude);
expect(markers[0].id).toBe(_getAsset_1().id);
expect(markers[0]).toHaveLength(3);
expect(markers[0][0]).toBe(_getAsset_1().id);
expect(markers[0][1]).toBeCloseTo(_getAsset_1().exifInfo?.latitude || 0, 4);
expect(markers[0][2]).toBeCloseTo(_getAsset_1().exifInfo?.longitude || 0, 4);
});
it('should preload assets', async () => {
assetRepositoryMock.getMapMarkerByUserId.mockResolvedValue(
_getAssets().filter((asset) => asset.exifInfo?.latitude != null),
);
const markers = await sut.getMapMarkers(authStub.admin, true);
expect(markers).toHaveLength(1);
expect(markers[0]).toHaveLength(3);
expect(markers[0][0]).toBe('');
expect(markers[0][1]).toBeCloseTo(_getAsset_1().exifInfo?.latitude || 0, 4);
expect(markers[0][2]).toBeCloseTo(_getAsset_1().exifInfo?.longitude || 0, 4);
});
});
});

View file

@ -30,10 +30,9 @@ import {
JobName,
mapAsset,
mapAssetWithoutExif,
MapMarkerResponseDto,
mapAssetMapMarker,
} from '@app/domain';
import { CreateAssetDto, UploadFile } from './dto/create-asset.dto';
import { MapMarkerResponseDto, mapAssetMapMarker } from './response-dto/map-marker-response.dto';
import { DeleteAssetResponseDto, DeleteAssetStatusEnum } from './response-dto/delete-asset-response.dto';
import { GetAssetThumbnailDto, GetAssetThumbnailFormatEnum } from './dto/get-asset-thumbnail.dto';
import { CheckDuplicateAssetResponseDto } from './response-dto/check-duplicate-asset-response.dto';
@ -147,7 +146,9 @@ export class AssetService {
public async getMapMarkers(authUser: AuthUserDto, preload: boolean): Promise<MapMarkerResponseDto[]> {
const assets = await this._assetRepository.getMapMarkerByUserId(authUser.id);
return assets.map((asset) => mapAssetMapMarker(asset, preload)).filter((marker) => marker != null) as MapMarkerResponseDto[];
return assets
.map((asset) => mapAssetMapMarker(asset, preload))
.filter((marker) => marker != null) as MapMarkerResponseDto[];
}
public async getAssetByTimeBucket(

View file

@ -4,13 +4,13 @@ import { toBoolean } from 'apps/immich/src/utils/transform.util';
import { ApiProperty } from '@nestjs/swagger';
export class GetMapMarkerDto {
@IsOptional()
@IsBoolean()
@Transform(toBoolean)
@ApiProperty()
/**
* true: returns only a list of locations
* false: also include asset id
*/
preload?: boolean;
}
@IsOptional()
@IsBoolean()
@Transform(toBoolean)
@ApiProperty()
/**
* true: returns only a list of locations
* false: also include asset id
*/
preload?: boolean;
}

View file

@ -1,5 +1,5 @@
import { AssetEntity } from "@app/infra/entities";
import { roundToDecimals } from 'apps/immich/src/utils/coordinate.util';
import { AssetEntity } from '@app/infra/entities';
import { roundToDecimals } from '../../../utils/coordinate.util';
export type MapMarkerResponseDto = [
// assetId
@ -7,7 +7,7 @@ export type MapMarkerResponseDto = [
// latitude
number,
// longitude
number
number,
];
export function mapAssetMapMarker(asset: AssetEntity, preload: boolean): MapMarkerResponseDto {
@ -15,10 +15,6 @@ export function mapAssetMapMarker(asset: AssetEntity, preload: boolean): MapMark
const lon = asset.exifInfo?.longitude || 0;
const assetId = preload ? '' : asset.id;
return [
assetId,
roundToDecimals(lat, 5),
roundToDecimals(lon, 5)
];
return [assetId, roundToDecimals(lat, 5), roundToDecimals(lon, 5)];
}

View file

@ -0,0 +1,14 @@
import { roundToDecimals } from './coordinate.util';
describe('Coordinate utils roundToDecimals test', () => {
it('should round latitude and longitude to 5', () => {
const lat = 49.533547;
const lon = 10.703075;
const latRounded = roundToDecimals(lat, 5);
const lonRounded = roundToDecimals(lon, 5);
expect(latRounded).toBeCloseTo(lat, 4);
expect(lonRounded).toBeCloseTo(lon, 4);
});
});

View file

@ -1,4 +1,4 @@
export function roundToDecimals(num: number, digits: number): number {
const factor = 10 ** digits;
return Math.round(num * factor + Number.EPSILON) / factor;
}
const factor = 10 ** digits;
return Math.round(num * factor + Number.EPSILON) / factor;
}

View file

@ -1,3 +1,3 @@
export * from './album.repository';
export * from './album.service';
export * from './response-dto';
export * from './response-dto';

View file

@ -1 +0,0 @@
export * from './get-map-marker.dto';

View file

@ -2,4 +2,3 @@ export * from './asset.core';
export * from './asset.repository';
export * from './asset.service';
export * from './response-dto';
export * from './dto';

View file

@ -1,4 +1,3 @@
export * from './asset-response.dto';
export * from './exif-response.dto';
export * from './smart-info-response.dto';
export * from './map-marker-response.dto';

View file

@ -55,7 +55,7 @@
.getAllChildMarkers()
.map((marker: AssetMarker) => marker.getAssetId())
.filter((id: string) => id.length > 0);
if (ids.length > 0) {
dispatch('view', { assets: ids });
}
@ -96,7 +96,7 @@
<style>
:global(.marker-cluster-asset-marker) {
border-radius: 25%;
background-color: rgba(236, 237, 246, .8);
background-color: rgba(236, 237, 246, 0.8);
line-height: 60px;
text-align: center;
}

View file

@ -9,8 +9,8 @@
viewingAssetStoreState
} from '$lib/stores/asset-interaction.store';
import { api, MapMarkerResponseDto } from '@api';
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import { onMount } from 'svelte';
import { browser } from '$app/environment';
export let data: PageData;
let mapMarkers: MapMarkerResponseDto = [];