Skip to content

Commit 2ae14e6

Browse files
committed
feat(spp_api_v2_gis): promote to Beta with validation and exception fixes
Promote spp_api_v2_gis from Alpha to Beta after code review. - Add GeoJSON geometry validation to spatial query and geofence schemas (type must be Polygon/MultiPolygon, coordinates must be non-empty) - Type geofence_type as Literal enum instead of open string - Fix exception chaining: use `from e` instead of `from None` in proximity, statistics, and spatial_query routers for better debugging - Add SPP module icon - Bump version 19.0.2.0.0 -> 19.0.2.0.1 - Update HISTORY.md
1 parent f738582 commit 2ae14e6

10 files changed

Lines changed: 91 additions & 31 deletions

File tree

spp_api_v2_gis/README.rst

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ OpenSPP GIS API
1010
!! source digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
1111
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1212
13-
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
1414
:target: https://odoo-community.org/page/development-status
15-
:alt: Alpha
15+
:alt: Beta
1616
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
1717
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
1818
:alt: License: LGPL-3
@@ -144,10 +144,6 @@ Dependencies
144144
- ``spp_gis_report`` - Report configuration
145145
- ``spp_area`` - Administrative area data
146146

147-
.. IMPORTANT::
148-
This is an alpha version, the data model and design can change at any time without warning.
149-
Only for development or testing purpose, do not use in production.
150-
151147
**Table of contents**
152148

153149
.. contents::
@@ -156,6 +152,16 @@ Dependencies
156152
Changelog
157153
=========
158154

155+
19.0.2.0.1
156+
~~~~~~~~~~
157+
158+
- Promoted to Beta
159+
- fix(schemas): Add GeoJSON geometry validation for spatial queries and
160+
geofences
161+
- fix(routers): Use proper exception chaining (from e) for better
162+
debugging
163+
- feat: Add SPP module icon
164+
159165
19.0.2.0.0
160166
~~~~~~~~~~
161167

spp_api_v2_gis/__manifest__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
{
33
"name": "OpenSPP GIS API",
44
"category": "OpenSPP/Integration",
5-
"version": "19.0.2.0.0",
5+
"version": "19.0.2.0.1",
66
"sequence": 1,
77
"author": "OpenSPP.org",
88
"website": "https://github.com/OpenSPP/OpenSPP2",
99
"license": "LGPL-3",
10-
"development_status": "Alpha",
10+
"development_status": "Beta",
1111
"maintainers": ["jeremi", "gonzalesedwin1123", "reichie020212"],
1212
"depends": [
1313
"spp_api_v2",

spp_api_v2_gis/readme/HISTORY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
### 19.0.2.0.1
2+
3+
- Promoted to Beta
4+
- fix(schemas): Add GeoJSON geometry validation for spatial queries and geofences
5+
- fix(routers): Use proper exception chaining (from e) for better debugging
6+
- feat: Add SPP module icon
7+
18
### 19.0.2.0.0
29

310
- Initial migration to OpenSPP2

spp_api_v2_gis/routers/proximity.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ async def query_proximity(
7272
raise HTTPException(
7373
status_code=status.HTTP_400_BAD_REQUEST,
7474
detail=str(e),
75-
) from None
76-
except Exception:
75+
) from e
76+
except Exception as e:
7777
_logger.exception("Proximity query failed")
7878
raise HTTPException(
7979
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
8080
detail="Proximity query failed",
81-
) from None
81+
) from e

spp_api_v2_gis/routers/spatial_query.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,10 @@ async def query_statistics_batch(
128128
raise HTTPException(
129129
status_code=status.HTTP_400_BAD_REQUEST,
130130
detail=str(e),
131-
) from None
132-
except Exception:
131+
) from e
132+
except Exception as e:
133133
_logger.exception("Batch spatial query failed")
134134
raise HTTPException(
135135
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
136136
detail="Batch spatial query failed",
137-
) from None
137+
) from e

spp_api_v2_gis/routers/statistics.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ async def list_statistics(
8484
total_count=total_count,
8585
)
8686

87-
except Exception:
87+
except Exception as e:
8888
_logger.exception("Failed to list statistics")
8989
raise HTTPException(
9090
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
9191
detail="Failed to list statistics",
92-
) from None
92+
) from e

spp_api_v2_gis/schemas/geofence.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
22
"""Pydantic schemas for Geofence API."""
33

4-
from pydantic import BaseModel, Field
4+
from typing import Literal
5+
6+
from pydantic import BaseModel, Field, field_validator
7+
8+
from .query import _validate_geojson_geometry
59

610

711
class GeofenceCreateRequest(BaseModel):
@@ -10,7 +14,15 @@ class GeofenceCreateRequest(BaseModel):
1014
name: str = Field(..., description="Name of the geofence")
1115
description: str | None = Field(default=None, description="Description of the geofence")
1216
geometry: dict = Field(..., description="Geometry as GeoJSON (Polygon or MultiPolygon)")
13-
geofence_type: str = Field(default="custom", description="Type of geofence")
17+
geofence_type: Literal["hazard_zone", "service_area", "targeting_area", "custom"] = Field(
18+
default="custom", description="Type of geofence"
19+
)
20+
21+
@field_validator("geometry")
22+
@classmethod
23+
def check_geometry(cls, v):
24+
return _validate_geojson_geometry(v)
25+
1426
incident_code: str | None = Field(default=None, description="Related incident code")
1527

1628

spp_api_v2_gis/schemas/query.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,36 @@
33

44
from typing import Literal
55

6-
from pydantic import BaseModel, Field
6+
from pydantic import BaseModel, Field, field_validator
7+
8+
_VALID_GEOMETRY_TYPES = {"Polygon", "MultiPolygon"}
9+
10+
11+
def _validate_geojson_geometry(v):
12+
"""Validate that a dict is a valid GeoJSON geometry (Polygon or MultiPolygon)."""
13+
if not isinstance(v, dict):
14+
raise ValueError("geometry must be a JSON object")
15+
geo_type = v.get("type")
16+
if not geo_type:
17+
raise ValueError("geometry must have a 'type' field")
18+
if geo_type not in _VALID_GEOMETRY_TYPES:
19+
raise ValueError(f"geometry type must be one of {_VALID_GEOMETRY_TYPES}, got '{geo_type}'")
20+
coords = v.get("coordinates")
21+
if not coords or not isinstance(coords, list):
22+
raise ValueError("geometry must have a non-empty 'coordinates' array")
23+
return v
724

825

926
class SpatialQueryRequest(BaseModel):
1027
"""Request for spatial query."""
1128

1229
geometry: dict = Field(..., description="Query geometry as GeoJSON (Polygon or MultiPolygon)")
30+
31+
@field_validator("geometry")
32+
@classmethod
33+
def check_geometry(cls, v):
34+
return _validate_geojson_geometry(v)
35+
1336
filters: dict | None = Field(default=None, description="Additional filters for registrants")
1437
variables: list[str] | None = Field(
1538
default=None,
@@ -50,6 +73,11 @@ class GeometryItem(BaseModel):
5073
id: str = Field(..., description="Unique identifier for this geometry (e.g., feature ID)")
5174
geometry: dict = Field(..., description="GeoJSON geometry (Polygon or MultiPolygon)")
5275

76+
@field_validator("geometry")
77+
@classmethod
78+
def check_geometry(cls, v):
79+
return _validate_geojson_geometry(v)
80+
5381

5482
class BatchSpatialQueryRequest(BaseModel):
5583
"""Request for batch spatial query across multiple geometries."""
15.1 KB
Loading

spp_api_v2_gis/static/description/index.html

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ <h1 class="title">OpenSPP GIS API</h1>
369369
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
370370
!! source digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
371371
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
372-
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Alpha" src="https://img.shields.io/badge/maturity-Alpha-red.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/license-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OpenSPP/OpenSPP2/tree/19.0/spp_api_v2_gis"><img alt="OpenSPP/OpenSPP2" src="https://img.shields.io/badge/github-OpenSPP%2FOpenSPP2-lightgray.png?logo=github" /></a></p>
372+
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/license-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OpenSPP/OpenSPP2/tree/19.0/spp_api_v2_gis"><img alt="OpenSPP/OpenSPP2" src="https://img.shields.io/badge/github-OpenSPP%2FOpenSPP2-lightgray.png?logo=github" /></a></p>
373373
<p>REST API for QGIS plugin integration, providing OGC API - Features
374374
endpoints, spatial queries, and geofence management.</p>
375375
<div class="section" id="key-features">
@@ -548,41 +548,48 @@ <h1>Dependencies</h1>
548548
<li><tt class="docutils literal">spp_gis_report</tt> - Report configuration</li>
549549
<li><tt class="docutils literal">spp_area</tt> - Administrative area data</li>
550550
</ul>
551-
<div class="admonition important">
552-
<p class="first admonition-title">Important</p>
553-
<p class="last">This is an alpha version, the data model and design can change at any time without warning.
554-
Only for development or testing purpose, do not use in production.</p>
555-
</div>
556551
<p><strong>Table of contents</strong></p>
557552
<div class="contents local topic" id="contents">
558553
<ul class="simple">
559554
<li><a class="reference internal" href="#changelog" id="toc-entry-1">Changelog</a><ul>
560-
<li><a class="reference internal" href="#section-1" id="toc-entry-2">19.0.2.0.0</a></li>
555+
<li><a class="reference internal" href="#section-1" id="toc-entry-2">19.0.2.0.1</a></li>
556+
<li><a class="reference internal" href="#section-2" id="toc-entry-3">19.0.2.0.0</a></li>
561557
</ul>
562558
</li>
563-
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li>
564-
<li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a></li>
559+
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-4">Bug Tracker</a></li>
560+
<li><a class="reference internal" href="#credits" id="toc-entry-5">Credits</a></li>
565561
</ul>
566562
</div>
567563
<div class="section" id="changelog">
568564
<h2><a class="toc-backref" href="#toc-entry-1">Changelog</a></h2>
569565
<div class="section" id="section-1">
570-
<h3><a class="toc-backref" href="#toc-entry-2">19.0.2.0.0</a></h3>
566+
<h3><a class="toc-backref" href="#toc-entry-2">19.0.2.0.1</a></h3>
567+
<ul class="simple">
568+
<li>Promoted to Beta</li>
569+
<li>fix(schemas): Add GeoJSON geometry validation for spatial queries and
570+
geofences</li>
571+
<li>fix(routers): Use proper exception chaining (from e) for better
572+
debugging</li>
573+
<li>feat: Add SPP module icon</li>
574+
</ul>
575+
</div>
576+
<div class="section" id="section-2">
577+
<h3><a class="toc-backref" href="#toc-entry-3">19.0.2.0.0</a></h3>
571578
<ul class="simple">
572579
<li>Initial migration to OpenSPP2</li>
573580
</ul>
574581
</div>
575582
</div>
576583
<div class="section" id="bug-tracker">
577-
<h2><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h2>
584+
<h2><a class="toc-backref" href="#toc-entry-4">Bug Tracker</a></h2>
578585
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OpenSPP/OpenSPP2/issues">GitHub Issues</a>.
579586
In case of trouble, please check there if your issue has already been reported.
580587
If you spotted it first, help us to smash it by providing a detailed and welcomed
581588
<a class="reference external" href="https://github.com/OpenSPP/OpenSPP2/issues/new?body=module:%20spp_api_v2_gis%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
582589
<p>Do not contact contributors directly about support or help with technical issues.</p>
583590
</div>
584591
<div class="section" id="credits">
585-
<h2><a class="toc-backref" href="#toc-entry-4">Credits</a></h2>
592+
<h2><a class="toc-backref" href="#toc-entry-5">Credits</a></h2>
586593
</div>
587594
</div>
588595
<div class="section" id="authors">

0 commit comments

Comments
 (0)