mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
feat: album map markers endpoint (#27830)
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
} from 'src/dtos/album.dto';
|
||||
import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { MapMarkerResponseDto } from 'src/dtos/map.dto';
|
||||
import { ApiTag, Permission } from 'src/enum';
|
||||
import { Auth, Authenticated } from 'src/middleware/auth.guard';
|
||||
import { AlbumService } from 'src/services/album.service';
|
||||
@@ -102,6 +103,17 @@ export class AlbumController {
|
||||
return this.service.delete(auth, id);
|
||||
}
|
||||
|
||||
@Authenticated({ permission: Permission.AlbumRead, sharedLink: true })
|
||||
@Get(':id/map-markers')
|
||||
@Endpoint({
|
||||
summary: 'Retrieve album map markers',
|
||||
description: 'Retrieve map marker information for a specific album by its ID.',
|
||||
history: new HistoryBuilder().added('v3'),
|
||||
})
|
||||
getAlbumMapMarkers(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise<MapMarkerResponseDto[]> {
|
||||
return this.service.getMapMarkers(auth, id);
|
||||
}
|
||||
|
||||
@Put(':id/assets')
|
||||
@Authenticated({ permission: Permission.AlbumAssetCreate })
|
||||
@Endpoint({
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
-- NOTE: This file is auto generated by ./sql-generator
|
||||
|
||||
-- MapRepository.getAlbumMapMarkers
|
||||
select
|
||||
"id",
|
||||
"asset_exif"."latitude" as "lat",
|
||||
"asset_exif"."longitude" as "lon",
|
||||
"asset_exif"."city",
|
||||
"asset_exif"."state",
|
||||
"asset_exif"."country"
|
||||
from
|
||||
"asset"
|
||||
inner join "asset_exif" on "asset"."id" = "asset_exif"."assetId"
|
||||
and "asset_exif"."latitude" is not null
|
||||
and "asset_exif"."longitude" is not null
|
||||
inner join "album_asset" on "asset"."id" = "album_asset"."assetId"
|
||||
where
|
||||
"asset"."deletedAt" is null
|
||||
and "album_asset"."albumId" = $1
|
||||
order by
|
||||
"fileCreatedAt" desc
|
||||
|
||||
-- MapRepository.getMapMarkers
|
||||
select
|
||||
"id",
|
||||
@@ -14,8 +34,8 @@ from
|
||||
and "asset_exif"."latitude" is not null
|
||||
and "asset_exif"."longitude" is not null
|
||||
where
|
||||
"asset"."visibility" = $1
|
||||
and "deletedAt" is null
|
||||
"asset"."deletedAt" is null
|
||||
and "asset"."visibility" = $1
|
||||
and (
|
||||
"ownerId" in ($2)
|
||||
or exists (
|
||||
|
||||
@@ -76,29 +76,21 @@ export class MapRepository {
|
||||
this.logger.log('Geodata import completed');
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID] })
|
||||
getAlbumMapMarkers(albumId: string) {
|
||||
return this.mapMarkersQuery()
|
||||
.innerJoin('album_asset', 'asset.id', 'album_asset.assetId')
|
||||
.where('album_asset.albumId', '=', albumId)
|
||||
.execute();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [[DummyValue.UUID], [DummyValue.UUID]] })
|
||||
getMapMarkers(
|
||||
ownerIds: string[],
|
||||
albumIds: string[],
|
||||
{ isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore }: MapMarkerSearchOptions = {},
|
||||
) {
|
||||
return this.db
|
||||
.selectFrom('asset')
|
||||
.innerJoin('asset_exif', (builder) =>
|
||||
builder
|
||||
.onRef('asset.id', '=', 'asset_exif.assetId')
|
||||
.on('asset_exif.latitude', 'is not', null)
|
||||
.on('asset_exif.longitude', 'is not', null),
|
||||
)
|
||||
.select([
|
||||
'id',
|
||||
'asset_exif.latitude as lat',
|
||||
'asset_exif.longitude as lon',
|
||||
'asset_exif.city',
|
||||
'asset_exif.state',
|
||||
'asset_exif.country',
|
||||
])
|
||||
.$narrowType<{ lat: NotNull; lon: NotNull }>()
|
||||
return this.mapMarkersQuery()
|
||||
.$if(isArchived === true, (qb) =>
|
||||
qb.where((eb) =>
|
||||
eb.or([
|
||||
@@ -113,7 +105,6 @@ export class MapRepository {
|
||||
.$if(isFavorite !== undefined, (q) => q.where('isFavorite', '=', isFavorite!))
|
||||
.$if(fileCreatedAfter !== undefined, (q) => q.where('fileCreatedAt', '>=', fileCreatedAfter!))
|
||||
.$if(fileCreatedBefore !== undefined, (q) => q.where('fileCreatedAt', '<=', fileCreatedBefore!))
|
||||
.where('deletedAt', 'is', null)
|
||||
.where((eb) => {
|
||||
const expression: Expression<SqlBool>[] = [];
|
||||
|
||||
@@ -134,10 +125,31 @@ export class MapRepository {
|
||||
|
||||
return eb.or(expression);
|
||||
})
|
||||
.orderBy('fileCreatedAt', 'desc')
|
||||
.execute();
|
||||
}
|
||||
|
||||
private mapMarkersQuery() {
|
||||
return this.db
|
||||
.selectFrom('asset')
|
||||
.innerJoin('asset_exif', (builder) =>
|
||||
builder
|
||||
.onRef('asset.id', '=', 'asset_exif.assetId')
|
||||
.on('asset_exif.latitude', 'is not', null)
|
||||
.on('asset_exif.longitude', 'is not', null),
|
||||
)
|
||||
.where('asset.deletedAt', 'is', null)
|
||||
.orderBy('fileCreatedAt', 'desc')
|
||||
.select([
|
||||
'id',
|
||||
'asset_exif.latitude as lat',
|
||||
'asset_exif.longitude as lon',
|
||||
'asset_exif.city',
|
||||
'asset_exif.state',
|
||||
'asset_exif.country',
|
||||
])
|
||||
.$narrowType<{ lat: NotNull; lon: NotNull }>();
|
||||
}
|
||||
|
||||
async reverseGeocode(point: GeoPoint): Promise<ReverseGeocodeResult> {
|
||||
this.logger.debug(`Request: ${point.latitude},${point.longitude}`);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from 'src/dtos/album.dto';
|
||||
import { BulkIdErrorReason, BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { MapMarkerResponseDto } from 'src/dtos/map.dto';
|
||||
import { Permission } from 'src/enum';
|
||||
import { AlbumAssetCount, AlbumInfoOptions } from 'src/repositories/album.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
@@ -94,6 +95,16 @@ export class AlbumService extends BaseService {
|
||||
};
|
||||
}
|
||||
|
||||
async getMapMarkers(auth: AuthDto, id: string): Promise<MapMarkerResponseDto[]> {
|
||||
await this.requireAccess({ auth, permission: Permission.AlbumRead, ids: [id] });
|
||||
|
||||
if (auth.sharedLink && !auth.sharedLink.showExif) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.mapRepository.getAlbumMapMarkers(id);
|
||||
}
|
||||
|
||||
async create(auth: AuthDto, dto: CreateAlbumDto): Promise<AlbumResponseDto> {
|
||||
const albumUsers = dto.albumUsers || [];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user