mirror of
https://github.com/immich-app/immich.git
synced 2025-12-20 17:25:35 +03:00
feat(server): reverse geocoding endpoint (#11430)
* feat(server): reverse geocoding endpoint * chore: rename error message
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
import { Controller, Get, Query } from '@nestjs/common';
|
||||
import { Controller, Get, HttpCode, HttpStatus, Query } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { MapMarkerDto, MapMarkerResponseDto } from 'src/dtos/search.dto';
|
||||
import {
|
||||
MapMarkerDto,
|
||||
MapMarkerResponseDto,
|
||||
MapReverseGeocodeDto,
|
||||
MapReverseGeocodeResponseDto,
|
||||
} from 'src/dtos/map.dto';
|
||||
import { MapThemeDto } from 'src/dtos/system-config.dto';
|
||||
import { Auth, Authenticated } from 'src/middleware/auth.guard';
|
||||
import { MapService } from 'src/services/map.service';
|
||||
@@ -22,4 +27,11 @@ export class MapController {
|
||||
getMapStyle(@Query() dto: MapThemeDto) {
|
||||
return this.service.getMapStyle(dto.theme);
|
||||
}
|
||||
|
||||
@Authenticated()
|
||||
@Get('reverse-geocode')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
reverseGeocode(@Query() dto: MapReverseGeocodeDto): Promise<MapReverseGeocodeResponseDto[]> {
|
||||
return this.service.reverseGeocode(dto);
|
||||
}
|
||||
}
|
||||
|
||||
67
server/src/dtos/map.dto.ts
Normal file
67
server/src/dtos/map.dto.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsLatitude, IsLongitude } from 'class-validator';
|
||||
import { ValidateBoolean, ValidateDate } from 'src/validation';
|
||||
|
||||
export class MapReverseGeocodeDto {
|
||||
@ApiProperty({ format: 'double' })
|
||||
@Type(() => Number)
|
||||
@IsLatitude({ message: ({ property }) => `${property} must be a number between -90 and 90` })
|
||||
lat!: number;
|
||||
|
||||
@ApiProperty({ format: 'double' })
|
||||
@Type(() => Number)
|
||||
@IsLongitude({ message: ({ property }) => `${property} must be a number between -180 and 180` })
|
||||
lon!: number;
|
||||
}
|
||||
|
||||
export class MapReverseGeocodeResponseDto {
|
||||
@ApiProperty()
|
||||
city!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
state!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
country!: string | null;
|
||||
}
|
||||
|
||||
export class MapMarkerDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
isArchived?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isFavorite?: boolean;
|
||||
|
||||
@ValidateDate({ optional: true })
|
||||
fileCreatedAfter?: Date;
|
||||
|
||||
@ValidateDate({ optional: true })
|
||||
fileCreatedBefore?: Date;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
withPartners?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
withSharedAlbums?: boolean;
|
||||
}
|
||||
|
||||
export class MapMarkerResponseDto {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty({ format: 'double' })
|
||||
lat!: number;
|
||||
|
||||
@ApiProperty({ format: 'double' })
|
||||
lon!: number;
|
||||
|
||||
@ApiProperty()
|
||||
city!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
state!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
country!: string | null;
|
||||
}
|
||||
@@ -289,26 +289,6 @@ export class SearchExploreResponseDto {
|
||||
items!: SearchExploreItem[];
|
||||
}
|
||||
|
||||
export class MapMarkerDto {
|
||||
@ValidateBoolean({ optional: true })
|
||||
isArchived?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
isFavorite?: boolean;
|
||||
|
||||
@ValidateDate({ optional: true })
|
||||
fileCreatedAfter?: Date;
|
||||
|
||||
@ValidateDate({ optional: true })
|
||||
fileCreatedBefore?: Date;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
withPartners?: boolean;
|
||||
|
||||
@ValidateBoolean({ optional: true })
|
||||
withSharedAlbums?: boolean;
|
||||
}
|
||||
|
||||
export class MemoryLaneDto {
|
||||
@IsInt()
|
||||
@Type(() => Number)
|
||||
@@ -324,22 +304,3 @@ export class MemoryLaneDto {
|
||||
@ApiProperty({ type: 'integer' })
|
||||
month!: number;
|
||||
}
|
||||
export class MapMarkerResponseDto {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty({ format: 'double' })
|
||||
lat!: number;
|
||||
|
||||
@ApiProperty({ format: 'double' })
|
||||
lon!: number;
|
||||
|
||||
@ApiProperty()
|
||||
city!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
state!: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
country!: string | null;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { SystemConfigCore } from 'src/cores/system-config.core';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { MapMarkerDto, MapMarkerResponseDto } from 'src/dtos/search.dto';
|
||||
import { MapMarkerDto, MapMarkerResponseDto, MapReverseGeocodeDto } from 'src/dtos/map.dto';
|
||||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||
@@ -53,4 +53,11 @@ export class MapService {
|
||||
|
||||
return JSON.parse(await this.systemMetadataRepository.readFile(`./resources/style-${theme}.json`));
|
||||
}
|
||||
|
||||
async reverseGeocode(dto: MapReverseGeocodeDto) {
|
||||
const { lat: latitude, lon: longitude } = dto;
|
||||
// eventually this should probably return an array of results
|
||||
const result = await this.mapRepository.reverseGeocode({ latitude, longitude });
|
||||
return result ? [result] : [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user