Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a440b55
feat: integrate pygeoapi for OGC API - Features endpoints and update …
jirhiker Feb 24, 2026
a427cd6
Formatting changes
jirhiker Feb 24, 2026
9bdaaca
Potential fix for code scanning alert no. 17: Clear-text storage of s…
jirhiker Feb 24, 2026
d96b6c1
Update core/pygeoapi.py
jirhiker Feb 24, 2026
04d05b5
feat: enhance pygeoapi configuration with new thing collections and s…
jirhiker Feb 24, 2026
2997de2
Formatting changes
jirhiker Feb 24, 2026
d635162
fix: update pygeoapi configuration to use environment variable for Po…
jirhiker Feb 24, 2026
a2e8f57
feat: create supporting views for pygeoapi OGC API integration
jirhiker Feb 25, 2026
87d1b9e
Formatting changes
jirhiker Feb 25, 2026
b7baeda
Update core/pygeoapi.py
jirhiker Feb 25, 2026
64eeb02
Update core/pygeoapi.py
jirhiker Feb 25, 2026
77968de
feat: update pygeoapi configuration to use environment variables for …
jirhiker Feb 25, 2026
de1ace4
feat(transfers): add permissions transfer functionality and update co…
jirhiker Feb 25, 2026
d4da8ff
feat: update pygeoapi supporting views and enhance thing collections …
jirhiker Feb 25, 2026
b356c7a
feat: update environment variable references for PostgreSQL settings …
jirhiker Feb 25, 2026
ffd30e4
Formatting changes
jirhiker Feb 25, 2026
9c74fac
feat: change views to materialized views for depth and TDS data in py…
jirhiker Feb 25, 2026
4923c1e
feat: refactor app initialization to import from main module
jirhiker Feb 25, 2026
2ad195f
feat: add refresh command for pygeoapi materialized views and schedul…
jirhiker Feb 25, 2026
9a5e01e
Formatting changes
jirhiker Feb 25, 2026
c8d6957
feat: enhance test workflow by adding database readiness checks and p…
jirhiker Feb 25, 2026
dc424cf
feat: add Dockerfile to set up PostGIS with pg_cron for scheduled tasks
jirhiker Feb 26, 2026
131f46e
Update alembic/versions/d5e6f7a8b9c0_create_pygeoapi_supporting_views.py
jirhiker Feb 26, 2026
d7d5880
Update db/initialization.py
jirhiker Feb 26, 2026
92e031c
Update core/pygeoapi.py
jirhiker Feb 26, 2026
9cae52a
Update alembic/versions/d5e6f7a8b9c0_create_pygeoapi_supporting_views.py
jirhiker Feb 26, 2026
36b5bb5
feat: update endpoint paths from /oapi to /ogcapi and improve pg_cron…
jirhiker Feb 26, 2026
b94c565
Formatting changes
jirhiker Feb 26, 2026
c8b31ce
feat: rename wells collection to water_wells for consistency
jirhiker Feb 26, 2026
627a27b
feat: ensure feature IDs are consistently treated as strings in tests
jirhiker Feb 26, 2026
42e93d2
Update cli/cli.py
jirhiker Feb 26, 2026
5e26ba3
Formatting changes
jirhiker Feb 26, 2026
c799ed5
feat: update API endpoint paths from /oapi to /ogcapi and set default…
jirhiker Feb 26, 2026
7c9bd47
feat: update OGC API endpoint path and add unique indexes for materia…
jirhiker Feb 26, 2026
2d40419
feat: enhance test for refreshing materialized views with execution o…
jirhiker Feb 26, 2026
c0c911a
Formatting changes
jirhiker Feb 26, 2026
2bb0032
feat: refactor test connection context management in CLI commands
jirhiker Feb 26, 2026
b3248ab
Update cli/cli.py
jirhiker Feb 26, 2026
41d16c1
Update tests/conftest.py
jirhiker Feb 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ TRANSFER_PARALLEL=1
TRANSFER_WELL_SCREENS=True
TRANSFER_SENSORS=True
TRANSFER_CONTACTS=True
TRANSFER_PERMISSIONS=True
TRANSFER_WATERLEVELS=True
TRANSFER_WATERLEVELS_PRESSURE=True
TRANSFER_WATERLEVELS_ACOUSTIC=True
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/CD_production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ jobs:
CLOUD_SQL_INSTANCE_NAME: "${{ secrets.CLOUD_SQL_INSTANCE_NAME }}"
CLOUD_SQL_DATABASE: "${{ vars.CLOUD_SQL_DATABASE }}"
CLOUD_SQL_USER: "${{ secrets.CLOUD_SQL_USER }}"
PYGEOAPI_POSTGRES_DB: "${{ vars.CLOUD_SQL_DATABASE }}"
PYGEOAPI_POSTGRES_USER: "${{ secrets.PYGEOAPI_POSTGRES_USER }}"
PYGEOAPI_POSTGRES_HOST: "${{ vars.PYGEOAPI_POSTGRES_HOST || '127.0.0.1' }}"
PYGEOAPI_POSTGRES_PORT: "${{ vars.PYGEOAPI_POSTGRES_PORT || '5432' }}"
PYGEOAPI_POSTGRES_PASSWORD: "${{ secrets.PYGEOAPI_POSTGRES_PASSWORD }}"
CLOUD_SQL_IAM_AUTH: true
run: |
uv run alembic upgrade head
Expand All @@ -66,6 +71,11 @@ jobs:
CLOUD_SQL_INSTANCE_NAME: "${{ secrets.CLOUD_SQL_INSTANCE_NAME }}"
CLOUD_SQL_DATABASE: "${{ vars.CLOUD_SQL_DATABASE }}"
CLOUD_SQL_USER: "${{ secrets.CLOUD_SQL_USER }}"
PYGEOAPI_POSTGRES_DB: "${{ vars.CLOUD_SQL_DATABASE }}"
PYGEOAPI_POSTGRES_USER: "${{ secrets.PYGEOAPI_POSTGRES_USER }}"
PYGEOAPI_POSTGRES_HOST: "${{ vars.PYGEOAPI_POSTGRES_HOST || '127.0.0.1' }}"
PYGEOAPI_POSTGRES_PORT: "${{ vars.PYGEOAPI_POSTGRES_PORT || '5432' }}"
PYGEOAPI_POSTGRES_PASSWORD: "${{ secrets.PYGEOAPI_POSTGRES_PASSWORD }}"
CLOUD_SQL_IAM_AUTH: true
GCS_SERVICE_ACCOUNT_KEY: "${{ secrets.GCS_SERVICE_ACCOUNT_KEY }}"
GCS_BUCKET_NAME: "${{ vars.GCS_BUCKET_NAME }}"
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/CD_staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ jobs:
CLOUD_SQL_INSTANCE_NAME: "${{ secrets.CLOUD_SQL_INSTANCE_NAME }}"
CLOUD_SQL_DATABASE: "${{ vars.CLOUD_SQL_DATABASE }}"
CLOUD_SQL_USER: "${{ secrets.CLOUD_SQL_USER }}"
PYGEOAPI_POSTGRES_DB: "${{ vars.CLOUD_SQL_DATABASE }}"
PYGEOAPI_POSTGRES_USER: "${{ secrets.PYGEOAPI_POSTGRES_USER }}"
PYGEOAPI_POSTGRES_HOST: "${{ vars.PYGEOAPI_POSTGRES_HOST || '127.0.0.1' }}"
PYGEOAPI_POSTGRES_PORT: "${{ vars.PYGEOAPI_POSTGRES_PORT || '5432' }}"
PYGEOAPI_POSTGRES_PASSWORD: "${{ secrets.PYGEOAPI_POSTGRES_PASSWORD }}"
CLOUD_SQL_IAM_AUTH: true
run: |
uv run alembic upgrade head
Expand All @@ -67,6 +72,11 @@ jobs:
CLOUD_SQL_INSTANCE_NAME: "${{ secrets.CLOUD_SQL_INSTANCE_NAME }}"
CLOUD_SQL_DATABASE: "${{ vars.CLOUD_SQL_DATABASE }}"
CLOUD_SQL_USER: "${{ secrets.CLOUD_SQL_USER }}"
PYGEOAPI_POSTGRES_DB: "${{ vars.CLOUD_SQL_DATABASE }}"
PYGEOAPI_POSTGRES_USER: "${{ secrets.PYGEOAPI_POSTGRES_USER }}"
PYGEOAPI_POSTGRES_HOST: "${{ vars.PYGEOAPI_POSTGRES_HOST || '127.0.0.1' }}"
PYGEOAPI_POSTGRES_PORT: "${{ vars.PYGEOAPI_POSTGRES_PORT || '5432' }}"
PYGEOAPI_POSTGRES_PASSWORD: "${{ secrets.PYGEOAPI_POSTGRES_PASSWORD }}"
CLOUD_SQL_IAM_AUTH: true
GCS_SERVICE_ACCOUNT_KEY: "${{ secrets.GCS_SERVICE_ACCOUNT_KEY }}"
GCS_BUCKET_NAME: "${{ vars.GCS_BUCKET_NAME }}"
Expand Down
97 changes: 58 additions & 39 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,38 @@ jobs:
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
PYGEOAPI_POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PYGEOAPI_POSTGRES_PASSWORD: postgres
POSTGRES_DB: ocotilloapi_test
PYGEOAPI_POSTGRES_HOST: localhost
PYGEOAPI_POSTGRES_PORT: 5432
PYGEOAPI_POSTGRES_DB: ocotilloapi_test
DB_DRIVER: postgres
BASE_URL: http://localhost:8000
SESSION_SECRET_KEY: supersecretkeyforunittests
AUTHENTIK_DISABLE_AUTHENTICATION: 1

services:
postgis:
image: postgis/postgis:17-3.5
# don't test against latest. be explicit in version being tested to avoid breaking changes
# image: postgis/postgis:latest

# These env vars are ONLY for the service container itself
env:
POSTGRES_PASSWORD: postgres
POSTGRES_PORT: 5432

options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432

steps:
- name: Check out source repository
uses: actions/checkout@v6.0.2

- name: Start database (PostGIS + pg_cron)
run: |
docker compose build db
docker compose up -d db

- name: Wait for database readiness
run: |
for i in {1..60}; do
if PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c "SELECT 1" >/dev/null 2>&1; then
exit 0
fi
sleep 2
done
echo "Database did not become ready in time"
exit 1

- name: Install uv
uses: astral-sh/setup-uv@v7.3.0
with:
Expand All @@ -76,10 +76,12 @@ jobs:
- name: Show Alembic heads
run: uv run alembic heads

- name: Create test database
- name: Create test database and extensions
run: |
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -c "CREATE DATABASE ocotilloapi_test"
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = 'ocotilloapi_test'" | grep -q 1 || \
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -c "CREATE DATABASE ocotilloapi_test"
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d ocotilloapi_test -c "CREATE EXTENSION IF NOT EXISTS postgis"
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d ocotilloapi_test -c "CREATE EXTENSION IF NOT EXISTS pg_cron"

- name: Run tests
run: uv run pytest -vv --durations=20 --cov --cov-report=xml --junitxml=junit.xml --ignore=tests/transfers
Expand All @@ -90,6 +92,10 @@ jobs:
report_type: test_results
token: ${{ secrets.CODECOV_TOKEN }}

- name: Stop database
if: always()
run: docker compose down -v

bdd-tests:
runs-on: ubuntu-latest

Expand All @@ -98,32 +104,39 @@ jobs:
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
PYGEOAPI_POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PYGEOAPI_POSTGRES_PASSWORD: postgres
POSTGRES_DB: ocotilloapi_test
PYGEOAPI_POSTGRES_HOST: localhost
PYGEOAPI_POSTGRES_PORT: 5432
PYGEOAPI_POSTGRES_DB: ocotilloapi_test
DB_DRIVER: postgres
BASE_URL: http://localhost:8000
SESSION_SECRET_KEY: supersecretkeyforunittests
AUTHENTIK_DISABLE_AUTHENTICATION: 1
DROP_AND_REBUILD_DB: 1

services:
postgis:
image: postgis/postgis:17-3.5
env:
POSTGRES_PASSWORD: postgres
POSTGRES_PORT: 5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- name: Check out source repository
uses: actions/checkout@v6.0.2

- name: Start database (PostGIS + pg_cron)
run: |
docker compose build db
docker compose up -d db

- name: Wait for database readiness
run: |
for i in {1..60}; do
if PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c "SELECT 1" >/dev/null 2>&1; then
exit 0
fi
sleep 2
done
echo "Database did not become ready in time"
exit 1

- name: Install uv
uses: astral-sh/setup-uv@v7.3.0
with:
Expand All @@ -149,10 +162,16 @@ jobs:
- name: Show Alembic heads
run: uv run alembic heads

- name: Create test database
- name: Create test database and extensions
run: |
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -c "CREATE DATABASE ocotilloapi_test"
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = 'ocotilloapi_test'" | grep -q 1 || \
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -c "CREATE DATABASE ocotilloapi_test"
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d ocotilloapi_test -c "CREATE EXTENSION IF NOT EXISTS postgis"
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d ocotilloapi_test -c "CREATE EXTENSION IF NOT EXISTS pg_cron"

- name: Run BDD tests
run: uv run behave tests/features --tags="@backend and @production and not @skip" --no-capture

- name: Stop database
if: always()
run: docker compose down -v
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ run_bdd-local.sh
.pre-commit-config.local.yaml
.serena/
cli/logs

.pygeoapi/
# deployment files
app.yaml
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,6 @@ GitHub Actions workflows (`.github/workflows/`):
## Additional Resources

- **API Docs**: `http://localhost:8000/docs` (Swagger UI) or `/redoc` (ReDoc)
- **OGC API**: `http://localhost:8000/ogc` for OGC API - Features endpoints
- **OGC API**: `http://localhost:8000/ogcapi` for OGC API - Features endpoints
- **CLI**: `oco --help` for Ocotillo CLI commands
- **Sentry**: Error tracking and performance monitoring integrated
33 changes: 14 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,50 +27,45 @@ supports research, field operations, and public data delivery for the Bureau of

## 🗺️ OGC API - Features

The API exposes OGC API - Features endpoints under `/ogc`.
The API exposes OGC API - Features endpoints under `/ogcapi` using `pygeoapi`.

### Landing & metadata

```bash
curl http://localhost:8000/ogc
curl http://localhost:8000/ogc/conformance
curl http://localhost:8000/ogc/collections
curl http://localhost:8000/ogc/collections/locations
curl http://localhost:8000/ogcapi
curl http://localhost:8000/ogcapi/conformance
curl http://localhost:8000/ogcapi/collections
curl http://localhost:8000/ogcapi/collections/locations
```

### Items (GeoJSON)

```bash
curl "http://localhost:8000/ogc/collections/locations/items?limit=10&offset=0"
curl "http://localhost:8000/ogc/collections/wells/items?limit=5"
curl "http://localhost:8000/ogc/collections/springs/items?limit=5"
curl "http://localhost:8000/ogc/collections/locations/items/123"
curl "http://localhost:8000/ogcapi/collections/locations/items?limit=10&offset=0"
curl "http://localhost:8000/ogcapi/collections/wells/items?limit=5"
curl "http://localhost:8000/ogcapi/collections/springs/items?limit=5"
curl "http://localhost:8000/ogcapi/collections/locations/items/123"
```

### BBOX + datetime filters

```bash
curl "http://localhost:8000/ogc/collections/locations/items?bbox=-107.9,33.8,-107.8,33.9"
curl "http://localhost:8000/ogc/collections/wells/items?datetime=2020-01-01/2024-01-01"
curl "http://localhost:8000/ogcapi/collections/locations/items?bbox=-107.9,33.8,-107.8,33.9"
curl "http://localhost:8000/ogcapi/collections/wells/items?datetime=2020-01-01/2024-01-01"
```

### Polygon filter (CQL2 text)

Use `filter` + `filter-lang=cql2-text` with `WITHIN(...)`:

```bash
curl "http://localhost:8000/ogc/collections/locations/items?filter=WITHIN(geometry,POLYGON((-107.9 33.8,-107.8 33.8,-107.8 33.9,-107.9 33.9,-107.9 33.8)))&filter-lang=cql2-text"
curl "http://localhost:8000/ogcapi/collections/locations/items?filter=WITHIN(geometry,POLYGON((-107.9 33.8,-107.8 33.8,-107.8 33.9,-107.9 33.9,-107.9 33.8)))&filter-lang=cql2-text"
```

### Property filter (CQL)

Basic property filters are supported with `properties`:
### OpenAPI UI

```bash
curl "http://localhost:8000/ogc/collections/wells/items?properties=thing_type='water well' AND well_depth>=100 AND well_depth<=200"
curl "http://localhost:8000/ogc/collections/wells/items?properties=well_purposes IN ('domestic','irrigation')"
curl "http://localhost:8000/ogc/collections/wells/items?properties=well_casing_materials='PVC'"
curl "http://localhost:8000/ogc/collections/wells/items?properties=well_screen_type='Steel'"
curl "http://localhost:8000/ogcapi/openapi?ui=swagger"
```


Expand Down
Loading