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

Add project properties support #81

Open
wants to merge 1 commit 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
49 changes: 48 additions & 1 deletion qsa-api/qsa_api/api/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,53 @@ def project_info(name: str):
return {"error": "internal server error"}, 415


@projects.get("/<name>/properties")
def project_properties(name: str):
log_request()
try:
psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)

if project.exists():
return jsonify(project.properties)
return {"error": "Project does not exist"}, 415
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415


@projects.post("/<name>/properties")
def project_properties_update(name: str):
log_request()
try:
schema = {
"type": "object",
"required": [],
"properties": {
},
}

psql_schema = request.args.get("schema", default="public")
project = QSAProject(name, psql_schema)
if project.exists():
data = request.get_json()
try:
validate(data, schema)
except ValidationError as e:
return {"error": e.message}, 415

rc, err = project.properties_update(data)
if rc:
return jsonify(rc), 201
else:
return {"error": err}, 415
else:
return {"error": "Project does not exist"}, 415
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415


@projects.post("/")
def project_add():
log_request()
Expand Down Expand Up @@ -156,7 +203,7 @@ def project_del_style(name, style):
return {"error": "Project does not exist"}, 415
except Exception as e:
logger().exception(str(e))
return {"error": "internal server error"}, 415
return {"error": "internal server error"}, 414


@projects.post("/<name>/layers/<layer_name>/style")
Expand Down
22 changes: 19 additions & 3 deletions qsa-api/qsa_api/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,12 @@
)

from .mapproxy import QSAMapProxy
from .properties import ProjectProperties
from .vector import VectorSymbologyRenderer
from .utils import StorageBackend, config, logger
from .raster import RasterSymbologyRenderer, RasterOverview


RENDERER_TAG_NAME = "renderer-v2" # constant from core/symbology/renderer.h


class QSAProject:
def __init__(self, name: str, schema: str = "public") -> None:
self.name: str = name
Expand All @@ -63,6 +61,12 @@ def sqlite_db(self) -> Path:
con.close()
return p

@property
def properties(self) -> dict:
props = ProjectProperties()
props.read(self.project)
return props.to_json()

@staticmethod
def projects(schema: str = "") -> list:
p = []
Expand Down Expand Up @@ -136,6 +140,18 @@ def metadata(self) -> dict:

return m

def properties_update(self, data) -> bool:
project = self.project

properties = ProjectProperties()
properties.read(project)
rc, err = properties.update(data)
if rc:
properties.write(project)
project.write()

return rc, err

def cache_metadata(self) -> (dict, str):
if self._mapproxy_enabled:
return QSAMapProxy(self.name).metadata(), ""
Expand Down
77 changes: 77 additions & 0 deletions qsa-api/qsa_api/properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# coding: utf8

from qgis.core import QgsProject


class _Property:
def __init__(self, scope: str, key: str, entry_type, default):
self.scope = scope
self.key = key
self.type = entry_type
self.default = default
self._value = self.default

@property
def value(self):
return self._value

@value.setter
def value(self, v):
self._value = self.type(v)

def update(self, project):
meth = None
if self.type == bool:
meth = project.readBoolEntry
elif self.type == int:
meth = project.readNumEntry

if meth:
self.value = meth(self.scope, self.key, self.default)[0]


class ProjectProperties:
def __init__(self) -> None:
self.props = {}

# WMS project properties
wms = {}

prop = _Property("WMSAddWktGeometry", "/", bool, False)
wms["getfeatureinfo_geometry"] = prop

prop = _Property("WMSPrecision", "/", int, 8)
wms["getfeatureinfo_geometry_precision"] = prop

self.props["wms"] = wms

def to_json(self):
d = {}
d["wms"] = {}
for key in self.props["wms"]:
d["wms"][key] = self.props["wms"][key].value
return d

def read(self, project):
for key in self.props:
for subkey in self.props[key]:
self.props[key][subkey].update(project)

def update(self, data) -> (bool, str):
for key in data:
if key not in self.props:
return False, f"Unsupported key '{key}'"

for subkey in data[key]:
if subkey not in self.props[key]:
return False, f"Unsupported key '{subkey}'"

self.props[key][subkey].value = data[key][subkey]

return True, ""

def write(self, project) -> (bool, str):
for key in self.props:
for subkey in self.props[key]:
prop = self.props[key][subkey]
project.writeEntry(prop.scope, prop.key, prop.value)
Loading