Skip to content

Commit

Permalink
feat(DTFS2-7052): new module geospatial
Browse files Browse the repository at this point in the history
  • Loading branch information
avaitonis committed Apr 10, 2024
1 parent 2cdd0de commit 14a6a08
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 0 deletions.
16 changes: 16 additions & 0 deletions src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ApiProperty } from '@nestjs/swagger';
import { Matches, MaxLength, MinLength } from 'class-validator';

const UK_POSTCODE = /^[A-Za-z]{1,2}[0-9Rr][0-9A-Za-z]?\s?[0-9][ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/;

export class GetAddressByPostcodeQueryDto {
@ApiProperty({
example: 'SW1A 2AQ',
description: 'Postcode to search for',
})
@MinLength(5)
@MaxLength(8)
@Matches(UK_POSTCODE)
public postcode: string;
}

47 changes: 47 additions & 0 deletions src/modules/geospatial/dto/get-search-addresses-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ApiProperty } from '@nestjs/swagger';

export type GetSearchAddressesResponse = GetSearchAddressesResponseItem[];

export class GetSearchAddressesResponseItem {
@ApiProperty({
description: 'Organisation name if available',
example: 'CHURCHILL MUSEUM & CABINET WAR ROOMS',
})
readonly organisationName: string | null;

@ApiProperty({
description: 'Address line 1',
example: 'CLIVE STEPS KING CHARLES STREET',
})
readonly addressLine1: string;

@ApiProperty({
description: 'Address line 2',
example: null,
})
readonly addressLine2: string | null;

@ApiProperty({
description: 'Address line 3',
example: null,
})
readonly addressLine3: string | null;

@ApiProperty({
description: 'Locality, Town',
example: 'LONDON',
})
readonly locality: string | null;

@ApiProperty({
description: 'Postcode',
example: 'SW1A 2AQ',
})
readonly postalCode: string | null;

@ApiProperty({
description: 'Country of address record',
example: null,
})
readonly country: string | null;
}
29 changes: 29 additions & 0 deletions src/modules/geospatial/geospatial.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { BadRequestException, Controller, Get, Query } from '@nestjs/common';
import { ApiNotFoundResponse, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';

import { GetSearchPostcodeOrdnanceSurveyQueryDto } from '@ukef/helper-modules/ordnance-survey/dto/get-search-postcode-query.dto';
import { GeospatialService } from './geospatial.service';
import { GetAddressByPostcodeQueryDto } from './dto/get-address-by-postcode-query.dto';
import { GetSearchAddressesResponse, GetSearchAddressesResponseItem } from './dto/get-search-addresses-response.dto';

@ApiTags('geospatial')
@Controller('geospatial')
export class GeospatialController {
constructor(private readonly geospatialService: GeospatialService) {}

@Get('addresses/postcode')
@ApiOperation({
summary: "A search based on a property's postcode. Will accept a full postcode consisting of the area, district, sector and unit e.g. SO16 0AS.",
})
@ApiResponse({
status: 200,
description: 'AddressBase® Premium Basic Land and Property Units (BLPUs) can reference two types of address and with the OS Places API it is possible to search for one at a time, or both. These are the Delivery Point Address (DPA) and the Land and Property Identifier (LPI).',
type: [GetSearchAddressesResponseItem],
})
@ApiNotFoundResponse({
description: 'Customer not found.',
})
getGeospatial(@Query() query: GetAddressByPostcodeQueryDto): Promise<GetSearchAddressesResponse> {
return this.geospatialService.getAddressesByPostcode(query.postcode);
}
}
12 changes: 12 additions & 0 deletions src/modules/geospatial/geospatial.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { OrdnanceSurveyModule } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.module';

import { GeospatialController } from './geospatial.controller';
import { GeospatialService } from './geospatial.service';

@Module({
imports: [OrdnanceSurveyModule],
controllers: [GeospatialController],
providers: [GeospatialService],
})
export class GeospatialModule {}
33 changes: 33 additions & 0 deletions src/modules/geospatial/geospatial.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Injectable } from '@nestjs/common';
import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service';

import { GetSearchAddressesResponse } from './dto/get-search-addresses-response.dto';

@Injectable()
export class GeospatialService {
constructor(private readonly ordnanceSurveyService: OrdnanceSurveyService) {}

async getAddressesByPostcode(postcode: string): Promise<GetSearchAddressesResponse> {
let addresses = [];
const response = await this.ordnanceSurveyService.getAddressesByPostcode(postcode);

response.results.forEach((item) => {
// if (item.DPA.LANGUAGE === (req.query.language ? req.query.language : 'EN')) {
if (item.DPA.LANGUAGE === 'EN') {
// Ordnance survey sends duplicated results with the welsh version too via 'CY'

addresses.push({
organisationName: item.DPA.ORGANISATION_NAME || null,
addressLine1: `${item.DPA.BUILDING_NAME || ''} ${item.DPA.BUILDING_NUMBER || ''} ${item.DPA.THOROUGHFARE_NAME || ''}`.trim(),
addressLine2: item.DPA.DEPENDENT_LOCALITY || null,
addressLine3: null, // keys to match registered Address as requested, but not available in OS Places
locality: item.DPA.POST_TOWN || null,
postalCode: item.DPA.POSTCODE || null,
country: null, // keys to match registered Address as requested, but not available in OS Places
});
}
});

return addresses;
}
}

0 comments on commit 14a6a08

Please sign in to comment.