Skip to content

Instantly share code, notes, and snippets.

@leodc
Last active June 26, 2018 16:53
Show Gist options
  • Save leodc/d7f9228884f87bf803d419ad65d3fbf2 to your computer and use it in GitHub Desktop.
Save leodc/d7f9228884f87bf803d419ad65d3fbf2 to your computer and use it in GitHub Desktop.
Help script to publish postgis tables to geoserver
#!/usr/bin/python3
import os
import sys
import psycopg2
import subprocess
import urllib.request
import json
POSTGRES_DBNAME = os.getenv("POSTGRES_DBNAME")
POSTGRES_USER = os.getenv("POSTGRES_USER")
POSTGRES_HOST = os.getenv("POSTGRES_HOST")
POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD")
POSTGRES_PORT = os.getenv("POSTGRES_PORT")
GEOSERVER_DATASTORE = os.getenv("GEOSERVER_DATASTORE")
GEOSERVER_WORKSPACE = os.getenv("GEOSERVER_WORKSPACE")
GEOSERVER_REST = os.getenv("GEOSERVER_REST")
GEOSERVER_USER = os.getenv("GEOSERVER_USER")
GEOSERVER_PASSWORD = os.getenv("GEOSERVER_PASSWORD")
MAX_LAYERS = os.getenv("MAX_LAYERS")
CKAN_API = "https://datos.gob.mx/ckan-admin/api/3/action/package_show?id="
DGM_API = "https://api.datos.gob.mx/v1/resources?id="
def main():
# create connection
conn = initConnection()
cursor = conn.cursor()
# get postgis tables name
cursor.execute( "select relname from pg_stat_user_tables;" )
tables = cursor.fetchall()
boundingBoxQuery = "SELECT ST_XMin(ST_Extent(the_geom)) AS min_x,\
ST_XMax(ST_Extent(the_geom)) AS max_x,\
ST_YMin(ST_Extent(the_geom)) AS min_y,\
ST_YMax(ST_Extent(the_geom)) AS max_y FROM \"{}\""
skip = ["spatial_ref_sys"]
counter = 0
for table in tables:
layerName = table[0]
# layer to process
if layerName not in skip:
print("Layer {count} - {layerName}... ".format(count=str(counter+1), layerName=layerName), end="", flush=True)
# build api resource id
resourceId = layerName.split("__")[0].replace("_","-")
# get bounding bounds
cursor.execute( boundingBoxQuery.format(layerName) )
boundingBox = cursor.fetchall()[0]
# validate bounding box
if isValidLayer(boundingBox):
# get DGM information
with urllib.request.urlopen(DGM_API + resourceId) as dgm_response:
dgm_result = json.loads(dgm_response.read().decode("utf-8"))
if len(dgm_result["results"]) >= 1:
dgm_resource = dgm_result["results"][0]
if len(layerName.split("__")) > 1:
dgm_resource["name"] = dgm_resource["name"] + " - " + layerName.split("__")[1]
# get CKAN information
with urllib.request.urlopen(CKAN_API + dgm_resource["package-id"]) as ckan_response:
ckan_resource = json.loads(ckan_response.read().decode("utf-8"))["result"]
processFeatureType(layerName, dgm_resource, ckan_resource)
print("OK")
counter += 1
else:
print("No se encontro el recurso", json.dumps(dgm_result))
else:
print("Extension del layer no valido")
if MAX_LAYERS is not None and int(MAX_LAYERS) <= counter:
break
print("Done, layers created: " + str(counter))
def processFeatureType(layerName, dgm_resource, ckan_resource):
layerXml = "<featureType>";
layerXml += "<name>{}</name>".format(dgm_resource["name"])
if "description" in dgm_resource:
layerXml += "<abstract>{}</abstract>".format(dgm_resource["description"])
# define tags
tags = []
if "organization" in dgm_resource and dgm_resource["organization"] is not None:
tags.append(dgm_resource["organization"])
if "tags" in ckan_resource:
for tag in ckan_resource["tags"]:
if tag["state"] == "active":
tags.append(tag["display_name"])
# add tags to new layer
if len(tags) > 0:
layerXml += "<keywords>"
for tag in tags:
layerXml += "<string>{}</string>".format(tag)
layerXml += "</keywords>"
layerXml += "</featureType>"
subprocess.call( "curl -v -u {user}:{password} -X POST -H \"Content-type: text/xml\" -d \"{layerXml}\" {geoserver_rest}/workspaces/{workspace}/datastores/{datastore}/featuretypes".format(user=GEOSERVER_USER, password=GEOSERVER_PASSWORD, layerXml=layerXml, workspace=GEOSERVER_WORKSPACE, datastore=GEOSERVER_DATASTORE, geoserver_rest=GEOSERVER_REST) , shell=True)
def initConnection():
try:
conn = psycopg2.connect(dbname=POSTGRES_DBNAME, user=POSTGRES_USER, host=POSTGRES_HOST, password=POSTGRES_PASSWORD, port=POSTGRES_PORT)
return conn
except:
print("Error connecting to postgis.", True)
sys.exit()
def isValidLayer(boundingBox):
minx = boundingBox[0]
maxx = boundingBox[1]
miny = boundingBox[2]
maxy = boundingBox[3]
if minx < -180.0000 or minx > 180.0000:
return False
if maxx < -180.0000 or maxx > 180.0000:
return False
if miny < -90.0000 or miny > 90.0000:
return False
if maxy < -90.0000 or maxy > 90.0000:
return False
return True
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment