mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[processing] removed geoserver algorithms and moved postgis ones to qgis agorithms group
This commit is contained in:
parent
414d371376
commit
2073026f7c
@ -1,6 +1,5 @@
|
||||
FILE(GLOB PY_FILES *.py)
|
||||
|
||||
ADD_SUBDIRECTORY(admintools)
|
||||
ADD_SUBDIRECTORY(gdal)
|
||||
ADD_SUBDIRECTORY(grass)
|
||||
ADD_SUBDIRECTORY(grass7)
|
||||
|
@ -1,81 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
AdminToolsAlgorithmProvider.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from processing.core.AlgorithmProvider import AlgorithmProvider
|
||||
from PostGISExecuteSQL import PostGISExecuteSQL
|
||||
from ImportIntoPostGIS import ImportIntoPostGIS
|
||||
from ImportVectorIntoGeoServer import ImportVectorIntoGeoServer
|
||||
from CreateWorkspace import CreateWorkspace
|
||||
from ImportRasterIntoGeoServer import ImportRasterIntoGeoServer
|
||||
from DeleteWorkspace import DeleteWorkspace
|
||||
from DeleteDatastore import DeleteDatastore
|
||||
from CreateStyleGeoServer import CreateStyleGeoServer
|
||||
|
||||
|
||||
class AdminToolsAlgorithmProvider(AlgorithmProvider):
|
||||
|
||||
def __init__(self):
|
||||
AlgorithmProvider.__init__(self)
|
||||
self.alglist = [
|
||||
ImportVectorIntoGeoServer(),
|
||||
ImportRasterIntoGeoServer(),
|
||||
CreateWorkspace(),
|
||||
DeleteWorkspace(),
|
||||
DeleteDatastore(),
|
||||
CreateStyleGeoServer(),
|
||||
]
|
||||
|
||||
try:
|
||||
self.alglist.append(ImportIntoPostGIS())
|
||||
self.alglist.append(PostGISExecuteSQL())
|
||||
except:
|
||||
pass
|
||||
|
||||
def initializeSettings(self):
|
||||
AlgorithmProvider.initializeSettings(self)
|
||||
|
||||
def unload(self):
|
||||
AlgorithmProvider.unload(self)
|
||||
|
||||
def getName(self):
|
||||
return 'gspg'
|
||||
|
||||
def getDescription(self):
|
||||
return 'GeoServer/PostGIS tools'
|
||||
|
||||
def getIcon(self):
|
||||
return QtGui.QIcon(os.path.dirname(__file__)
|
||||
+ '/../../images/database.png')
|
||||
|
||||
def _loadAlgorithms(self):
|
||||
self.algs = self.alglist
|
||||
|
||||
def supportsNonFileBasedOutput(self):
|
||||
return False
|
@ -1,7 +0,0 @@
|
||||
FILE(GLOB PY_FILES *.py)
|
||||
|
||||
SET (WITH_INTERNAL_HTTPLIB TRUE CACHE BOOL "Use internal httplib2")
|
||||
|
||||
ADD_SUBDIRECTORY(geoserver)
|
||||
|
||||
PLUGIN_INSTALL(processing ./algs/admintools ${PY_FILES})
|
@ -1,58 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
CreateMosaicDatastore.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
from qgis.core import *
|
||||
from GeoServerToolsAlgorithm import \
|
||||
GeoServerToolsAlgorithm
|
||||
from processing.parameters.ParameterVector import ParameterVector
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
from processing.tools import dataobjects
|
||||
|
||||
|
||||
class CreateMosaicDatastore(GeoServerToolsAlgorithm):
|
||||
|
||||
INPUT = "INPUT"
|
||||
WORKSPACE = "WORKSPACE"
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
self.createCatalog()
|
||||
input = self.getParameterValue(self.INPUT)
|
||||
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||
connection = {
|
||||
'shp': basepathname + '.shp',
|
||||
'shx': basepathname + '.shx',
|
||||
'dbf': basepathname + '.dbf',
|
||||
'prj': basepathname + '.prj'}
|
||||
workspace = self.catalog.get_workspace(workspaceName)
|
||||
self.catalog.create_featurestore(basefilename, connection, workspace)
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.addcaddBaseParameters()
|
||||
self.name = "Import into GeoServer"
|
||||
self.group = "GeoServer management tools"
|
||||
self.addParameter(ParameterVector(self.INPUT, "Layer to import",
|
||||
[ParameterVector.VECTOR_TYPE_ANY]))
|
||||
self.addParameter(ParameterString(self.WORKSPACE, "Workspace"))
|
@ -1,55 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
CreateStyleGeoServer.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import *
|
||||
from GeoServerToolsAlgorithm import \
|
||||
GeoServerToolsAlgorithm
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
from processing.parameters.ParameterFile import ParameterFile
|
||||
from processing.parameters.ParameterBoolean import ParameterBoolean
|
||||
|
||||
|
||||
class CreateStyleGeoServer(GeoServerToolsAlgorithm):
|
||||
|
||||
STYLE = 'STYLE'
|
||||
OVERWRITE = 'OVERWRITE'
|
||||
NAME = 'NAME'
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
self.createCatalog()
|
||||
stylefile = self.getParameterValue(self.STYLE)
|
||||
overwrite = self.getParameterValue(self.OVERWRITE)
|
||||
name = self.getParameterValue(self.NAME)
|
||||
self.catalog.create_style(name, stylefile, overwrite)
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.addBaseParameters()
|
||||
self.name = 'Add style'
|
||||
self.group = 'GeoServer management tools'
|
||||
self.addParameter(ParameterString(self.NAME, 'Style name'))
|
||||
self.addParameter(ParameterFile(self.STYLE, 'Style SLD file'))
|
||||
self.addParameter(ParameterBoolean(self.OVERWRITE, 'Overwrite'))
|
@ -1,52 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
CreateWorkspace.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import *
|
||||
from GeoServerToolsAlgorithm import \
|
||||
GeoServerToolsAlgorithm
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
from processing.outputs.OutputString import OutputString
|
||||
|
||||
|
||||
class CreateWorkspace(GeoServerToolsAlgorithm):
|
||||
|
||||
WORKSPACE = 'WORKSPACE'
|
||||
WORKSPACEURI = 'WORKSPACEURI'
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
self.createCatalog()
|
||||
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||
workspaceUri = self.getParameterValue(self.WORKSPACEURI)
|
||||
self.catalog.create_workspace(workspaceName, workspaceUri)
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.addBaseParameters()
|
||||
self.name = 'Create workspace'
|
||||
self.group = 'GeoServer management tools'
|
||||
self.addParameter(ParameterString(self.WORKSPACE, 'Workspace'))
|
||||
self.addParameter(ParameterString(self.WORKSPACEURI, 'Workspace URI'))
|
||||
self.addOutput(OutputString(self.WORKSPACE, 'Workspace'))
|
@ -1,51 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
DeleteDatastore.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import *
|
||||
from GeoServerToolsAlgorithm import \
|
||||
GeoServerToolsAlgorithm
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
|
||||
|
||||
class DeleteDatastore(GeoServerToolsAlgorithm):
|
||||
|
||||
DATASTORE = 'DATASTORE'
|
||||
WORKSPACE = 'WORKSPACE'
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
self.createCatalog()
|
||||
datastoreName = self.getParameterValue(self.DATASTORE)
|
||||
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||
ds = self.catalog.get_store(datastoreName, workspaceName)
|
||||
self.catalog.delete(ds, recurse=True)
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.addBaseParameters()
|
||||
self.name = 'Delete datastore'
|
||||
self.group = 'GeoServer management tools'
|
||||
self.addParameter(ParameterString(self.DATASTORE, 'Datastore name'))
|
||||
self.addParameter(ParameterString(self.WORKSPACE, 'Workspace'))
|
@ -1,48 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
DeleteWorkspace.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import *
|
||||
from GeoServerToolsAlgorithm import \
|
||||
GeoServerToolsAlgorithm
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
|
||||
|
||||
class DeleteWorkspace(GeoServerToolsAlgorithm):
|
||||
|
||||
WORKSPACE = 'WORKSPACE'
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
self.createCatalog()
|
||||
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||
ws = self.catalog.get_workspace(workspaceName)
|
||||
self.catalog.delete(ws)
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.addBaseParameters()
|
||||
self.name = 'Delete workspace'
|
||||
self.group = 'GeoServer management tools'
|
||||
self.addParameter(ParameterString(self.WORKSPACE, 'Workspace'))
|
@ -1,56 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
GeoserverToolsAlgorithm.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
from PyQt4 import QtGui
|
||||
from processing.core.GeoAlgorithm import GeoAlgorithm
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
from geoserver.catalog import Catalog
|
||||
|
||||
|
||||
class GeoServerToolsAlgorithm(GeoAlgorithm):
|
||||
|
||||
URL = 'URL'
|
||||
USER = 'USER'
|
||||
PASSWORD = 'PASSWORD'
|
||||
|
||||
def getIcon(self):
|
||||
return QtGui.QIcon(os.path.dirname(__file__)
|
||||
+ '/../../images/geoserver.png')
|
||||
|
||||
def addBaseParameters(self):
|
||||
self.addParameter(ParameterString(self.URL, 'URL',
|
||||
'http://localhost:8080/geoserver/rest'))
|
||||
self.addParameter(ParameterString(self.USER, 'User', 'admin'))
|
||||
self.addParameter(ParameterString(self.PASSWORD, 'Password',
|
||||
'geoserver'))
|
||||
|
||||
def createCatalog(self):
|
||||
url = self.getParameterValue(self.URL)
|
||||
user = self.getParameterValue(self.USER)
|
||||
password = self.getParameterValue(self.PASSWORD)
|
||||
self.catalog = Catalog(url, user, password)
|
@ -1,61 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
ImportVectorIntoGeoServer.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import *
|
||||
from GeoServerToolsAlgorithm import \
|
||||
GeoServerToolsAlgorithm
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
from processing.parameters.ParameterRaster import ParameterRaster
|
||||
|
||||
|
||||
class ImportRasterIntoGeoServer(GeoServerToolsAlgorithm):
|
||||
|
||||
INPUT = 'INPUT'
|
||||
WORKSPACE = 'WORKSPACE'
|
||||
NAME = 'NAME'
|
||||
|
||||
def exportRasterLayer(self, inputFilename):
|
||||
return inputFilename
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
self.createCatalog()
|
||||
inputFilename = self.getParameterValue(self.INPUT)
|
||||
name = self.getParameterValue(self.NAME)
|
||||
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||
filename = self.exportRasterLayer(inputFilename)
|
||||
workspace = self.catalog.get_workspace(workspaceName)
|
||||
ds = self.catalog.create_coveragestore2(name, workspace)
|
||||
ds.data_url = 'file:' + filename
|
||||
self.catalog.save(ds)
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.addBaseParameters()
|
||||
self.name = 'Import raster into GeoServer'
|
||||
self.group = 'GeoServer management tools'
|
||||
self.addParameter(ParameterRaster(self.INPUT, 'Layer to import'))
|
||||
self.addParameter(ParameterString(self.WORKSPACE, 'Workspace'))
|
||||
self.addParameter(ParameterString(self.NAME, 'Store name'))
|
@ -1,67 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
ImportVectorIntoGeoServer.py
|
||||
---------------------
|
||||
Date : October 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'October 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
from qgis.core import *
|
||||
from GeoServerToolsAlgorithm import \
|
||||
GeoServerToolsAlgorithm
|
||||
from processing.parameters.ParameterVector import ParameterVector
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
from processing.tools import dataobjects
|
||||
|
||||
|
||||
class ImportVectorIntoGeoServer(GeoServerToolsAlgorithm):
|
||||
|
||||
INPUT = 'INPUT'
|
||||
WORKSPACE = 'WORKSPACE'
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
self.createCatalog()
|
||||
inputFilename = self.getParameterValue(self.INPUT)
|
||||
layer = dataobjects.getObjectFromUri(inputFilename)
|
||||
workspaceName = self.getParameterValue(self.WORKSPACE)
|
||||
filename = dataobjects.exportVectorLayer(layer)
|
||||
basefilename = os.path.basename(filename)
|
||||
basepathname = os.path.dirname(filename) + os.sep \
|
||||
+ basefilename[:basefilename.find('.')]
|
||||
connection = {
|
||||
'shp': basepathname + '.shp',
|
||||
'shx': basepathname + '.shx',
|
||||
'dbf': basepathname + '.dbf',
|
||||
'prj': basepathname + '.prj',
|
||||
}
|
||||
|
||||
workspace = self.catalog.get_workspace(workspaceName)
|
||||
self.catalog.create_featurestore(basefilename, connection, workspace)
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.addBaseParameters()
|
||||
self.name = 'Import vector into GeoServer'
|
||||
self.group = 'GeoServer management tools'
|
||||
self.addParameter(ParameterVector(self.INPUT, 'Layer to import',
|
||||
[ParameterVector.VECTOR_TYPE_ANY]))
|
||||
self.addParameter(ParameterString(self.WORKSPACE, 'Workspace'))
|
@ -1,3 +0,0 @@
|
||||
FILE(GLOB PY_FILES *.py)
|
||||
|
||||
PLUGIN_INSTALL(processing ./algs/admintools/geoserver ${PY_FILES})
|
@ -1,572 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
catalog.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
from os import unlink
|
||||
from xml.etree.ElementTree import XML
|
||||
from xml.parsers.expat import ExpatError
|
||||
from urlparse import urlparse
|
||||
|
||||
from layer import Layer
|
||||
from style import Style
|
||||
from store import coveragestore_from_index, \
|
||||
datastore_from_index, UnsavedDataStore, UnsavedCoverageStore
|
||||
from support import prepare_upload_bundle, url
|
||||
from layergroup import LayerGroup, \
|
||||
UnsavedLayerGroup
|
||||
from workspace import workspace_from_index, \
|
||||
Workspace
|
||||
|
||||
import httplib2
|
||||
|
||||
|
||||
logger = logging.getLogger('gsconfig.catalog')
|
||||
|
||||
|
||||
class UploadError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ConflictingDataError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AmbiguousRequestError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class FailedRequestError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _name(named):
|
||||
"""Get the name out of an object.
|
||||
This varies based on the type of the input:
|
||||
* the "name" of a string is itself
|
||||
* the "name" of None is itself
|
||||
* the "name" of an object with a property named name is that
|
||||
property - as long as it's a string
|
||||
* otherwise, we raise a ValueError
|
||||
"""
|
||||
|
||||
if isinstance(named, basestring) or named is None:
|
||||
return named
|
||||
elif hasattr(named, 'name') and isinstance(named.name, basestring):
|
||||
return named.name
|
||||
else:
|
||||
raise ValueError(
|
||||
"Can't interpret %s as a name or a configuration object"
|
||||
% named)
|
||||
|
||||
|
||||
class Catalog(object):
|
||||
"""The GeoServer catalog represents all of the information in the
|
||||
GeoServer configuration. This includes:
|
||||
- Stores of geospatial data
|
||||
- Resources, or individual coherent datasets within stores
|
||||
- Styles for resources
|
||||
- Layers, which combine styles with resources to create a visible map
|
||||
layer
|
||||
- LayerGroups, which alias one or more layers for convenience
|
||||
- Workspaces, which provide logical grouping of Stores
|
||||
- Maps, which provide a set of OWS services with a subset of the server's
|
||||
Layers
|
||||
- Namespaces, which provide unique identifiers for resources
|
||||
"""
|
||||
|
||||
def __init__(self, service_url, username='admin', password='geoserver',
|
||||
disable_ssl_certificate_validation=False):
|
||||
self.service_url = service_url
|
||||
if self.service_url.endswith('/'):
|
||||
self.service_url = self.service_url.strip('/')
|
||||
self.http = httplib2.Http(
|
||||
disable_ssl_certificate_validation=disable_ssl_certificate_validation)
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.http.add_credentials(self.username, self.password)
|
||||
netloc = urlparse(service_url).netloc
|
||||
self.http.authorizations.append(httplib2.BasicAuthentication(
|
||||
(username, password),
|
||||
netloc,
|
||||
service_url,
|
||||
{},
|
||||
None,
|
||||
None,
|
||||
self.http,
|
||||
))
|
||||
self._cache = dict()
|
||||
|
||||
def delete(self, config_object, purge=False, recurse=False):
|
||||
"""Send a delete request
|
||||
"""
|
||||
|
||||
rest_url = config_object.href
|
||||
|
||||
# params aren't supported fully in httplib2 yet, so:
|
||||
params = []
|
||||
|
||||
# purge deletes the SLD from disk when a style is deleted
|
||||
if purge:
|
||||
params.append('purge=true')
|
||||
|
||||
# recurse deletes the resource when a layer is deleted.
|
||||
if recurse:
|
||||
params.append('recurse=true')
|
||||
|
||||
if params:
|
||||
rest_url = rest_url + '?' + '&'.join(params)
|
||||
|
||||
headers = {'Content-type': 'application/xml',
|
||||
'Accept': 'application/xml'}
|
||||
(response, content) = self.http.request(rest_url, 'DELETE',
|
||||
headers=headers)
|
||||
self._cache.clear()
|
||||
|
||||
if response.status == 200:
|
||||
return (response, content)
|
||||
else:
|
||||
raise FailedRequestError(
|
||||
'Tried to make a DELETE request to %s but got a %d \
|
||||
status code: \n%s'
|
||||
% (rest_url, response.status, content))
|
||||
|
||||
def get_xml(self, rest_url):
|
||||
logger.debug('GET %s', rest_url)
|
||||
|
||||
cached_response = self._cache.get(rest_url)
|
||||
|
||||
def is_valid(cached_response):
|
||||
return cached_response is not None and datetime.now() \
|
||||
- cached_response[0] < timedelta(seconds=5)
|
||||
|
||||
def parse_or_raise(xml):
|
||||
try:
|
||||
return XML(xml)
|
||||
except (ExpatError, SyntaxError), e:
|
||||
msg = 'GeoServer gave non-XML response for [GET %s]: %s'
|
||||
msg = msg % (rest_url, xml)
|
||||
raise Exception(msg, e)
|
||||
|
||||
if is_valid(cached_response):
|
||||
raw_text = cached_response[1]
|
||||
return parse_or_raise(raw_text)
|
||||
else:
|
||||
(response, content) = self.http.request(rest_url)
|
||||
if response.status == 200:
|
||||
self._cache[rest_url] = (datetime.now(), content)
|
||||
return parse_or_raise(content)
|
||||
else:
|
||||
raise FailedRequestError(
|
||||
'Tried to make a GET request to %s but got a %d \
|
||||
status code: \n%s'
|
||||
% (url, response.status, content))
|
||||
|
||||
def reload(self):
|
||||
reload_url = url(self.service_url, ['reload'])
|
||||
response = self.http.request(reload_url, 'POST')
|
||||
self._cache.clear()
|
||||
return response
|
||||
|
||||
def save(self, obj):
|
||||
"""Saves an object to the REST service.
|
||||
|
||||
Gets the object's REST location and the XML from the object,
|
||||
then POSTS the request.
|
||||
"""
|
||||
|
||||
rest_url = obj.href
|
||||
message = obj.message()
|
||||
|
||||
headers = {'Content-type': 'application/xml',
|
||||
'Accept': 'application/xml'}
|
||||
logger.debug('%s %s', obj.save_method, obj.href)
|
||||
response = self.http.request(rest_url, obj.save_method, message,
|
||||
headers)
|
||||
(headers, body) = response
|
||||
self._cache.clear()
|
||||
if 400 <= int(headers['status']) < 600:
|
||||
raise FailedRequestError('Error code (%s) from GeoServer: %s'
|
||||
% (headers['status'], body))
|
||||
return response
|
||||
|
||||
def get_store(self, name, workspace=None):
|
||||
if workspace is None:
|
||||
store = None
|
||||
for ws in self.get_workspaces():
|
||||
found = None
|
||||
try:
|
||||
found = self.get_store(name, ws)
|
||||
except:
|
||||
# Don't expect every workspace to contain the named store
|
||||
pass
|
||||
if found:
|
||||
if store:
|
||||
raise AmbiguousRequestError(
|
||||
'Multiple stores found named: ' + name)
|
||||
else:
|
||||
store = found
|
||||
if not store:
|
||||
raise FailedRequestError('No store found named: ' + name)
|
||||
return store
|
||||
else:
|
||||
# Workspace is not None
|
||||
if isinstance(workspace, basestring):
|
||||
workspace = self.get_workspace(workspace)
|
||||
if workspace is None:
|
||||
return None
|
||||
logger.debug('datastore url is [%s]', workspace.datastore_url)
|
||||
ds_list = self.get_xml(workspace.datastore_url)
|
||||
cs_list = self.get_xml(workspace.coveragestore_url)
|
||||
datastores = [n for n in ds_list.findall('dataStore')
|
||||
if n.find('name').text == name]
|
||||
coveragestores = [n for n in cs_list.findall('coverageStore')
|
||||
if n.find('name').text == name]
|
||||
(ds_len, cs_len) = (len(datastores), len(coveragestores))
|
||||
|
||||
if ds_len == 1 and cs_len == 0:
|
||||
return datastore_from_index(self, workspace, datastores[0])
|
||||
elif ds_len == 0 and cs_len == 1:
|
||||
return coveragestore_from_index(self, workspace,
|
||||
coveragestores[0])
|
||||
elif ds_len == 0 and cs_len == 0:
|
||||
raise FailedRequestError('No store found in ' + str(workspace)
|
||||
+ ' named: ' + name)
|
||||
else:
|
||||
raise AmbiguousRequestError(str(workspace) + ' and name: '
|
||||
+ name + ' do not uniquely identify a layer')
|
||||
|
||||
def get_stores(self, workspace=None):
|
||||
if workspace is not None:
|
||||
if isinstance(workspace, basestring):
|
||||
workspace = self.get_workspace(workspace)
|
||||
ds_list = self.get_xml(workspace.datastore_url)
|
||||
cs_list = self.get_xml(workspace.coveragestore_url)
|
||||
datastores = [datastore_from_index(self, workspace, n) for n in
|
||||
ds_list.findall('dataStore')]
|
||||
coveragestores = [coveragestore_from_index(self, workspace, n)
|
||||
for n in cs_list.findall('coverageStore')]
|
||||
return datastores + coveragestores
|
||||
else:
|
||||
stores = []
|
||||
for ws in self.get_workspaces():
|
||||
a = self.get_stores(ws)
|
||||
stores.extend(a)
|
||||
return stores
|
||||
|
||||
def create_datastore(self, name, workspace=None):
|
||||
if isinstance(workspace, basestring):
|
||||
workspace = self.get_workspace(workspace)
|
||||
elif workspace is None:
|
||||
workspace = self.get_default_workspace()
|
||||
return UnsavedDataStore(self, name, workspace)
|
||||
|
||||
def create_coveragestore2(self, name, workspace=None):
|
||||
"""Hm we already named the method that creates a coverage *resource*
|
||||
create_coveragestore... time for an API break?
|
||||
"""
|
||||
|
||||
if isinstance(workspace, basestring):
|
||||
workspace = self.get_workspace(workspace)
|
||||
elif workspace is None:
|
||||
workspace = self.get_default_workspace()
|
||||
return UnsavedCoverageStore(self, name, workspace)
|
||||
|
||||
def add_data_to_store(self, store, name, data, workspace=None,
|
||||
overwrite=False, charset=None):
|
||||
if isinstance(store, basestring):
|
||||
store = self.get_store(store, workspace=workspace)
|
||||
if workspace is not None:
|
||||
workspace = _name(workspace)
|
||||
assert store.workspace.name == workspace, \
|
||||
'Specified store (%s) is not in specified workspace (%s)!' \
|
||||
% (store, workspace)
|
||||
else:
|
||||
workspace = store.workspace.name
|
||||
store = store.name
|
||||
|
||||
if isinstance(data, dict):
|
||||
bundle = prepare_upload_bundle(name, data)
|
||||
else:
|
||||
bundle = data
|
||||
|
||||
params = dict()
|
||||
if overwrite:
|
||||
params['update'] = 'overwrite'
|
||||
if charset is not None:
|
||||
params['charset'] = charset
|
||||
|
||||
message = open(bundle)
|
||||
headers = {'Content-Type': 'application/zip',
|
||||
'Accept': 'application/xml'}
|
||||
upload_url = url(self.service_url, ['workspaces', workspace,
|
||||
'datastores', store, 'file.shp'], params)
|
||||
|
||||
try:
|
||||
(headers, response) = self.http.request(upload_url, 'PUT',
|
||||
message, headers)
|
||||
self._cache.clear()
|
||||
if headers.status != 201:
|
||||
raise UploadError(response)
|
||||
finally:
|
||||
unlink(bundle)
|
||||
|
||||
def create_featurestore(self, name, data, workspace=None, overwrite=False,
|
||||
charset=None):
|
||||
if not overwrite:
|
||||
try:
|
||||
store = self.get_store(name, workspace)
|
||||
msg = 'There is already a store named ' + name
|
||||
if workspace:
|
||||
msg += ' in ' + str(workspace)
|
||||
raise ConflictingDataError(msg)
|
||||
except FailedRequestError:
|
||||
# We don't really expect that every layer name will be taken
|
||||
pass
|
||||
|
||||
if workspace is None:
|
||||
workspace = self.get_default_workspace()
|
||||
workspace = _name(workspace)
|
||||
params = dict()
|
||||
if charset is not None:
|
||||
params['charset'] = charset
|
||||
ds_url = url(self.service_url, ['workspaces', workspace, 'datastores',
|
||||
name, 'file.shp'], params)
|
||||
|
||||
# PUT /workspaces/<ws>/datastores/<ds>/file.shp
|
||||
headers = {'Content-type': 'application/zip',
|
||||
'Accept': 'application/xml'}
|
||||
if isinstance(data, dict):
|
||||
logger.debug('Data is NOT a zipfile')
|
||||
archive = prepare_upload_bundle(name, data)
|
||||
else:
|
||||
logger.debug('Data is a zipfile')
|
||||
archive = data
|
||||
message = open(archive)
|
||||
try:
|
||||
(headers, response) = self.http.request(ds_url, 'PUT', message,
|
||||
headers)
|
||||
self._cache.clear()
|
||||
if headers.status != 201:
|
||||
raise UploadError(response)
|
||||
finally:
|
||||
unlink(archive)
|
||||
|
||||
def create_coveragestore(self, name, data, workspace=None,
|
||||
overwrite=False):
|
||||
if not overwrite:
|
||||
try:
|
||||
store = self.get_store(name, workspace)
|
||||
msg = 'There is already a store named ' + name
|
||||
if workspace:
|
||||
msg += ' in ' + str(workspace)
|
||||
raise ConflictingDataError(msg)
|
||||
except FailedRequestError:
|
||||
# We don't really expect that every layer name will be taken
|
||||
pass
|
||||
|
||||
if workspace is None:
|
||||
workspace = self.get_default_workspace()
|
||||
headers = {'Content-type': 'image/tiff', 'Accept': 'application/xml'}
|
||||
|
||||
archive = None
|
||||
ext = 'geotiff'
|
||||
|
||||
if isinstance(data, dict):
|
||||
archive = prepare_upload_bundle(name, data)
|
||||
message = open(archive)
|
||||
if 'tfw' in data:
|
||||
headers['Content-type'] = 'application/archive'
|
||||
ext = 'worldimage'
|
||||
elif isinstance(data, basestring):
|
||||
message = open(data)
|
||||
else:
|
||||
message = data
|
||||
|
||||
cs_url = url(self.service_url, ['workspaces', workspace.name,
|
||||
'coveragestores', name, 'file.' + ext])
|
||||
|
||||
try:
|
||||
(headers, response) = self.http.request(cs_url, 'PUT', message,
|
||||
headers)
|
||||
self._cache.clear()
|
||||
if headers.status != 201:
|
||||
raise UploadError(response)
|
||||
finally:
|
||||
if archive is not None:
|
||||
unlink(archive)
|
||||
|
||||
def get_resource(self, name, store=None, workspace=None):
|
||||
if store is not None:
|
||||
candidates = [s for s in self.get_resources(store) if s.name
|
||||
== name]
|
||||
if len(candidates) == 0:
|
||||
return None
|
||||
elif len(candidates) > 1:
|
||||
raise AmbiguousRequestError
|
||||
else:
|
||||
return candidates[0]
|
||||
|
||||
if workspace is not None:
|
||||
for store in self.get_stores(workspace):
|
||||
resource = self.get_resource(name, store)
|
||||
if resource is not None:
|
||||
return resource
|
||||
return None
|
||||
|
||||
for ws in self.get_workspaces():
|
||||
resource = self.get_resource(name, workspace=ws)
|
||||
if resource is not None:
|
||||
return resource
|
||||
return None
|
||||
|
||||
def get_resources(self, store=None, workspace=None):
|
||||
if isinstance(workspace, basestring):
|
||||
workspace = self.get_workspace(workspace)
|
||||
if isinstance(store, basestring):
|
||||
store = self.get_store(store, workspace)
|
||||
if store is not None:
|
||||
return store.get_resources()
|
||||
if workspace is not None:
|
||||
resources = []
|
||||
for store in self.get_stores(workspace):
|
||||
resources.extend(self.get_resources(store))
|
||||
return resources
|
||||
resources = []
|
||||
for ws in self.get_workspaces():
|
||||
resources.extend(self.get_resources(workspace=ws))
|
||||
return resources
|
||||
|
||||
def get_layer(self, name):
|
||||
try:
|
||||
lyr = Layer(self, name)
|
||||
lyr.fetch()
|
||||
return lyr
|
||||
except FailedRequestError:
|
||||
return None
|
||||
|
||||
def get_layers(self, resource=None):
|
||||
if isinstance(resource, basestring):
|
||||
resource = self.get_resource(resource)
|
||||
layers_url = url(self.service_url, ['layers.xml'])
|
||||
description = self.get_xml(layers_url)
|
||||
lyrs = [Layer(self, l.find('name').text) for l in
|
||||
description.findall('layer')]
|
||||
if resource is not None:
|
||||
lyrs = [l for l in lyrs if l.resource.href == resource.href]
|
||||
|
||||
# TODO: filter by style
|
||||
return lyrs
|
||||
|
||||
def get_layergroup(self, name=None):
|
||||
try:
|
||||
group_url = url(self.service_url, ['layergroups', name + '.xml'])
|
||||
group = self.get_xml(group_url)
|
||||
return LayerGroup(self, group.find('name').text)
|
||||
except FailedRequestError:
|
||||
return None
|
||||
|
||||
def get_layergroups(self):
|
||||
groups = self.get_xml('%s/layergroups.xml' % self.service_url)
|
||||
return [LayerGroup(self, g.find('name').text) for g in
|
||||
groups.findall('layerGroup')]
|
||||
|
||||
def create_layergroup(self, name, layers=(), styles=(), bounds=None):
|
||||
if any(g.name == name for g in self.get_layergroups()):
|
||||
raise ConflictingDataError('LayerGroup named %s already exists!'
|
||||
% name)
|
||||
else:
|
||||
return UnsavedLayerGroup(self, name, layers, styles, bounds)
|
||||
|
||||
def get_style(self, name):
|
||||
try:
|
||||
style_url = url(self.service_url, ['styles', name + '.xml'])
|
||||
dom = self.get_xml(style_url)
|
||||
return Style(self, dom.find('name').text)
|
||||
except FailedRequestError:
|
||||
return None
|
||||
|
||||
def get_styles(self):
|
||||
styles_url = url(self.service_url, ['styles.xml'])
|
||||
description = self.get_xml(styles_url)
|
||||
return [Style(self, s.find('name').text) for s in
|
||||
description.findall('style')]
|
||||
|
||||
def create_style(self, name, data, overwrite=False):
|
||||
if not overwrite and self.get_style(name) is not None:
|
||||
raise ConflictingDataError('There is already a style named %s'
|
||||
% name)
|
||||
|
||||
headers = {'Content-type': 'application/vnd.ogc.sld+xml',
|
||||
'Accept': 'application/xml'}
|
||||
|
||||
if overwrite:
|
||||
style_url = url(self.service_url, ['styles', name + '.sld'])
|
||||
(headers, response) = self.http.request(style_url, 'PUT', data,
|
||||
headers)
|
||||
else:
|
||||
style_url = url(self.service_url, ['styles'], dict(name=name))
|
||||
(headers, response) = self.http.request(style_url, 'POST', data,
|
||||
headers)
|
||||
|
||||
self._cache.clear()
|
||||
if headers.status < 200 or headers.status > 299:
|
||||
raise UploadError(response)
|
||||
|
||||
def create_workspace(self, name, uri):
|
||||
xml = '<namespace><prefix>{name}</prefix><uri>{uri}</uri>\
|
||||
</namespace>'.format(name=name, uri=uri)
|
||||
headers = {'Content-Type': 'application/xml'}
|
||||
workspace_url = self.service_url + '/namespaces/'
|
||||
|
||||
(headers, response) = self.http.request(workspace_url, 'POST', xml,
|
||||
headers)
|
||||
assert 200 <= headers.status < 300, \
|
||||
'Tried to create workspace but got ' + str(headers.status) + ': ' \
|
||||
+ response
|
||||
self._cache.clear()
|
||||
return self.get_workspace(name)
|
||||
|
||||
def get_workspaces(self):
|
||||
description = self.get_xml('%s/workspaces.xml' % self.service_url)
|
||||
return [workspace_from_index(self, node) for node in
|
||||
description.findall('workspace')]
|
||||
|
||||
def get_workspace(self, name):
|
||||
candidates = [w for w in self.get_workspaces() if w.name == name]
|
||||
if len(candidates) == 0:
|
||||
return None
|
||||
elif len(candidates) > 1:
|
||||
raise AmbiguousRequestError()
|
||||
else:
|
||||
return candidates[0]
|
||||
|
||||
def get_default_workspace(self):
|
||||
return Workspace(self, 'default')
|
||||
|
||||
def set_default_workspace(self):
|
||||
raise NotImplementedError()
|
@ -1,161 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
layer.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from style import Style
|
||||
from support import ResourceInfo, \
|
||||
xml_property, write_bool, url
|
||||
|
||||
|
||||
class _attribution(object):
|
||||
|
||||
def __init__(self, title, width, height):
|
||||
self.title = title
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
|
||||
def _read_attribution(node):
|
||||
title = node.find('title')
|
||||
width = node.find('logoWidth')
|
||||
height = node.find('logoHeight')
|
||||
|
||||
if title is not None:
|
||||
title = title.text
|
||||
if width is not None:
|
||||
width = width.text
|
||||
if height is not None:
|
||||
height = height.text
|
||||
|
||||
return _attribution(title, width, height)
|
||||
|
||||
|
||||
def _write_attribution(builder, attr):
|
||||
builder.start('attribution', dict())
|
||||
if attr.title is not None:
|
||||
builder.start('title', dict())
|
||||
builder.data(attr.title)
|
||||
builder.end('title')
|
||||
if attr.width is not None:
|
||||
builder.start('logoWidth', dict())
|
||||
builder.data(attr.width)
|
||||
builder.end('logoWidth')
|
||||
if attr.height is not None:
|
||||
builder.start('logoHeight', dict())
|
||||
builder.data(attr.height)
|
||||
builder.end('logoHeight')
|
||||
builder.end('attribution')
|
||||
|
||||
|
||||
def _write_default_style(builder, name):
|
||||
builder.start('defaultStyle', dict())
|
||||
if name is not None:
|
||||
builder.start('name', dict())
|
||||
builder.data(name)
|
||||
builder.end('name')
|
||||
builder.end('defaultStyle')
|
||||
|
||||
|
||||
def _write_alternate_styles(builder, styles):
|
||||
builder.start('styles', dict())
|
||||
for s in styles:
|
||||
builder.start('style', dict())
|
||||
builder.start('name', dict())
|
||||
builder.data(s.name)
|
||||
builder.end('name')
|
||||
builder.end('style')
|
||||
builder.end('styles')
|
||||
|
||||
|
||||
class Layer(ResourceInfo):
|
||||
|
||||
def __init__(self, catalog, name):
|
||||
super(Layer, self).__init__()
|
||||
self.catalog = catalog
|
||||
self.name = name
|
||||
|
||||
resource_type = 'layer'
|
||||
save_method = 'PUT'
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, ['layers', self.name + '.xml'])
|
||||
|
||||
@property
|
||||
def resource(self):
|
||||
if self.dom is None:
|
||||
self.fetch()
|
||||
name = self.dom.find('resource/name').text
|
||||
return self.catalog.get_resource(name)
|
||||
|
||||
def _get_default_style(self):
|
||||
if 'default_style' in self.dirty:
|
||||
return self.dirty['default_style']
|
||||
if self.dom is None:
|
||||
self.fetch()
|
||||
name = self.dom.find('defaultStyle/name')
|
||||
|
||||
# Aborted data uploads can result in no default style
|
||||
if name is not None:
|
||||
return self.catalog.get_style(name.text)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _set_default_style(self, style):
|
||||
if isinstance(style, Style):
|
||||
style = style.name
|
||||
self.dirty['default_style'] = style
|
||||
|
||||
def _get_alternate_styles(self):
|
||||
if 'alternate_styles' in self.dirty:
|
||||
return self.dirty['alternate_styles']
|
||||
if self.dom is None:
|
||||
self.fetch()
|
||||
styles = self.dom.findall('styles/style/name')
|
||||
return [Style(self.catalog, s.text) for s in styles]
|
||||
|
||||
def _set_alternate_styles(self, styles):
|
||||
self.dirty['alternate_styles'] = styles
|
||||
|
||||
default_style = property(_get_default_style, _set_default_style)
|
||||
styles = property(_get_alternate_styles, _set_alternate_styles)
|
||||
|
||||
attribution_object = xml_property('attribution', _read_attribution)
|
||||
enabled = xml_property('enabled', lambda x: x.text == 'true')
|
||||
|
||||
def _get_attr_text(self):
|
||||
return self.attribution_object.title
|
||||
|
||||
def _set_attr_text(self, text):
|
||||
self.dirty['attribution'] = _attribution(text,
|
||||
self.attribution_object.width, self.attribution_object.height)
|
||||
assert self.attribution_object.title == text
|
||||
|
||||
attribution = property(_get_attr_text, _set_attr_text)
|
||||
|
||||
writers = dict(attribution=_write_attribution, enabled=write_bool('enabled'
|
||||
), default_style=_write_default_style,
|
||||
alternate_styles=_write_alternate_styles)
|
@ -1,117 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
layergroup.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by David Winslow
|
||||
Email : dwins at opengeo dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'David Winslow'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, David Winslow'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from support import ResourceInfo, bbox, \
|
||||
write_bbox, write_string, xml_property, url
|
||||
|
||||
|
||||
def _maybe_text(n):
|
||||
if n is None:
|
||||
return None
|
||||
else:
|
||||
return n.text
|
||||
|
||||
|
||||
def _layer_list(node):
|
||||
if node is not None:
|
||||
return [_maybe_text(n.find('name')) for n in node.findall('layer')]
|
||||
|
||||
|
||||
def _style_list(node):
|
||||
if node is not None:
|
||||
return [_maybe_text(n.find('name')) for n in node.findall('style')]
|
||||
|
||||
|
||||
def _write_layers(builder, layers):
|
||||
builder.start('layers', dict())
|
||||
for l in layers:
|
||||
builder.start('layer', dict())
|
||||
if l is not None:
|
||||
builder.start('name', dict())
|
||||
builder.data(l)
|
||||
builder.end('name')
|
||||
builder.end('layer')
|
||||
builder.end('layers')
|
||||
|
||||
|
||||
def _write_styles(builder, styles):
|
||||
builder.start('styles', dict())
|
||||
for s in styles:
|
||||
builder.start('style', dict())
|
||||
if s is not None:
|
||||
builder.start('name', dict())
|
||||
builder.data(s)
|
||||
builder.end('name')
|
||||
builder.end('style')
|
||||
builder.end('styles')
|
||||
|
||||
|
||||
class LayerGroup(ResourceInfo):
|
||||
"""Represents a layer group in geoserver.
|
||||
"""
|
||||
|
||||
resource_type = 'layerGroup'
|
||||
save_method = 'PUT'
|
||||
|
||||
def __init__(self, catalog, name):
|
||||
super(LayerGroup, self).__init__()
|
||||
|
||||
assert isinstance(name, basestring)
|
||||
|
||||
self.catalog = catalog
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, ['layergroups', self.name + '.xml'
|
||||
])
|
||||
|
||||
styles = xml_property('styles', _style_list)
|
||||
layers = xml_property('layers', _layer_list)
|
||||
bounds = xml_property('bounds', bbox)
|
||||
|
||||
writers = dict(name=write_string('name'), styles=_write_styles,
|
||||
layers=_write_layers, bounds=write_bbox('bounds'))
|
||||
|
||||
def __str__(self):
|
||||
return '<LayerGroup %s>' % self.name
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
class UnsavedLayerGroup(LayerGroup):
|
||||
|
||||
save_method = 'POST'
|
||||
|
||||
def __init__(self, catalog, name, layers, styles, bounds):
|
||||
super(UnsavedLayerGroup, self).__init__(catalog, name)
|
||||
self.dirty.update(name=name, layers=layers, styles=styles,
|
||||
bounds=bounds)
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return '%s/layergroups?name=%s' % (self.catalog.service_url, self.name)
|
@ -1,229 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
resource.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by David Winslow
|
||||
Email : dwins at opengeo dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'David Winslow'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, David Winslow'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from support import ResourceInfo, \
|
||||
xml_property, write_string, bbox, write_bbox, string_list, \
|
||||
write_string_list, attribute_list, write_bool, url
|
||||
|
||||
|
||||
def md_link(node):
|
||||
"""Extract a metadata link tuple from an xml node"""
|
||||
|
||||
mimetype = node.find('type')
|
||||
mdtype = node.find('metadataType')
|
||||
content = node.find('content')
|
||||
if None in [mimetype, mdtype, content]:
|
||||
return None
|
||||
else:
|
||||
return (mimetype.text, mdtype.text, content.text)
|
||||
|
||||
|
||||
def metadata_link_list(node):
|
||||
if node is not None:
|
||||
return [md_link(n) for n in node.findall('metadataLink')]
|
||||
|
||||
|
||||
def write_metadata_link_list(name):
|
||||
|
||||
def write(builder, md_links):
|
||||
builder.start(name, dict())
|
||||
for (mime, md_type, content_url) in md_links:
|
||||
builder.start('metadataLink', dict())
|
||||
builder.start('type', dict())
|
||||
builder.data(mime)
|
||||
builder.end('type')
|
||||
builder.start('metadataType', dict())
|
||||
builder.data(md_type)
|
||||
builder.end('metadataType')
|
||||
builder.start('content', dict())
|
||||
builder.data(content_url)
|
||||
builder.end('content')
|
||||
builder.end('metadataLink')
|
||||
builder.end('metadataLinks')
|
||||
|
||||
return write
|
||||
|
||||
|
||||
def featuretype_from_index(catalog, workspace, store, node):
|
||||
name = node.find('name')
|
||||
return FeatureType(catalog, workspace, store, name.text)
|
||||
|
||||
|
||||
def coverage_from_index(catalog, workspace, store, node):
|
||||
name = node.find('name')
|
||||
return Coverage(catalog, workspace, store, name.text)
|
||||
|
||||
|
||||
class FeatureType(ResourceInfo):
|
||||
|
||||
resource_type = 'featureType'
|
||||
save_method = 'PUT'
|
||||
|
||||
def __init__(self, catalog, workspace, store, name):
|
||||
super(FeatureType, self).__init__()
|
||||
|
||||
assert isinstance(store, ResourceInfo)
|
||||
assert isinstance(name, basestring)
|
||||
|
||||
self.catalog = catalog
|
||||
self.workspace = workspace
|
||||
self.store = store
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, [
|
||||
'workspaces',
|
||||
self.workspace.name,
|
||||
'datastores',
|
||||
self.store.name,
|
||||
'featuretypes',
|
||||
self.name + '.xml',
|
||||
])
|
||||
|
||||
title = xml_property('title')
|
||||
abstract = xml_property('abstract')
|
||||
enabled = xml_property('enabled')
|
||||
native_bbox = xml_property('nativeBoundingBox', bbox)
|
||||
latlon_bbox = xml_property('latLonBoundingBox', bbox)
|
||||
projection = xml_property('srs')
|
||||
projection_policy = xml_property('projectionPolicy')
|
||||
keywords = xml_property('keywords', string_list)
|
||||
attributes = xml_property('attributes', attribute_list)
|
||||
metadata_links = xml_property('metadataLinks', metadata_link_list)
|
||||
|
||||
writers = dict(
|
||||
title=write_string('title'),
|
||||
abstract=write_string('abstract'),
|
||||
enabled=write_bool('enabled'),
|
||||
nativeBoundingBox=write_bbox('nativeBoundingBox'),
|
||||
latLonBoundingBox=write_bbox('latLonBoundingBox'),
|
||||
srs=write_string('srs'),
|
||||
projectionPolicy=write_string('projectionPolicy'),
|
||||
keywords=write_string_list('keywords'),
|
||||
metadataLinks=write_metadata_link_list('metadataLinks'),
|
||||
)
|
||||
|
||||
|
||||
class CoverageDimension(object):
|
||||
|
||||
def __init__(self, name, description, dimension_range):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.dimension_range = dimension_range
|
||||
|
||||
|
||||
def coverage_dimension(node):
|
||||
name = node.find('name')
|
||||
name = (name.text if name is not None else None)
|
||||
description = node.find('description')
|
||||
description = (description.text if description is not None else None)
|
||||
range_min = node.find('range/min')
|
||||
range_max = node.find('range/max')
|
||||
dimension_range = None
|
||||
if None not in [min, max]:
|
||||
dimension_range = (float(range_min.text), float(range_max.text))
|
||||
if None not in [name, description]:
|
||||
return CoverageDimension(name, description, dimension_range)
|
||||
else:
|
||||
# Should we bomb out more spectacularly here?
|
||||
return None
|
||||
|
||||
|
||||
def coverage_dimension_xml(builder, dimension):
|
||||
builder.start('coverageDimension', dict())
|
||||
builder.start('name', dict())
|
||||
builder.data(dimension.name)
|
||||
builder.end('name')
|
||||
|
||||
builder.start('description', dict())
|
||||
builder.data(dimension.description)
|
||||
builder.end('description')
|
||||
|
||||
if dimension.range is not None:
|
||||
builder.start('range', dict())
|
||||
builder.start('min', dict())
|
||||
builder.data(str(dimension.range[0]))
|
||||
builder.end('min')
|
||||
builder.start('max', dict())
|
||||
builder.data(str(dimension.range[1]))
|
||||
builder.end('max')
|
||||
builder.end('range')
|
||||
|
||||
builder.end('coverageDimension')
|
||||
|
||||
|
||||
class Coverage(ResourceInfo):
|
||||
|
||||
def __init__(self, catalog, workspace, store, name):
|
||||
super(Coverage, self).__init__()
|
||||
self.catalog = catalog
|
||||
self.workspace = workspace
|
||||
self.store = store
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, [
|
||||
'workspaces',
|
||||
self.workspace.name,
|
||||
'coveragestores',
|
||||
self.store.name,
|
||||
'coverages',
|
||||
self.name + '.xml',
|
||||
])
|
||||
|
||||
resource_type = 'coverage'
|
||||
save_method = 'PUT'
|
||||
|
||||
title = xml_property('title')
|
||||
abstract = xml_property('abstract')
|
||||
enabled = xml_property('enabled')
|
||||
native_bbox = xml_property('nativeBoundingBox', bbox)
|
||||
latlon_bbox = xml_property('latLonBoundingBox', bbox)
|
||||
projection = xml_property('srs')
|
||||
projection_policy = xml_property('projectionPolicy')
|
||||
keywords = xml_property('keywords', string_list)
|
||||
request_srs_list = xml_property('requestSRS', string_list)
|
||||
response_srs_list = xml_property('responseSRS', string_list)
|
||||
supported_formats = xml_property('supportedFormats', string_list)
|
||||
metadata_links = xml_property('metadataLinks', metadata_link_list)
|
||||
|
||||
writers = dict(
|
||||
title=write_string('title'),
|
||||
abstract=write_string('abstract'),
|
||||
enabled=write_bool('enabled'),
|
||||
nativeBoundingBox=write_bbox('nativeBoundingBox'),
|
||||
latLonBoundingBox=write_bbox('latLonBoundingBox'),
|
||||
srs=write_string('srs'),
|
||||
projection_policy=write_string('projectionPolicy'),
|
||||
keywords=write_string_list('keywords'),
|
||||
metadataLinks=write_metadata_link_list('metadataLinks'),
|
||||
requestSRS=write_string_list('requestSRS'),
|
||||
responseSRS=write_string_list('responseSRS'),
|
||||
supportedFormats=write_string_list('supportedFormats'),
|
||||
)
|
@ -1,156 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
store.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by David Winslow
|
||||
Email : dwins at opengeo dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'David Winslow'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, David Winslow'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from workspace import Workspace
|
||||
from resource import featuretype_from_index, \
|
||||
coverage_from_index
|
||||
from support import ResourceInfo, \
|
||||
xml_property, key_value_pairs, write_bool, write_dict, write_string, url
|
||||
|
||||
|
||||
def datastore_from_index(catalog, workspace, node):
|
||||
name = node.find('name')
|
||||
return DataStore(catalog, workspace, name.text)
|
||||
|
||||
|
||||
def coveragestore_from_index(catalog, workspace, node):
|
||||
name = node.find('name')
|
||||
return CoverageStore(catalog, workspace, name.text)
|
||||
|
||||
|
||||
class DataStore(ResourceInfo):
|
||||
|
||||
resource_type = 'dataStore'
|
||||
save_method = 'PUT'
|
||||
|
||||
def __init__(self, catalog, workspace, name):
|
||||
super(DataStore, self).__init__()
|
||||
|
||||
assert isinstance(workspace, Workspace)
|
||||
assert isinstance(name, basestring)
|
||||
self.catalog = catalog
|
||||
self.workspace = workspace
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, ['workspaces',
|
||||
self.workspace.name, 'datastores', self.name + '.xml'])
|
||||
|
||||
enabled = xml_property('enabled', lambda x: x.text == 'true')
|
||||
name = xml_property('name')
|
||||
connection_parameters = xml_property('connectionParameters',
|
||||
key_value_pairs)
|
||||
|
||||
writers = dict(enabled=write_bool('enabled'), name=write_string('name'),
|
||||
connectionParameters=write_dict('connectionParameters'))
|
||||
|
||||
def get_resources(self):
|
||||
res_url = url(self.catalog.service_url, ['workspaces',
|
||||
self.workspace.name, 'datastores', self.name,
|
||||
'featuretypes.xml'])
|
||||
xml = self.catalog.get_xml(res_url)
|
||||
|
||||
def ft_from_node(node):
|
||||
return featuretype_from_index(self.catalog, self.workspace, self,
|
||||
node)
|
||||
|
||||
return [ft_from_node(node) for node in xml.findall('featureType')]
|
||||
|
||||
|
||||
class UnsavedDataStore(DataStore):
|
||||
|
||||
save_method = 'POST'
|
||||
|
||||
def __init__(self, catalog, name, workspace):
|
||||
super(UnsavedDataStore, self).__init__(catalog, workspace, name)
|
||||
self.dirty.update(dict(name=name, enabled=True,
|
||||
connectionParameters=dict()))
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
path = ['workspaces', self.workspace.name, 'datastores']
|
||||
query = dict(name=self.name)
|
||||
return url(self.catalog.service_url, path, query)
|
||||
|
||||
|
||||
class CoverageStore(ResourceInfo):
|
||||
|
||||
resource_type = 'coverageStore'
|
||||
save_method = 'PUT'
|
||||
|
||||
def __init__(self, catalog, workspace, name):
|
||||
super(CoverageStore, self).__init__()
|
||||
|
||||
assert isinstance(workspace, Workspace)
|
||||
assert isinstance(name, basestring)
|
||||
|
||||
self.catalog = catalog
|
||||
self.workspace = workspace
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, ['workspaces',
|
||||
self.workspace.name, 'coveragestores', self.name + '.xml'])
|
||||
|
||||
enabled = xml_property('enabled', lambda x: x.text == 'true')
|
||||
name = xml_property('name')
|
||||
url = xml_property('url')
|
||||
type = xml_property('type')
|
||||
|
||||
writers = dict(enabled=write_bool('enabled'), name=write_string('name'),
|
||||
url=write_string('url'), type=write_string('type'))
|
||||
|
||||
def get_resources(self):
|
||||
res_url = url(self.catalog.service_url, ['workspaces',
|
||||
self.workspace.name, 'coveragestores', self.name,
|
||||
'coverages.xml'])
|
||||
|
||||
xml = self.catalog.get_xml(res_url)
|
||||
|
||||
def cov_from_node(node):
|
||||
return coverage_from_index(self.catalog, self.workspace, self,
|
||||
node)
|
||||
|
||||
return [cov_from_node(node) for node in xml.findall('coverage')]
|
||||
|
||||
|
||||
class UnsavedCoverageStore(CoverageStore):
|
||||
|
||||
save_method = 'POST'
|
||||
|
||||
def __init__(self, catalog, name, workspace):
|
||||
super(UnsavedCoverageStore, self).__init__(catalog, workspace, name)
|
||||
self.dirty.update(name=name, enabled=True, type='GeoTIFF',
|
||||
url='file:data/')
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, ['workspaces',
|
||||
self.workspace.name, 'coveragestores'],
|
||||
dict(name=self.name))
|
@ -1,77 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
style.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by David Winslow
|
||||
Email : dwins at opengeo dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'David Winslow'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, David Winslow'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from support import ResourceInfo, url, \
|
||||
xml_property
|
||||
|
||||
|
||||
class Style(ResourceInfo):
|
||||
|
||||
def __init__(self, catalog, name):
|
||||
super(Style, self).__init__()
|
||||
assert isinstance(name, basestring)
|
||||
|
||||
self.catalog = catalog
|
||||
self.name = name
|
||||
self._sld_dom = None
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, ['styles', self.name + '.xml'])
|
||||
|
||||
def body_href(self):
|
||||
return url(self.catalog.service_url, ['styles', self.name + '.sld'])
|
||||
|
||||
filename = xml_property('filename')
|
||||
|
||||
def _get_sld_dom(self):
|
||||
if self._sld_dom is None:
|
||||
self._sld_dom = self.catalog.get_xml(self.body_href())
|
||||
return self._sld_dom
|
||||
|
||||
@property
|
||||
def sld_title(self):
|
||||
user_style = \
|
||||
self._get_sld_dom().find('{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle')
|
||||
title_node = user_style.find('{http://www.opengis.net/sld}Title')
|
||||
return (title_node.text if title_node is not None else None)
|
||||
|
||||
@property
|
||||
def sld_name(self):
|
||||
user_style = \
|
||||
self._get_sld_dom().find('{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle')
|
||||
name_node = user_style.find('{http://www.opengis.net/sld}Name')
|
||||
return (name_node.text if name_node is not None else None)
|
||||
|
||||
@property
|
||||
def sld_body(self):
|
||||
content = self.catalog.http.request(self.body_href())[1]
|
||||
return content
|
||||
|
||||
def update_body(self, body):
|
||||
headers = {'Content-Type': 'application/vnd.ogc.sld+xml'}
|
||||
self.catalog.http.request(self.body_href(), 'PUT', body, headers)
|
@ -1,277 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
support.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by David Winslow
|
||||
Email : dwins at opengeo dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'David Winslow'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, David Winslow'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import logging
|
||||
from xml.etree.ElementTree import TreeBuilder, tostring
|
||||
import urllib
|
||||
import urlparse
|
||||
from zipfile import ZipFile
|
||||
from processing.tools.system import *
|
||||
|
||||
logger = logging.getLogger('gsconfig.support')
|
||||
|
||||
# The projection handling policy for layers that should use coordinates
|
||||
# directly while reporting the configured projection to clients. This
|
||||
# should be used when projection information is missing from the
|
||||
# underlying datastore.
|
||||
FORCE_DECLARED = 'FORCE_DECLARED'
|
||||
|
||||
# The projection handling policy for layers that should use the
|
||||
# projection information from the underlying storage mechanism directly,
|
||||
# and ignore the projection setting.
|
||||
FORCE_NATIVE = 'FORCE_NATIVE'
|
||||
|
||||
# The projection handling policy for layers that should use the
|
||||
# projection information from the underlying storage mechanism to
|
||||
# reproject to the configured projection.
|
||||
REPROJECT = 'REPROJECT'
|
||||
|
||||
|
||||
def url(base, seg, query=None):
|
||||
"""Create a URL from a list of path segments and an optional dict
|
||||
of query parameters.
|
||||
"""
|
||||
|
||||
seg = (urllib.quote(s.strip('/')) for s in seg)
|
||||
if query is None or len(query) == 0:
|
||||
query_string = ''
|
||||
else:
|
||||
query_string = '?' + urllib.urlencode(query)
|
||||
path = '/'.join(seg) + query_string
|
||||
adjusted_base = base.rstrip('/') + '/'
|
||||
return urlparse.urljoin(adjusted_base, path)
|
||||
|
||||
|
||||
def xml_property(path, converter=lambda x: x.text):
|
||||
|
||||
def getter(self):
|
||||
if path in self.dirty:
|
||||
return self.dirty[path]
|
||||
else:
|
||||
if self.dom is None:
|
||||
self.fetch()
|
||||
node = self.dom.find(path)
|
||||
return (converter(self.dom.find(path)) if node
|
||||
is not None else None)
|
||||
|
||||
def setter(self, value):
|
||||
self.dirty[path] = value
|
||||
|
||||
def delete(self):
|
||||
self.dirty[path] = None
|
||||
|
||||
return property(getter, setter, delete)
|
||||
|
||||
|
||||
def bbox(node):
|
||||
if node is not None:
|
||||
minx = node.find('minx')
|
||||
maxx = node.find('maxx')
|
||||
miny = node.find('miny')
|
||||
maxy = node.find('maxy')
|
||||
crs = node.find('crs')
|
||||
crs = (crs.text if crs is not None else None)
|
||||
|
||||
if None not in [minx, maxx, miny, maxy]:
|
||||
return (minx.text, maxx.text, miny.text, maxy.text, crs)
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def string_list(node):
|
||||
if node is not None:
|
||||
return [n.text for n in node.findall('string')]
|
||||
|
||||
|
||||
def attribute_list(node):
|
||||
if node is not None:
|
||||
return [n.text for n in node.findall('attribute/name')]
|
||||
|
||||
|
||||
def key_value_pairs(node):
|
||||
if node is not None:
|
||||
return dict((entry.attrib['key'], entry.text) for entry in
|
||||
node.findall('entry'))
|
||||
|
||||
|
||||
def write_string(name):
|
||||
|
||||
def write(builder, value):
|
||||
builder.start(name, dict())
|
||||
if value is not None:
|
||||
builder.data(value)
|
||||
builder.end(name)
|
||||
|
||||
return write
|
||||
|
||||
|
||||
def write_bool(name):
|
||||
|
||||
def write(builder, b):
|
||||
builder.start(name, dict())
|
||||
builder.data(('true' if b else 'false'))
|
||||
builder.end(name)
|
||||
|
||||
return write
|
||||
|
||||
|
||||
def write_bbox(name):
|
||||
|
||||
def write(builder, b):
|
||||
builder.start(name, dict())
|
||||
bbox_xml(builder, b)
|
||||
builder.end(name)
|
||||
|
||||
return write
|
||||
|
||||
|
||||
def write_string_list(name):
|
||||
|
||||
def write(builder, words):
|
||||
builder.start(name, dict())
|
||||
for w in words:
|
||||
builder.start('string', dict())
|
||||
builder.data(w)
|
||||
builder.end('string')
|
||||
builder.end(name)
|
||||
|
||||
return write
|
||||
|
||||
|
||||
def write_dict(name):
|
||||
|
||||
def write(builder, pairs):
|
||||
builder.start(name, dict())
|
||||
for (k, v) in pairs.iteritems():
|
||||
builder.start('entry', dict(key=k))
|
||||
builder.data(v)
|
||||
builder.end('entry')
|
||||
builder.end(name)
|
||||
|
||||
return write
|
||||
|
||||
|
||||
class ResourceInfo(object):
|
||||
|
||||
def __init__(self):
|
||||
self.dom = None
|
||||
self.dirty = dict()
|
||||
|
||||
def fetch(self):
|
||||
self.dom = self.catalog.get_xml(self.href)
|
||||
|
||||
def clear(self):
|
||||
self.dirty = dict()
|
||||
|
||||
def refresh(self):
|
||||
self.clear()
|
||||
self.fetch()
|
||||
|
||||
def serialize(self, builder):
|
||||
# GeoServer will disable the resource if we omit the <enabled>
|
||||
# tag, so force it into the dirty dict before writing
|
||||
if hasattr(self, 'enabled'):
|
||||
self.dirty['enabled'] = self.enabled
|
||||
|
||||
for (k, writer) in self.writers.items():
|
||||
if k in self.dirty:
|
||||
writer(builder, self.dirty[k])
|
||||
|
||||
def message(self):
|
||||
builder = TreeBuilder()
|
||||
builder.start(self.resource_type, dict())
|
||||
self.serialize(builder)
|
||||
builder.end(self.resource_type)
|
||||
msg = tostring(builder.close())
|
||||
return msg
|
||||
|
||||
|
||||
def prepare_upload_bundle(name, data):
|
||||
"""GeoServer's REST API uses ZIP archives as containers for file
|
||||
formats such as Shapefile and WorldImage which include several
|
||||
'boxcar' files alongside the main data.
|
||||
|
||||
In such archives, GeoServer assumes that all of the relevant files
|
||||
will have the same base name and appropriate extensions, and live
|
||||
in the root of the ZIP archive. This method produces a zip file
|
||||
that matches these expectations, based on a basename, and a dict of
|
||||
extensions to paths or file-like objects. The client code is
|
||||
responsible for deleting the zip archive when it's done.
|
||||
"""
|
||||
|
||||
# We put the zip file in the Processing temp dir, so it is
|
||||
# deleted at the end.
|
||||
f = getTempFilename('zip')
|
||||
zip_file = ZipFile(f, 'w')
|
||||
for (ext, stream) in data.iteritems():
|
||||
fname = '%s.%s' % (name, ext)
|
||||
if isinstance(stream, basestring):
|
||||
zip_file.write(stream, fname)
|
||||
else:
|
||||
zip_file.writestr(fname, stream.read())
|
||||
zip_file.close()
|
||||
return f
|
||||
|
||||
|
||||
def atom_link(node):
|
||||
if 'href' in node.attrib:
|
||||
return node.attrib['href']
|
||||
else:
|
||||
l = node.find('{http://www.w3.org/2005/Atom}link')
|
||||
return l.get('href')
|
||||
|
||||
|
||||
def atom_link_xml(builder, href):
|
||||
builder.start('atom:link', {
|
||||
'rel': 'alternate',
|
||||
'href': href,
|
||||
'type': 'application/xml',
|
||||
'xmlns:atom': 'http://www.w3.org/2005/Atom',
|
||||
})
|
||||
builder.end('atom:link')
|
||||
|
||||
|
||||
def bbox_xml(builder, box):
|
||||
(minx, maxx, miny, maxy, crs) = box
|
||||
builder.start('minx', dict())
|
||||
builder.data(minx)
|
||||
builder.end('minx')
|
||||
builder.start('maxx', dict())
|
||||
builder.data(maxx)
|
||||
builder.end('maxx')
|
||||
builder.start('miny', dict())
|
||||
builder.data(miny)
|
||||
builder.end('miny')
|
||||
builder.start('maxy', dict())
|
||||
builder.data(maxy)
|
||||
builder.end('maxy')
|
||||
if crs is not None:
|
||||
builder.start('crs', {'class': 'projected'})
|
||||
builder.data(crs)
|
||||
builder.end('crs')
|
@ -1,31 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
util.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by David Winslow
|
||||
Email : dwins at opengeo dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'David Winslow'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, David Winslow'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
|
||||
def shapefile_and_friends(path):
|
||||
return dict((ext, path + '.' + ext) for ext in ['shx', 'shp', 'dbf', 'prj'
|
||||
])
|
@ -1,65 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
workspace.py
|
||||
---------------------
|
||||
Date : November 2012
|
||||
Copyright : (C) 2012 by David Winslow
|
||||
Email : dwins at opengeo dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'David Winslow'
|
||||
__date__ = 'November 2012'
|
||||
__copyright__ = '(C) 2012, David Winslow'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from support import xml_property, write_bool, \
|
||||
ResourceInfo, url
|
||||
|
||||
|
||||
def workspace_from_index(catalog, node):
|
||||
name = node.find('name')
|
||||
return Workspace(catalog, name.text)
|
||||
|
||||
|
||||
class Workspace(ResourceInfo):
|
||||
|
||||
resource_type = 'workspace'
|
||||
|
||||
def __init__(self, catalog, name):
|
||||
super(Workspace, self).__init__()
|
||||
self.catalog = catalog
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def href(self):
|
||||
return url(self.catalog.service_url, ['workspaces', self.name + '.xml'
|
||||
])
|
||||
|
||||
@property
|
||||
def coveragestore_url(self):
|
||||
return url(self.catalog.service_url, ['workspaces', self.name,
|
||||
'coveragestores.xml'])
|
||||
|
||||
@property
|
||||
def datastore_url(self):
|
||||
return url(self.catalog.service_url, ['workspaces', self.name,
|
||||
'datastores.xml'])
|
||||
|
||||
enabled = xml_property('enabled', lambda x: x.lower() == 'true')
|
||||
writers = dict(enabled=write_bool('enabled'))
|
||||
|
||||
def __repr__(self):
|
||||
return '%s @ %s' % (self.name, self.href)
|
@ -38,7 +38,7 @@ from processing.parameters.ParameterString import ParameterString
|
||||
from processing.parameters.ParameterSelection import ParameterSelection
|
||||
from processing.parameters.ParameterTableField import ParameterTableField
|
||||
from processing.tools import dataobjects
|
||||
import postgis_utils
|
||||
from processing.algs.qgis import postgis_utils
|
||||
|
||||
|
||||
class ImportIntoPostGIS(GeoAlgorithm):
|
||||
@ -54,9 +54,6 @@ class ImportIntoPostGIS(GeoAlgorithm):
|
||||
DROP_STRING_LENGTH = 'DROP_STRING_LENGTH'
|
||||
PRIMARY_KEY = 'PRIMARY_KEY'
|
||||
|
||||
def getIcon(self):
|
||||
return QIcon(os.path.dirname(__file__) + '/../../images/postgis.png')
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
connection = self.DB_CONNECTIONS[self.getParameterValue(self.DATABASE)]
|
||||
schema = self.getParameterValue(self.SCHEMA)
|
||||
@ -135,7 +132,7 @@ class ImportIntoPostGIS(GeoAlgorithm):
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.name = 'Import into PostGIS'
|
||||
self.group = 'PostGIS management tools'
|
||||
self.group = 'Database'
|
||||
self.addParameter(ParameterVector(self.INPUT, 'Layer to import'))
|
||||
|
||||
self.DB_CONNECTIONS = self.dbConnectionNames()
|
@ -33,7 +33,7 @@ from processing.core.GeoAlgorithm import GeoAlgorithm
|
||||
from processing.core.GeoAlgorithmExecutionException import \
|
||||
GeoAlgorithmExecutionException
|
||||
from processing.parameters.ParameterString import ParameterString
|
||||
import postgis_utils
|
||||
from processing.algs.qgis import postgis_utils
|
||||
|
||||
|
||||
class PostGISExecuteSQL(GeoAlgorithm):
|
||||
@ -41,11 +41,7 @@ class PostGISExecuteSQL(GeoAlgorithm):
|
||||
DATABASE = 'DATABASE'
|
||||
SQL = 'SQL'
|
||||
|
||||
def getIcon(self):
|
||||
return QIcon(os.path.dirname(__file__) + '/../../images/postgis.png')
|
||||
|
||||
def processAlgorithm(self, progress):
|
||||
|
||||
connection = self.getParameterValue(self.DATABASE)
|
||||
settings = QSettings()
|
||||
mySettings = '/PostgreSQL/connections/' + connection
|
||||
@ -74,6 +70,6 @@ class PostGISExecuteSQL(GeoAlgorithm):
|
||||
|
||||
def defineCharacteristics(self):
|
||||
self.name = 'PostGIS execute SQL'
|
||||
self.group = 'PostGIS management tools'
|
||||
self.group = 'Database'
|
||||
self.addParameter(ParameterString(self.DATABASE, 'Database'))
|
||||
self.addParameter(ParameterString(self.SQL, 'SQL query', '', True))
|
@ -17,6 +17,7 @@
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'December 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
@ -96,7 +97,8 @@ from RandomPointsPolygonsFixed import RandomPointsPolygonsFixed
|
||||
from RandomPointsPolygonsVariable import RandomPointsPolygonsVariable
|
||||
from RandomPointsAlongLines import RandomPointsAlongLines
|
||||
from PointsToPaths import PointsToPaths
|
||||
|
||||
from PostGISExecuteSQL import PostGISExecuteSQL
|
||||
from ImportIntoPostGIS import ImportIntoPostGIS
|
||||
# from VectorLayerHistogram import VectorLayerHistogram
|
||||
# from VectorLayerScatterplot import VectorLayerScatterplot
|
||||
# from MeanAndStdDevPlot import MeanAndStdDevPlot
|
||||
@ -152,6 +154,7 @@ class QGISAlgorithmProvider(AlgorithmProvider):
|
||||
RandomPointsLayer(), RandomPointsPolygonsFixed(),
|
||||
RandomPointsPolygonsVariable(),
|
||||
RandomPointsAlongLines(), PointsToPaths(),
|
||||
PostGISExecuteSQL(), ImportIntoPostGIS()
|
||||
# ------ raster ------
|
||||
# CreateConstantRaster(),
|
||||
# ------ graphics ------
|
||||
|
@ -57,8 +57,6 @@ from processing.algs.r.RAlgorithmProvider import RAlgorithmProvider
|
||||
from processing.algs.saga.SagaAlgorithmProvider import SagaAlgorithmProvider
|
||||
from processing.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider
|
||||
from processing.algs.taudem.TauDEMAlgorithmProvider import TauDEMAlgorithmProvider
|
||||
from processing.algs.admintools.AdminToolsAlgorithmProvider import \
|
||||
AdminToolsAlgorithmProvider
|
||||
from processing.tools import dataobjects
|
||||
|
||||
|
||||
@ -143,7 +141,6 @@ class Processing:
|
||||
Processing.addProvider(Grass7AlgorithmProvider())
|
||||
Processing.addProvider(ScriptAlgorithmProvider())
|
||||
Processing.addProvider(TauDEMAlgorithmProvider())
|
||||
Processing.addProvider(AdminToolsAlgorithmProvider())
|
||||
Processing.modeler.initializeSettings()
|
||||
|
||||
# And initialize
|
||||
|
Loading…
x
Reference in New Issue
Block a user