From 5fcd6e787c5ae04dab831e0b027ee60737bca375 Mon Sep 17 00:00:00 2001 From: Dan Jones <danjon@noc.ac.uk> Date: Tue, 20 Aug 2024 14:14:42 +0100 Subject: [PATCH] refactor: load geojson defs from published schemas --- formats/planning_configuration.py | 15 +- generate_schema_config.py | 91 +++ project/soar/swagger.json | 1203 +++++++++++++++++++++++++++-- requirements.txt | 1 + 4 files changed, 1244 insertions(+), 66 deletions(-) diff --git a/formats/planning_configuration.py b/formats/planning_configuration.py index 6a16e42..a2260f7 100644 --- a/formats/planning_configuration.py +++ b/formats/planning_configuration.py @@ -184,20 +184,11 @@ platform_schema = { region_schema = { "type": "object", "properties": { - "geometry_coordinates": { - "type": "array", - "example": [ - [ - [-4.1777839187560915, 50.34173405662855], - [-4.1777839187560915, 50.33820949229701], - [-4.143667777943875, 50.33820949229701], - [-4.143667777943875, 50.34173405662855], - [-4.1777839187560915, 50.34173405662855], - ] - ], + "geometry": { + "$ref": "https://geojson.org/schema/Polygon.json", }, }, - "description": "Using GEOJSON, exact 4-point region (rectangle shaped - 5 points)", + "description": "GeoJSON Polygon", } squad_metadata_schema = { diff --git a/generate_schema_config.py b/generate_schema_config.py index fa58bb1..07dcae7 100644 --- a/generate_schema_config.py +++ b/generate_schema_config.py @@ -17,6 +17,8 @@ from flask import Flask import argparse import json import os +import re +import requests # Enable running on domain sub-path @@ -112,6 +114,93 @@ swagger_config = { } +def resolve_ref(ref): + """ + Get schema URL, parse JSON + Return None if either fails + """ + try: + res = requests.get(ref) + if res.status_code == 200: + return res.json() + else: + return None + except (json.JSONDecodeError, ValueError): + return None + + +def rename_ref(ref): + """ + Convert remote ref URL into a name that can + be used for a local ref in the schema + Remote the URL scheme and replace / with . + """ + # remove url scheme + deschemed = re.sub(r"^[htps]*\:*[/]{2}", "", ref) + # replace / with . since the name will be in a path + return re.sub(r"[/]", ".", deschemed) + + +def nested_replace(source, key, value, replace_with): + """ + Find all instances of a key value pair in a nested + dictionary and replace the value with replace_with + """ + for k,v in source.items(): + if k == key and v == value: + source[k] = replace_with + elif type(v) is list: + for item in v: + if type(item) is dict: + nested_replace(item, key, value, replace_with) + if type(v) is dict: + nested_replace(v, key, value, replace_with) + + +def inject_schema(schema, remote_ref): + """ + Given a parent schema and a remote ref + + 1. get the remote ref schema + 2. create a local reference name (without path separators) + 3. insert into components.schemas + 4. replace remote references with local references + + + returns True if resolved and injected + """ + local_name = rename_ref(remote_ref) + local_ref = f"#/components/schemas/{local_name}" + ref_schema = resolve_ref(remote_ref) + if (ref_schema is not None): + nested_replace(schema, "$ref", remote_ref, local_ref) + schema["components"]["schemas"][local_name] = ref_schema + return True + else: + return False + + +def import_remote_refs(): + """ + inject the following remote refs into the schema + and replace the remote refs with local refs + + returns True if all schemas resolved and injected + """ + ref_imports = [ + "https://geojson.org/schema/Feature.json", + "https://geojson.org/schema/FeatureCollection.json", + "https://geojson.org/schema/LineString.json", + "https://geojson.org/schema/Point.json", + "https://geojson.org/schema/Polygon.json", + ] + + return all([ + inject_schema(swagger_config, ref) + for ref in ref_imports + ]) + + def configure_flask(swagger_config): """ Setup a flask app, load flasgger @@ -223,6 +312,8 @@ def get_options(): if __name__ == "__main__": + import_remote_refs() + # Parse script args config = get_options() diff --git a/project/soar/swagger.json b/project/soar/swagger.json index 12a468e..46a2b91 100644 --- a/project/soar/swagger.json +++ b/project/soar/swagger.json @@ -111,6 +111,1149 @@ ], "type": "object" }, + "geojson.org.schema.Feature.json": { + "$id": "https://geojson.org/schema/Feature.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "geometry": { + "oneOf": [ + { + "type": "null" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "Point" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Point", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "LineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON LineString", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "Polygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Polygon", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiPoint" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiPoint", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiLineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiLineString", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiPolygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiPolygon", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "geometries": { + "items": { + "oneOf": [ + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "Point" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Point", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "LineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON LineString", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "Polygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Polygon", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiPoint" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiPoint", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiLineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiLineString", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiPolygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiPolygon", + "type": "object" + } + ] + }, + "type": "array" + }, + "type": { + "enum": [ + "GeometryCollection" + ], + "type": "string" + } + }, + "required": [ + "type", + "geometries" + ], + "title": "GeoJSON GeometryCollection", + "type": "object" + } + ] + }, + "id": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "properties": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object" + } + ] + }, + "type": { + "enum": [ + "Feature" + ], + "type": "string" + } + }, + "required": [ + "type", + "properties", + "geometry" + ], + "title": "GeoJSON Feature", + "type": "object" + }, + "geojson.org.schema.FeatureCollection.json": { + "$id": "https://geojson.org/schema/FeatureCollection.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "features": { + "items": { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "geometry": { + "oneOf": [ + { + "type": "null" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "Point" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Point", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "LineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON LineString", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "Polygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Polygon", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiPoint" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiPoint", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiLineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiLineString", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiPolygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiPolygon", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "geometries": { + "items": { + "oneOf": [ + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "Point" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Point", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "LineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON LineString", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "Polygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Polygon", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiPoint" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiPoint", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiLineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiLineString", + "type": "object" + }, + { + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "MultiPolygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON MultiPolygon", + "type": "object" + } + ] + }, + "type": "array" + }, + "type": { + "enum": [ + "GeometryCollection" + ], + "type": "string" + } + }, + "required": [ + "type", + "geometries" + ], + "title": "GeoJSON GeometryCollection", + "type": "object" + } + ] + }, + "id": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "properties": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object" + } + ] + }, + "type": { + "enum": [ + "Feature" + ], + "type": "string" + } + }, + "required": [ + "type", + "properties", + "geometry" + ], + "title": "GeoJSON Feature", + "type": "object" + }, + "type": "array" + }, + "type": { + "enum": [ + "FeatureCollection" + ], + "type": "string" + } + }, + "required": [ + "type", + "features" + ], + "title": "GeoJSON FeatureCollection", + "type": "object" + }, + "geojson.org.schema.LineString.json": { + "$id": "https://geojson.org/schema/LineString.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "LineString" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON LineString", + "type": "object" + }, + "geojson.org.schema.Point.json": { + "$id": "https://geojson.org/schema/Point.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "type": { + "enum": [ + "Point" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Point", + "type": "object" + }, + "geojson.org.schema.Polygon.json": { + "$id": "https://geojson.org/schema/Polygon.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "bbox": { + "items": { + "type": "number" + }, + "minItems": 4, + "type": "array" + }, + "coordinates": { + "items": { + "items": { + "items": { + "type": "number" + }, + "minItems": 2, + "type": "array" + }, + "minItems": 4, + "type": "array" + }, + "type": "array" + }, + "type": { + "enum": [ + "Polygon" + ], + "type": "string" + } + }, + "required": [ + "type", + "coordinates" + ], + "title": "GeoJSON Polygon", + "type": "object" + }, "header": { "discriminator": { "propertyName": "message_type" @@ -468,34 +1611,10 @@ "exclusion_zones": { "description": "Exclusion zones for all platforms", "items": { - "description": "Using GEOJSON, exact 4-point region (rectangle shaped - 5 points)", + "description": "GeoJSON Polygon", "properties": { - "geometry_coordinates": { - "example": [ - [ - [ - -4.1777839187560915, - 50.34173405662855 - ], - [ - -4.1777839187560915, - 50.33820949229701 - ], - [ - -4.143667777943875, - 50.33820949229701 - ], - [ - -4.143667777943875, - 50.34173405662855 - ], - [ - -4.1777839187560915, - 50.34173405662855 - ] - ] - ], - "type": "array" + "geometry": { + "$ref": "#/components/schemas/geojson.org.schema.Polygon.json" } }, "type": "object" @@ -518,34 +1637,10 @@ "region_of_interest": { "description": "Region of interest for the entire operation", "items": { - "description": "Using GEOJSON, exact 4-point region (rectangle shaped - 5 points)", + "description": "GeoJSON Polygon", "properties": { - "geometry_coordinates": { - "example": [ - [ - [ - -4.1777839187560915, - 50.34173405662855 - ], - [ - -4.1777839187560915, - 50.33820949229701 - ], - [ - -4.143667777943875, - 50.33820949229701 - ], - [ - -4.143667777943875, - 50.34173405662855 - ], - [ - -4.1777839187560915, - 50.34173405662855 - ] - ] - ], - "type": "array" + "geometry": { + "$ref": "#/components/schemas/geojson.org.schema.Polygon.json" } }, "type": "object" diff --git a/requirements.txt b/requirements.txt index 738135a..9866dde 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Flask flask-restx flasgger +requests -- GitLab