1682
1668
msg += "Content-Type: text/plain\n\n"
1683
1669
msg += "Some unexpected error occurred. Error text was: %s" % str(E)
1688
######################
1689
# Deprecated Functions
1690
######################
1695
Provide the Enabled Layers
1698
from gluon.tools import fetch
1700
response.warning = ""
1705
layers.openstreetmap = Storage()
1706
layers_openstreetmap = db(db.gis_layer_openstreetmap.enabled == True).select()
1707
for layer in layers_openstreetmap:
1708
for subtype in gis_layer_openstreetmap_subtypes:
1709
if layer.subtype == subtype:
1710
layers.openstreetmap["%s" % subtype] = layer.name
1713
layers.google = Storage()
1714
# Check for Google Key
1716
layers.google.key = db(db.gis_apikey.name == "google").select(db.gis_apikey.apikey).first().apikey
1717
layers_google = db(db.gis_layer_google.enabled == True).select()
1718
for layer in layers_google:
1719
for subtype in gis_layer_google_subtypes:
1720
if layer.subtype == subtype:
1721
layers.google["%s" % subtype] = layer.name
1722
layers.google.enabled = 1
1724
# Redirect to Key entry screen
1725
session.warning = T("Please enter a Google Key if you wish to use Google Layers")
1726
redirect(URL(r=request, f=apikey))
1729
layers.yahoo = Storage()
1730
# Check for Yahoo Key
1732
layers.yahoo.key = db(db.gis_apikey.name == "yahoo").select(db.gis_apikey.apikey).first().apikey
1733
layers_yahoo = db(db.gis_layer_yahoo.enabled == True).select()
1734
for layer in layers_yahoo:
1735
for subtype in gis_layer_yahoo_subtypes:
1736
if layer.subtype == subtype:
1737
layers.yahoo["%s" % subtype] = layer.name
1738
layers.yahoo.enabled = 1
1740
# Redirect to Key entry screen
1741
session.warning = T("Please enter a Yahoo Key if you wish to use Yahoo Layers")
1742
redirect(URL(r=request, f=apikey))
1744
# Bing (Virtual Earth)
1745
# Broken in GeoExt: http://www.geoext.org/pipermail/users/2009-December/000393.html
1746
#layers.bing = Storage()
1747
#layers_bing = db(db.gis_layer_bing.enabled == True).select()
1748
#for layer in layers_bing:
1749
# for subtype in gis_layer_bing_subtypes:
1750
# if layer.subtype == subtype:
1751
# layers.bing["%s" % subtype] = layer.name
1754
layers.gpx = Storage()
1755
layers_gpx = db(db.gis_layer_gpx.enabled == True).select()
1756
for layer in layers_gpx:
1758
layers.gpx[name] = Storage()
1759
track = db(db.gis_track.id == layer.track_id).select(limitby=(0, 1)).first()
1760
layers.gpx[name].url = track.track
1762
layers.gpx[name].marker = db(db.gis_marker.id == layer.marker_id).select(db.gis_marker.image, limitby=(0, 1)).first().image
1764
marker_id = db(db.gis_config.id == 1).select(db.gis_config.marker_id, limitby=(0, 1)).first().marker_id
1765
layers.gpx[name].marker = db(db.gis_marker.id == marker_id).select(db.gis_marker.image, limitby=(0, 1)).first().image
1767
cachepath = os.path.join(request.folder, "uploads", "gis_cache")
1768
if os.access(cachepath, os.W_OK):
1774
layers.georss = Storage()
1775
layers_georss = db(db.gis_layer_georss.enabled == True).select()
1776
if layers_georss and not cache:
1777
response.warning += cachepath + " " + str(T("not writable - unable to cache GeoRSS layers!")) + "\n"
1778
for layer in layers_georss:
1782
filename = "gis_cache.file." + name.replace(" ", "_") + ".rss"
1783
filepath = os.path.join(cachepath, filename)
1785
# Download file to cache
1787
f = open(filepath, "w")
1790
records = db(db.gis_cache.name == name).select()
1792
records[0].update(modified_on=response.utcnow)
1794
db.gis_cache.insert(name=name, file=filename)
1795
url = URL(r=request, c="default", f="download", args=[filename])
1798
if os.access(filepath, os.R_OK):
1799
# Use cached version
1800
date = db(db.gis_cache.name == name).select(db.gis_cache.modified_on, limitby=(0, 1)).first().modified_on
1801
response.warning += url + " " + str(T("not accessible - using cached version from")) + " " + str(date) + "\n"
1802
url = URL(r=request, c="default", f="download", args=[filename])
1804
# No cached version available
1805
response.warning += url + " " + str(T("not accessible - no cached version available!")) + "\n"
1809
# No caching possible (e.g. GAE), display file direct from remote (using Proxy)
1813
layers.georss[name] = Storage()
1814
layers.georss[name].url = url
1815
layers.georss[name].projection = db(db.gis_projection.id == layer.projection_id).select(db.gis_projection.epsg, limitby=(0, 1)).first().epsg
1817
layers.georss[name].marker = db(db.gis_marker.id == layer.marker_id).select(db.gis_marker.image, limitby=(0, 1)).first().image
1819
marker_id = db(db.gis_config.id == 1).select(db.gis_config.marker_id, limitby=(0, 1)).first().marker_id
1820
layers.georss[name].marker = db(db.gis_marker.id == marker_id).select(db.gis_marker.image, limitby=(0, 1)).first().image
1823
layers.kml = Storage()
1824
layers_kml = db(db.gis_layer_kml.enabled == True).select()
1825
if layers_kml and not cache:
1826
response.warning += cachepath + " " + str(T("not writable - unable to cache KML layers!")) + "\n"
1828
# Append dynamic feed:
1829
# /gis/map_viewing_client?kml_feed=<url>&kml_name=<feed_name>
1830
layers_kml = [Storage(name=l.name, url=l.url) for l in layers_kml]
1831
if "kml_feed" in request.vars and "kml_name" in request.vars:
1832
layers_kml.append(Storage(name=request.vars["kml_name"], url=request.vars["kml_feed"]))
1834
for layer in layers_kml:
1838
filename = "gis_cache.file." + name.replace(" ", "_") + ".kml"
1839
filepath = os.path.join(cachepath, filename)
1841
file, warning = gis.download_kml(url, deployment_settings.get_base_public_url())
1843
if "URLError" in warning or "HTTPError" in warning:
1845
if os.access(filepath, os.R_OK):
1846
# Use cached version
1847
date = db(db.gis_cache.name == name).select(db.gis_cache.modified_on, limitby=(0, 1)).first().modified_on
1848
response.warning += url + " " + str(T("not accessible - using cached version from")) + " " + str(date) + "\n"
1849
url = URL(r=request, c="default", f="download", args=[filename])
1851
# No cached version available
1852
response.warning += url + " " + str(T("not accessible - no cached version available!")) + "\n"
1856
# Download was succesful
1857
if "ParseError" in warning:
1858
# @ToDo Parse detail
1859
response.warning += str(T("Layer")) + ": " + name + " " + str(T("couldn't be parsed so NetworkLinks not followed.")) + "\n"
1860
if "GroundOverlay" in warning or "ScreenOverlay" in warning:
1861
response.warning += str(T("Layer")) + ": " + name + " " + str(T("includes a GroundOverlay or ScreenOverlay which aren't supported in OpenLayers yet, so it may not work properly.")) + "\n"
1862
# Write file to cache
1863
f = open(filepath, "w")
1866
records = db(db.gis_cache.name == name).select()
1868
records[0].update(modified_on=response.utcnow)
1870
db.gis_cache.insert(name=name, file=filename)
1871
url = URL(r=request, c="default", f="download", args=[filename])
1873
# No caching possible (e.g. GAE), display file direct from remote (using Proxy)
1877
layers.kml[name] = Storage()
1878
layers.kml[name].url = url
1881
layers.wms = Storage()
1882
layers_wms = db(db.gis_layer_wms.enabled == True).select()
1883
for layer in layers_wms:
1885
layers.wms[name] = Storage()
1886
layers.wms[name].url = layer.url
1887
layers.wms[name].base = layer.base
1889
layers.wms[name].map = layer.map
1890
layers.wms[name].layers = layer.layers
1891
layers.wms[name].projection = db(db.gis_projection.id == layer.projection_id).select(db.gis_projection.epsg, limitby=(0, 1)).first().epsg
1892
layers.wms[name].transparent = layer.transparent
1894
layers.wms[name].format = layer.format
1897
layers.tms = Storage()
1898
layers_tms = db(db.gis_layer_tms.enabled == True).select()
1899
for layer in layers_tms:
1901
layers.tms[name] = Storage()
1902
layers.tms[name].url = layer.url
1903
layers.tms[name].layers = layer.layers
1905
layers.tms[name].format = layer.format
1907
# MGRS - only a single one of these should be defined & it actually appears as a Control not a Layer
1908
mgrs = db(db.gis_layer_mgrs.enabled == True).select(limitby=(0, 1)).first()
1910
layers.mgrs = Storage()
1911
layers.mgrs.name = mgrs.name
1912
layers.mgrs.url = mgrs.url
1915
layers.xyz = Storage()
1916
layers_xyz = db(db.gis_layer_xyz.enabled == True).select()
1917
for layer in layers_xyz:
1919
layers.xyz[name] = Storage()
1920
layers.xyz[name].url = layer.url
1921
layers.xyz[name].base = layer.base
1922
layers.xyz[name].sphericalMercator = layer.sphericalMercator
1923
layers.xyz[name].transitionEffect = layer.transitionEffect
1924
layers.xyz[name].numZoomLevels = layer.numZoomLevels
1925
layers.xyz[name].transparent = layer.transparent
1926
layers.xyz[name].visible = layer.visible
1927
layers.xyz[name].opacity = layer.opacity
1930
layers.js = Storage()
1931
layers_js = db(db.gis_layer_js.enabled == True).select()
1932
for layer in layers_js:
1934
layers.js[name] = Storage()
1935
layers.js[name].code = layer.code
1939
def display_feature_old():
1942
Cut-down version of the Map Viewing Client.
1943
Used as a .represent for location_id to show just this feature on the map.
1947
feature_id = request.args(0)
1948
feature = db(db.gis_location.id == feature_id).select(limitby=(0, 1)).first()
1950
# Check user is authorised to access record
1951
if not shn_has_permission("read", db.gis_location, feature.id):
1952
session.error = str(T("No access to this record!"))
1953
raise HTTP(401, body=s3xrc.xml.json_message(False, 401, session.error))
1956
config = gis.get_config()
1957
width = config.map_width
1958
height = config.map_height
1959
numZoomLevels = config.zoom_levels
1960
projection = config.epsg
1961
# Support bookmarks (such as from the control)
1962
if "lat" in request.vars:
1963
lat = request.vars.lat
1966
if "lon" in request.vars:
1967
lon = request.vars.lon
1970
if "zoom" in request.vars:
1971
zoom = request.vars.zoom
1974
units = config.units
1975
maxResolution = config.maxResolution
1976
maxExtent = config.maxExtent
1977
marker_default = config.marker_id
1978
cluster_distance = config.cluster_distance
1979
cluster_threshold = config.cluster_threshold
1980
layout = config.opt_gis_layout
1982
# Add the config to the Return
1983
output = dict(width=width, height=height, numZoomLevels=numZoomLevels, projection=projection, lat=lat, lon=lon, zoom=zoom, units=units, maxResolution=maxResolution, maxExtent=maxExtent, cluster_distance=cluster_distance, cluster_threshold=cluster_threshold, layout=layout)
1987
feature_class = db(db.gis_feature_class.id == feature.feature_class_id).select(limitby=(0, 1)).first()
1988
feature.module = feature_class.module
1989
feature.resource = feature_class.resource
1991
feature_class = None
1992
feature.module = None
1993
feature.resource = None
1994
if feature.module and feature.resource:
1995
_resource = db["%s_%s" % (feature.module, feature.resource)]
1996
feature.resource_id = db(_resource.location_id == feature.id).select(_resource.id, limitby=(0, 1)).first().id
1998
feature.resource_id = None
1999
# provide an extra access so no need to duplicate popups code
2000
feature.gis_location = Storage()
2001
feature.gis_location = feature
2002
feature.gis_feature_class = feature_class
2004
# Look up the marker to display
2005
feature.marker = gis.get_marker(feature_id)
2008
# Metadata is M->1 to Features
2009
# We use the most recent one
2010
query = (db.doc_metadata.location_id == feature.id) & (db.doc_metadata.deleted == False)
2011
metadata = db(query).select(orderby=~db.doc_metadata.event_time).first()
2013
# Person .represent is too complex to put into JOIN
2014
contact = shn_pr_person_represent(metadata.person_id)
2019
feature.metadata = metadata
2020
feature.contact = contact
2023
# Images are M->1 to Features
2024
# We use the most recently uploaded one
2025
query = (db.doc_image.location_id == feature.id) & (db.doc_image.deleted == False)
2026
image = db(query).select(db.doc_image.image, orderby=~db.doc_image.created_on).first().image
2029
feature.image = image
2031
# Add the feature to the Return
2032
output.update(dict(feature=feature))
2035
baselayers = layers()
2036
# Add the Base Layers to the Return
2037
output.update(dict(openstreetmap=baselayers.openstreetmap, google=baselayers.google, yahoo=baselayers.yahoo, bing=baselayers.bing, tms_layers=baselayers.tms, wms_layers=baselayers.wms, xyz_layers=baselayers.xyz))
2038
# Don't want confusing overlays
2039
output.update(dict(georss_layers=[], gpx_layers=[], kml_layers=[], js_layers=[], mgrs=[]))
2043
def display_features_old():
2046
Cut-down version of the Map Viewing Client.
2047
Used as a link from the RHeader.
2048
URL generated server-side
2049
Shows all locations matching a query.
2050
Most recent location is marked using a bigger Marker.
2053
# Parse the URL, check for implicit resources, extract the primary record
2054
# http://127.0.0.1:8000/sahana/gis/display_features&module=pr&resource=person&instance=1&jresource=presence
2056
if "module" in request.vars:
2057
res_module = request.vars.module
2059
if "resource" in request.vars:
2060
resource = request.vars.resource
2062
if "instance" in request.vars:
2063
instance = int(request.vars.instance)
2065
if "jresource" in request.vars:
2066
jresource = request.vars.jresource
2069
session.error = str(T("Insufficient vars: Need module, resource, jresource, instance"))
2070
raise HTTP(400, body=s3xrc.xml.json_message(False, 400, session.error))
2072
component, pkey, fkey = s3xrc.model.get_component(res_module, resource, jresource)
2073
table = db["%s_%s" % (res_module, resource)]
2074
jtable = db[str(component.table)]
2075
query = (jtable[fkey] == table[pkey]) & (table.id == instance)
2076
# Filter out deleted
2077
deleted = (table.deleted == False)
2078
query = query & deleted
2079
# Filter out inaccessible
2080
query2 = db.gis_location.id == jtable.location_id
2081
accessible = shn_accessible_query("read", db.gis_location)
2082
query2 = query2 & accessible
2084
features = db(query).select(db.gis_location.ALL, left = [db.gis_location.on(query2)])
2086
# Implicit case for instance requires:
2087
#request = the_web2py_way_to_build_a_request_from_url(button-data)
2088
#jr = s3xrc.request(request)
2089
#xml_tree = jr.export_xml()
2090
#retrieve the location_id's from xml_tree using XPath
2092
# Calculate an appropriate BBox
2093
bounds = gis.get_bounds(features=features)
2094
lon_max = bounds["max_lon"]
2095
lon_min = bounds["min_lon"]
2096
lat_max = bounds["max_lat"]
2097
lat_min = bounds["min_lat"]
2099
#bbox = str(lon_min) + "," + str(lat_min) + "," + str(lon_max) + "," + str(lat_max)
2100
#We now project these client-side, so pass raw info (client-side projection means less server-side dependencies)
2101
output = dict(lon_max=lon_max, lon_min=lon_min, lat_max=lat_max, lat_min=lat_min)
2104
config = gis.get_config()
2105
width = config.map_width
2106
height = config.map_height
2107
numZoomLevels = config.zoom_levels
2108
projection = config.epsg
2109
# Support bookmarks (such as from the control)
2110
if "lat" in request.vars:
2111
lat = request.vars.lat
2114
if "lon" in request.vars:
2115
lon = request.vars.lon
2118
if "zoom" in request.vars:
2119
zoom = request.vars.zoom
2122
units = config.units
2123
maxResolution = config.maxResolution
2124
maxExtent = config.maxExtent
2125
marker_default = config.marker_id
2126
cluster_distance = config.cluster_distance
2127
cluster_threshold = config.cluster_threshold
2128
layout = config.opt_gis_layout
2130
# Add the config to the Return
2131
output.update(dict(width=width, height=height, numZoomLevels=numZoomLevels, projection=projection, lat=lat, lon=lon, zoom=zoom, units=units, maxResolution=maxResolution, maxExtent=maxExtent, cluster_distance=cluster_distance, cluster_threshold=cluster_threshold, layout=layout))
2134
for feature in features:
2136
feature_class = db(db.gis_feature_class.id == feature.feature_class_id).select(limitby=(0, 1)).first()
2138
feature_class = None
2139
feature.module = feature_class.module
2140
feature.resource = feature_class.resource
2141
if feature.module and feature.resource:
2143
_resource = db["%s_%s" % (feature.module, feature.resource)]
2144
feature.resource_id = db(_resource.location_id == feature.id).select(_resource.id, limitby=(0, 1)).first().id
2146
feature.resource_id = None
2148
feature.resource_id = None
2149
# provide an extra access so no need to duplicate popups code
2150
feature.gis_location = Storage()
2151
feature.gis_location = feature
2152
feature.gis_feature_class = feature_class
2154
# Look up the marker to display
2155
feature.marker = gis.get_marker(feature.id)
2158
# Metadata is M->1 to Features
2159
# We use the most recent one
2160
query = (db.doc_metadata.location_id == feature.id) & (db.doc_metadata.deleted == False)
2161
metadata = db(query).select(orderby=~db.doc_metadata.event_time).first()
2163
# Person .represent is too complex to put into JOIN
2164
contact = shn_pr_person_represent(metadata.person_id)
2169
feature.metadata = metadata
2170
feature.contact = contact
2173
# Images are M->1 to Features
2174
# We use the most recently uploaded one
2175
query = (db.doc_image.location_id == feature.id) & (db.doc_image.deleted == False)
2176
image = db(query).select(orderby=~db.doc_image.created_on, limitby=(0, 1)).first().image
2179
feature.image = image
2181
# Add the features to the Return
2182
output.update(dict(features=features))
2185
baselayers = layers()
2186
# Add the Base Layers to the Return
2187
output.update(dict(openstreetmap=baselayers.openstreetmap, google=baselayers.google, yahoo=baselayers.yahoo, bing=baselayers.bing, tms_layers=baselayers.tms, wms_layers=baselayers.wms, xyz_layers=baselayers.xyz))
2188
# Don't want confusing overlays
2189
output.update(dict(georss_layers=[], gpx_layers=[], kml_layers=[], js_layers=[], mgrs=[]))
2193
def map_viewing_client_old():
2196
Main user UI for viewing the Maps with associated Features
2199
title = T("Map Viewing Client")
2200
response.title = title
2202
# Start building the Return with the Framework
2203
output = dict(title=title, )
2206
# ToDo return all of these to the view via a single 'config' var
2207
config = gis.get_config()
2208
width = config.map_width
2209
height = config.map_height
2210
numZoomLevels = config.zoom_levels
2211
projection = config.epsg
2212
# Support bookmarks (such as from the control)
2213
if "lat" in request.vars:
2214
lat = request.vars.lat
2217
if "lon" in request.vars:
2218
lon = request.vars.lon
2221
if "zoom" in request.vars:
2222
zoom = request.vars.zoom
2225
units = config.units
2226
maxResolution = config.maxResolution
2227
maxExtent = config.maxExtent
2228
marker_default = config.marker_id
2229
cluster_distance = config.cluster_distance
2230
cluster_threshold = config.cluster_threshold
2231
layout = config.opt_gis_layout
2233
# Add the Config to the Return
2234
output.update(dict(width=width, height=height, numZoomLevels=numZoomLevels, projection=projection, lat=lat, lon=lon, zoom=zoom, units=units, maxResolution=maxResolution, maxExtent=maxExtent, cluster_distance=cluster_distance, cluster_threshold=cluster_threshold, layout=layout))
2237
baselayers = layers()
2238
# Add the Layers to the Return
2239
output.update(dict(openstreetmap=baselayers.openstreetmap, google=baselayers.google, yahoo=baselayers.yahoo, bing=baselayers.bing, tms_layers=baselayers.tms, wms_layers=baselayers.wms, xyz_layers=baselayers.xyz))
2240
output.update(dict(georss_layers=baselayers.georss, gpx_layers=baselayers.gpx, js_layers=baselayers.js, kml_layers=baselayers.kml))
2241
# MGRS isn't a Layer, it's a Control, but added here anyway
2242
output.update(dict(mgrs=baselayers.mgrs))
2245
features = Storage()
2246
# Features are displayed in a layer per FeatureGroup
2247
feature_groups = db(db.gis_feature_group.enabled == True).select()
2248
for feature_group in feature_groups:
2249
groups = db.gis_feature_group
2250
locations = db.gis_location
2251
classes = db.gis_feature_class
2252
metadata = db.doc_metadata
2253
# Which Features are added to the Group directly?
2254
# ^^ No longer supported, for simplicity
2255
#link = db.gis_location_to_feature_group
2256
# JOINs are efficient for RDBMS but not compatible with GAE
2257
#features1 = db(link.feature_group_id == feature_group.id).select(groups.ALL, locations.ALL, classes.ALL, left=[groups.on(groups.id == link.feature_group_id), locations.on(locations.id == link.location_id), classes.on(classes.id == locations.feature_class_id)])
2258
# FIXME?: Extend JOIN for Metadata (sortby, want 1 only), Markers (complex logic), Resource_id (need to find from the results of prev query)
2259
# Which Features are added to the Group via their FeatureClass?
2260
link = db.gis_feature_class_to_feature_group
2261
features2 = db(link.feature_group_id == feature_group.id).select(groups.ALL, locations.ALL, classes.ALL, left=[groups.on(groups.id == link.feature_group_id), classes.on(classes.id == link.feature_class_id), locations.on(locations.feature_class_id == link.feature_class_id)])
2262
# FIXME?: Extend JOIN for Metadata (sortby, want 1 only), Markers (complex logic), Resource_id (need to find from the results of prev query)
2263
#features[feature_group.id] = features1 | features2
2264
features[feature_group.id] = features2
2265
for feature in features[feature_group.id]:
2267
# Deprecated since we'll be using KML to populate Popups with Edit URLs, etc
2268
feature.module = feature.gis_feature_class.module
2269
feature.resource = feature.gis_feature_class.resource
2270
if feature.module and feature.resource:
2272
_resource = db["%s_%s" % (feature.module, feature.resource)]
2273
feature.resource_id = db(_resource.location_id == feature.gis_location.id).select(_resource.id, limitby=(0, 1)).first().id
2275
feature.resource_id = None
2277
feature.resource_id = None
2279
# Look up the marker to display
2280
feature.marker = gis.get_marker(feature.gis_location.id)
2283
# Metadata is M->1 to Features
2284
# We use the most recent one
2285
query = (db.doc_metadata.location_id == feature.gis_location.id) & (db.doc_metadata.deleted == False)
2286
metadata = db(query).select(orderby=~db.doc_metadata.event_time).first()
2288
# Person .represent is too complex to put into JOIN
2289
contact = shn_pr_person_represent(metadata.person_id)
2294
feature.metadata = metadata
2295
feature.contact = contact
2298
# Images are M->1 to Features
2299
# We use the most recently uploaded one
2300
query = (db.doc_image.location_id == feature.gis_location.id) & (db.doc_image.deleted == False)
2301
image = db(query).select(db.doc_image.image, orderby=~db.doc_image.created_on).first().image
2304
feature.image = image
2308
# Add the Features to the Return
2309
#output.update(dict(features=features, features_classes=feature_classes, features_markers=feature_markers, features_metadata=feature_metadata))
2310
output.update(dict(feature_groups=feature_groups, features=features))