Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable WMS / WFS publication #75

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
64 changes: 60 additions & 4 deletions docs/src/qsa-api/endpoints/projects.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,25 @@ empty.
| POST | `/api/projects/{project}/layers` | Add layer to project. See [Layer definition](#layer-definition) for more information. |
| POST | `/api/projects/{project}/layers/{layer}/style` | Add/Update layer's style with `name` (style name) and `current` (`true` or `false`) |
| DELETE | `/api/projects/{project}/layers/{layer}` | Remove layer from project |
| GET | `/api/projects/{project}/layers/wms` | List all published WMS layers |
| GET | `/api/projects/{project}/layers/wms/feature-info`| List WMS Feature Info settings |
| POST | `/api/projects/{project}/layers/wms/feature-info`| Change WMS Feature Info settings |
| GET | `/api/projects/{project}/layers/{layer}/wms` | List a published WMS layer's metadata |
| POST | `/api/projects/{project}/layers/{layer}/wms` | Toggle WMS publication status of an existing layer |
| GET | `/api/projects/{project}/layers/wfs` | List all published WFS layers |
| GET | `/api/projects/{project}/layers/{layer}/wfs` | List a published WFS layer's metadata |
| POST | `/api/projects/{project}/layers/{layer}/wfs` | Toggle WFS publication status of an existing vector layer |

#### Layer definition {#layer-definition}
### Layer definition {#layer-definition}

A layer can be added to a project thanks to the next parameters:

- `type` : `raster` or `vector`
- `name` : the layer's name
- `datasource` : the link to the datasource according to the storage backend
- filesystem : `/tmp/raster.tif`
- AWS S3 : `/vsis3/bucket/raster.tif`
- PostGIS : `service=qsa table=\"public\".\"lines\" (geom)`
- filesystem : `/tmp/raster.tif`
- AWS S3 : `/vsis3/bucket/raster.tif`
- PostGIS : `service=qsa table=\"public\".\"lines\" (geom)`
- `overview` (optional) : automatically build overviews for raster layers stored in S3 buckets
- `crs` (optional) : CRS (automatically detected by default)

Expand All @@ -81,6 +89,54 @@ $ curl "http://localhost/api/projects/my_project/layers" \
}'
````

### WMS

### Publication

QGIS Server publishes WMS layers automatically. These parameters are needed to change the publication status of a layer:

- `published` : If the layer shall be published as boolean. Allowed values: `true`, `false`

```` shell
$ curl "http://localhost/api/projects/my_project/layers/my_layer/wms" \
-X POST \
-H 'Content-Type: application/json' \
-d '{
"published": false
}'
````

### Feature Info

By default QGIS Server does not send the geometry on a WMS Feature Info request. This can be changed with this configuration:

- `publish_geometry`: If WMS Feature Info request shall return the geometry. Allowed values: `true`, `false`

```` shell
$ curl "http://localhost/api/projects/my_project/layers/wms/feature-info" \
-X POST \
-H 'Content-Type: application/json' \
-d '{
"publish_geometry": true
}'
````

### WFS Publication

These parameters are needed to publish an existing vector layer as WFS:

- `published` : If the layer shall be published as boolean. Allowed values: `true`, `false`
- `geometry_precision` (optional) : the geometric precision as integer, default is `8`

```` shell
$ curl "http://localhost/api/projects/my_project/layers/my_layer/wfs" \
-X POST \
-H 'Content-Type: application/json' \
-d '{
"published": true
}'
````

## Style

A QSA style may be used through the `STYLE` OGC web services parameter to
Expand Down
217 changes: 217 additions & 0 deletions qsa-api/qsa_api/api/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,224 @@ def project_info_layer(name, layer_name):
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415

@projects.get("/<name>/layers/wms")
def project_layers_wms(name):
"""
Get all published WMS layers
"""
log_request()
try:
psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)
if project.exists():
return jsonify(project.layers_wms), 201
else:
return {"error": "Project does not exist"}, 415
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415

@projects.get("/<name>/layers/wms/feature-info")
def project_wms_feature_info(name):
"""
Information about the WMS Feature Info settings
"""
log_request()
try:
psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)
if project.exists():
return jsonify(project.project_wms_feature_info), 201
else:
return {"error": "Project does not exist"}, 415
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415


@projects.get("/<name>/layers/wfs")
def project_layers_wfs(name):
"""
Get all published WFS layers
"""
log_request()
try:
psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)
if project.exists():
return jsonify(project.layers_wfs_info), 201
else:
return {"error": "Project does not exist"}, 415
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415

@projects.get("/<name>/layers/<layer_name>/wfs")
def project_info_layer_wfs(name, layer_name):
"""
Get information about a single WFS layer
"""
log_request()
try:
psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)
if project.exists():
return jsonify(project.layer_wfs(layer_name)), 201
else:
return {"error": "Project does not exist"}, 415
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415

@projects.get("/<name>/layers/<layer_name>/wms")
def project_info_layer_wms(name, layer_name):
"""
Get information about a single WMS layer
"""
log_request()
try:
psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)
if project.exists():
return jsonify(project.layer_wms(layer_name)), 201
else:
return {"error": "Project does not exist"}, 415
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415

@projects.post("/<name>/layers/<layer_name>/wfs")
def project_publish_wfs_layer(name, layer_name):
"""
Change WFS publication status of an vector layer
"""
log_request()
try:
json_schema = {
"type": "object",
"required": ["published"],
"properties": {
"published": {"type": "boolean"},
"geometry_precision": {"type": "integer"}
},
}

psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)

if project.exists():
data = request.get_json()
try:
validate(data, json_schema)
except ValidationError as e:
return {"error": e.message}, 415

published = data["published"]

geometry_precision = 8 # default value in QGIS Server

if "geometry_precision" in data:
geometry_precision = data["geometry_precision"]

project = QSAProject(name, psql_schema)

rc, err = project.publish_wfs_layer(layer_name, published, geometry_precision)

if err:
return {"error": err}, 415
return jsonify(rc), 201

else:
return {"error": "Project does not exist"}, 415

except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415

@projects.post("/<name>/layers/<layer_name>/wms")
def project_publish_wms_layer(name, layer_name):
"""
Change WMS publication status of an vector layer
"""
log_request()
try:
json_schema = {
"type": "object",
"required": ["published"],
"properties": {
"published": {"type": "boolean"}
},
}

psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)

if project.exists():
data = request.get_json()
try:
validate(data, json_schema)
except ValidationError as e:
return {"error": e.message}, 415

published = data["published"]

project = QSAProject(name, psql_schema)

rc, err = project.publish_wms_layer(layer_name, published)

if err:
return {"error": err}, 415
return jsonify(rc), 201

else:
return {"error": "Project does not exist"}, 415

except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415

@projects.post("/<name>/layers/wms/feature-info")
def project_wms_adjust_feature_info(name):
"""
Adjust the WMS Feature Info settings
"""
log_request()
try:
json_schema = {
"type": "object",
"required": ["publish_geometry"],
"properties": {
"publish_geometry": {"type": "boolean"}
},
}

psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)

if project.exists():
data = request.get_json()
try:
validate(data, json_schema)
except ValidationError as e:
return {"error": e.message}, 415

publish_geometry = data["publish_geometry"]

project = QSAProject(name, psql_schema)

rc, err = project.wms_adjust_feature_info(publish_geometry)

if err:
return {"error": err}, 415
return jsonify(rc), 201

else:
return {"error": "Project does not exist"}, 415

except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415

@projects.delete("/<name>/layers/<layer_name>")
def project_del_layer(name, layer_name):
Expand Down
Loading
Loading