From 5a8595d8209248d656c2b203ce4cf199bba1ba60 Mon Sep 17 00:00:00 2001 From: Corey White Date: Wed, 19 Feb 2025 19:18:46 -0500 Subject: [PATCH] models: Replacing epsg.io API endpoint --- src/Models/EpsgInfo.js | 44 +++++++----------- src/Models/ProjectionInfoModel.js | 64 +++++++++++--------------- src/Models/ProjectionInfoModel.test.js | 16 ++++--- 3 files changed, 52 insertions(+), 72 deletions(-) diff --git a/src/Models/EpsgInfo.js b/src/Models/EpsgInfo.js index 5208ca3..59acb10 100644 --- a/src/Models/EpsgInfo.js +++ b/src/Models/EpsgInfo.js @@ -1,11 +1,11 @@ /* * Filename: EpsgInfo.js - * Project: TomorrowNow + * Project: OpenPlains * File Created: Thursday May 26th 2022 * Author: Corey White (smortopahri@gmail.com) * Maintainer: Corey White * ----- - * Last Modified: Thu May 26 2022 + * Last Modified: Wed Feb 19 2025 * Modified By: Corey White * ----- * License: GPLv3 @@ -33,32 +33,22 @@ /** * Class representing espg info return by epsg.io query. */ - export class EpsgInfo { +export class EpsgInfo { /** * Create an EpsgInfo - * @param {String} code - The epsg code - * @param {String} kind - The kind of projection e.g. CRS-GEOGCRS - * @param {Array | String} [bbox = ""] - The bounding box of the projection e.g. [90, -180, -90, 180] - * @param {String} [wkt = ""] - The wkt represention of the projection - * @param {String} [unit = ""] - The measurment unit e.g. degree, meter, feet. - * @param {String} [proj4 = ""] - The proj4 representation e.g. +proj=longlat +datum=WGS84 +no_def - * @param {String} [name = ""] - The projection name. e.g. WGS 84 - * @param {String} [area = ""] - The area of the projection e.g. World. - * @param {Number} [default_trans = 0] - Default transform coordinates. - * @param {Array} [trans = []] - Array of transform coordinates - * @param {String} [accuracy = ""] - The accuracy + * @param {Object} data - The data object containing EPSG information */ - constructor({code, kind, bbox = "", wkt = "", unit = "", proj4 ="", name = "", area = "", default_trans = 0, trans = [], accuracy}) { - this.code = code; - this.kind = kind; - this.bbox = Array.isArray(bbox) ? bbox : null; - this.wkt = wkt; - this.unit = unit; - this.proj4 = proj4; - this.name = name; - this.area = area; - this.defaultTrans = default_trans; - this.trans = [...trans]; - this.accuracy = accuracy; + constructor(data) { + this.code = data.id.code; + this.kind = data.kind; + this.bbox = Array.isArray(data.bbox) ? data.bbox : null; + this.wkt = data.exports.wkt; + this.unit = data.unit; + this.proj4 = data.exports.proj4; + this.name = data.name; + this.area = data.area; + this.defaultTrans = data.default_transformation.code; + this.trans = [...data.transformations]; + this.accuracy = data.accuracy; } -} \ No newline at end of file +} diff --git a/src/Models/ProjectionInfoModel.js b/src/Models/ProjectionInfoModel.js index cd42584..e8a253d 100644 --- a/src/Models/ProjectionInfoModel.js +++ b/src/Models/ProjectionInfoModel.js @@ -5,7 +5,7 @@ * Author: Corey White (smortopahri@gmail.com) * Maintainer: Corey White * ----- - * Last Modified: Mon Sep 12 2022 + * Last Modified: Wed Feb 19 2025 * Modified By: Corey White * ----- * License: GPLv3 @@ -37,64 +37,52 @@ import { EpsgSearchResponse } from "./EpsgSearchResponse"; * Actinia class mapping representing the schema to define projection information as JSON input in POST requests */ export class ProjectionInfoModel { - static EPSGIO_BASE_URL = "https://epsg.io/" + static MAPTILER_BASE_URL = "https://api.maptiler.com/"; + /** * Create a ProjectionInfoModel instance - * @param {Object} - * @param {String} epsg The EPSG code of the projection that should be used to create a location. + * @param {Object} param0 + * @param {String} param0.epsg The EPSG code of the projection that should be used to create a location. */ - constructor({epsg}) { + constructor({ epsg }) { this.epsg = epsg; - this.projectionDetails = {} + this.projectionDetails = {}; } /** * Fetch details about projection from epsg.io - * @returns ProjectionInfoModel with parameter projectionDetails containing projection details + * @returns {Promise} ProjectionInfoModel with parameter projectionDetails containing projection details */ async fetchDetails() { - let epsg = this.epsg - const results = await ProjectionInfoModel.searchEpsg(epsg).results; - - if (results) { - this.projectionDetails = results.map(result => { - let projDetails = {}; - if (result) { - const code = result.code; - const name = result.name; - const proj4def = result.proj4; - const bbox = result.bbox; - - if (code && code.length > 0 && proj4def && proj4def.length > 0 && bbox && bbox.length === 4) { - projDetails = { - code, - name, - proj4def, - bbox - } - } - } - return projDetails; - }) + const response = await ProjectionInfoModel.searchEpsg(this.epsg); + + if (response.results) { + this.projectionDetails = response.results + .filter(result => result && result.id.code && result.exports.proj4 && result.bbox && result.bbox.length === 4) + .map(result => ({ + code: result.id.code, + name: result.name, + proj4def: result.exports.proj4, + bbox: result.bbox + })); } - return this + return this; } /** * Search for details for a specific epsg code. * @param {String} epsg - * @returns {EpsgSearchResponse} Repsone from epsg.io or error response. + * @returns {Promise} Response from epsg.io or error response. */ static async searchEpsg(epsg) { + const searchPath = "/coordinates/search/"; try { - const url = new URL(`${this.EPSGIO_BASE_URL}?format=json&q=${epsg}`) + const url = new URL(`${this.MAPTILER_BASE_URL}${searchPath}${epsg}.json`); const res = await fetch(url); const data = await res.json(); - const response = await new EpsgSearchResponse({...data}) - return response - } - catch (e) { + return new EpsgSearchResponse(data); + } catch (e) { return e; } } -} \ No newline at end of file +} diff --git a/src/Models/ProjectionInfoModel.test.js b/src/Models/ProjectionInfoModel.test.js index f3c5eea..90534d1 100644 --- a/src/Models/ProjectionInfoModel.test.js +++ b/src/Models/ProjectionInfoModel.test.js @@ -5,7 +5,7 @@ * Author: Corey White (smortopahri@gmail.com) * Maintainer: Corey White * ----- - * Last Modified: Mon Sep 12 2022 + * Last Modified: Wed Feb 19 2025 * Modified By: Corey White * ----- * License: GPLv3 @@ -34,7 +34,6 @@ import { ProjectionInfoModel } from './ProjectionInfoModel'; import { EpsgSearchResponse } from './EpsgSearchResponse'; import { EpsgInfo } from './EpsgInfo'; - function setupFetchStub(data) { return function fetchStub() { return new Promise((resolve) => { @@ -49,8 +48,7 @@ function setupFetchStub(data) { } const MOCK_EPSG_RESPONSE = { - "status": "ok", - "number_result": 1, + "total": 1, "results": [ { "code": "4326", @@ -85,15 +83,19 @@ describe("ProjectionInfoModel", ()=> { expect(typeof projectionInfo.projectionDetails).toBe('object') }) + test("ProjectionInfoModel.fetchDetails() returns a Promise", ()=> { + expect(projectionInfo.fetchDetails() instanceof Promise).toBeTruthy() + }) + test('ProjectionInfoModel.searchEpsg(4326) searches epsg.io and returns data', async () => { - + global.fetch = jest.fn().mockImplementation(setupFetchStub(MOCK_EPSG_RESPONSE)) const json = await ProjectionInfoModel.searchEpsg(wgs84.epsg) expect(json instanceof EpsgSearchResponse).toBeTruthy() + expect(json.results).toEqual(MOCK_EPSG_RESPONSE.results) expect(json.results.length).toEqual(1) expect(json.results[0] instanceof EpsgInfo).toBeTruthy() global.fetch.mockClear() delete global.fetch + }) }) -}) -