def test_layer_bbox(self): lyr = Layer.objects.all().first() layer_bbox = lyr.bbox[0:4] logger.info(layer_bbox) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) # Must be in the form : [x0, x1, y0, y1 return [_bbox[0], _bbox[2], _bbox[1], _bbox[3]] from geonode.utils import bbox_to_projection projected_bbox = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ lyr.srid, ], target_srid=4326)[:4]) logger.info(projected_bbox) self.assertEquals(projected_bbox, [-180.0, -90.0, 180.0, 90.0]) logger.info(lyr.ll_bbox) self.assertEquals(lyr.ll_bbox, [-180.0, 180.0, -90.0, 90.0, u'EPSG:4326']) projected_bbox = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ lyr.srid, ], target_srid=3857)[:4]) logger.info(projected_bbox) self.assertEquals( projected_bbox, [-20037397.0233, -74299743.4007, 20037397.0233, 74299743.4006])
def test_layer_bbox(self): lyr = Layer.objects.all().first() layer_bbox = lyr.bbox[0:4] logger.info(layer_bbox) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) # Must be in the form : [x0, x1, y0, y1 return [_bbox[0], _bbox[2], _bbox[1], _bbox[3]] from geonode.utils import bbox_to_projection projected_bbox = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [lyr.srid, ], target_srid=4326)[:4]) logger.info(projected_bbox) self.assertEquals(projected_bbox, [-180.0, -90.0, 180.0, 90.0]) logger.info(lyr.ll_bbox) self.assertEquals(lyr.ll_bbox, [-180.0, 180.0, -90.0, 90.0, u'EPSG:4326']) projected_bbox = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [lyr.srid, ], target_srid=3857)[:4]) logger.info(projected_bbox) self.assertEquals(projected_bbox, [-20037397.0233, -74299743.4007, 20037397.0233, 74299743.4006])
def transform_bbox(bbox: List, target_crs: str = "EPSG:3857"): """ Function transforming BBOX in dataset compliant format (xmin, xmax, ymin, ymax, 'EPSG:xxxx') to another CRS, preserving overflow values. """ match = re.match(r'^(EPSG:)?(?P<srid>\d{4,6})$', str(target_crs)) target_srid = int(match.group('srid')) if match else 4326 return list(bbox_to_projection(bbox, target_srid=target_srid))[:-1] + [target_crs]
def ll_bbox(self): """BBOX is in the format: [x0,x1,y0,y1].""" from geonode.utils import bbox_to_projection llbbox = self.bbox[0:4] if self.srid and 'EPSG:' in self.srid: try: llbbox = bbox_to_projection([float(coord) for coord in llbbox] + [self.srid, ], target_srid=4326) except BaseException: pass return [ llbbox[0], # x0 llbbox[1], # x1 llbbox[2], # y0 llbbox[3], # y1 self.srid]
def filter_bbox(self, queryset, extent_filter): from geonode.utils import bbox_to_projection bbox = extent_filter.split(',') bbox = list(map(str, bbox)) intersects = (Q(bbox_x0__gte=bbox[0]) & Q(bbox_x1__lte=bbox[2]) & Q(bbox_y0__gte=bbox[1]) & Q(bbox_y1__lte=bbox[3])) for proj in Layer.objects.order_by('srid').values('srid').distinct(): if proj['srid'] != 'EPSG:4326': proj_bbox = bbox_to_projection(bbox + [ '4326', ], target_srid=int( proj['srid'][5:])) if proj_bbox[-1] != 4326: intersects = intersects | (Q(bbox_x0__gte=proj_bbox[0]) & Q(bbox_x1__lte=proj_bbox[2]) & Q(bbox_y0__gte=proj_bbox[1]) & Q(bbox_y1__lte=proj_bbox[3])) return queryset.filter(intersects)
def add_layers_to_map_config(request, map_obj, layer_names, add_base_layers=True): DEFAULT_MAP_CONFIG, DEFAULT_BASE_LAYERS = default_map_config(request) bbox = [] layers = [] for layer_name in layer_names: try: layer = _resolve_layer(request, layer_name) except ObjectDoesNotExist: # bad layer, skip continue except Http404: # can't find the layer, skip it. continue if not request.user.has_perm('view_resourcebase', obj=layer.get_self_resource()): # invisible layer, skip inclusion continue layer_bbox = layer.bbox[0:4] bbox = layer_bbox[:] bbox[0] = layer_bbox[0] bbox[1] = layer_bbox[2] bbox[2] = layer_bbox[1] bbox[3] = layer_bbox[3] # assert False, str(layer_bbox) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) # Must be in the form : [x0, x1, y0, y1 return [_bbox[0], _bbox[2], _bbox[1], _bbox[3]] def sld_definition(style): _sld = { "title": style.sld_title or style.name, "legend": { "height": "40", "width": "22", "href": layer.ows_url + "?service=wms&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=" + quote(layer.service_typename, safe=''), "format": "image/png" }, "name": style.name } return _sld config = layer.attribute_config() if hasattr(layer, 'srid'): config['crs'] = {'type': 'name', 'properties': layer.srid} # Add required parameters for GXP lazy-loading attribution = "%s %s" % ( layer.owner.first_name, layer.owner.last_name ) if layer.owner.first_name or layer.owner.last_name else str( layer.owner) srs = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') srs_srid = int(srs.split(":")[1]) if srs != "EPSG:900913" else 3857 config[ "attribution"] = "<span class='gx-attribution-title'>%s</span>" % attribution config["format"] = getattr(settings, 'DEFAULT_LAYER_FORMAT', 'image/png') config["title"] = layer.title config["wrapDateLine"] = True config["visibility"] = True config["srs"] = srs config["bbox"] = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=int(srs.split(":")[1]))[:4]) config["capability"] = { "abstract": layer.abstract, "store": layer.store, "name": layer.alternate, "title": layer.title, "queryable": True, "storeType": layer.storeType, "bbox": { layer.srid: { "srs": layer.srid, "bbox": decimal_encode(bbox) }, srs: { "srs": srs, "bbox": decimal_encode( bbox_to_projection( [float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=srs_srid)[:4]) }, "EPSG:4326": { "srs": "EPSG:4326", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=4326)[:4] }, "EPSG:900913": { "srs": "EPSG:900913", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:900913' else bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=3857)[:4] } }, "srs": { srs: True }, "formats": [ "image/png", "application/atom xml", "application/atom+xml", "application/json;type=utfgrid", "application/openlayers", "application/pdf", "application/rss xml", "application/rss+xml", "application/vnd.google-earth.kml", "application/vnd.google-earth.kml xml", "application/vnd.google-earth.kml+xml", "application/vnd.google-earth.kml+xml;mode=networklink", "application/vnd.google-earth.kmz", "application/vnd.google-earth.kmz xml", "application/vnd.google-earth.kmz+xml", "application/vnd.google-earth.kmz;mode=networklink", "atom", "image/geotiff", "image/geotiff8", "image/gif", "image/gif;subtype=animated", "image/jpeg", "image/png8", "image/png; mode=8bit", "image/svg", "image/svg xml", "image/svg+xml", "image/tiff", "image/tiff8", "image/vnd.jpeg-png", "kml", "kmz", "openlayers", "rss", "text/html; subtype=openlayers", "utfgrid" ], "attribution": { "title": attribution }, "infoFormats": [ "text/plain", "application/vnd.ogc.gml", "text/xml", "application/vnd.ogc.gml/3.1.1", "text/xml; subtype=gml/3.1.1", "text/html", "application/json" ], "styles": [sld_definition(s) for s in layer.styles.all()], "prefix": layer.alternate.split(":")[0] if ":" in layer.alternate else "", "keywords": [k.name for k in layer.keywords.all()] if layer.keywords else [], "llbbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=4326)[:4] } all_times = None if check_ogc_backend(geoserver.BACKEND_PACKAGE): if layer.has_time: from geonode.geoserver.views import get_capabilities workspace, layername = layer.alternate.split( ":") if ":" in layer.alternate else (None, layer.alternate) # WARNING Please make sure to have enabled DJANGO CACHE as per # https://docs.djangoproject.com/en/2.0/topics/cache/#filesystem-caching wms_capabilities_resp = get_capabilities(request, layer.id, tolerant=True) if wms_capabilities_resp.status_code >= 200 and wms_capabilities_resp.status_code < 400: wms_capabilities = wms_capabilities_resp.getvalue() if wms_capabilities: from defusedxml import lxml as dlxml namespaces = { 'wms': 'http://www.opengis.net/wms', 'xlink': 'http://www.w3.org/1999/xlink', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance' } e = dlxml.fromstring(wms_capabilities) for atype in e.findall( "./[wms:Name='%s']/wms:Dimension[@name='time']" % (layer.alternate), namespaces): dim_name = atype.get('name') if dim_name: dim_name = str(dim_name).lower() if dim_name == 'time': dim_values = atype.text if dim_values: all_times = dim_values.split(",") break if all_times: config["capability"]["dimensions"] = { "time": { "name": "time", "units": "ISO8601", "unitsymbol": None, "nearestVal": False, "multipleVal": False, "current": False, "default": "current", "values": all_times } } if layer.storeType == "remoteStore": service = layer.remote_service source_params = {} if service.type in ('REST_MAP', 'REST_IMG'): source_params = { "ptype": service.ptype, "remote": True, "url": service.service_url, "name": service.name, "title": "[R] %s" % service.title } maplayer = MapLayer(map=map_obj, name=layer.alternate, ows_url=layer.ows_url, layer_params=json.dumps(config), visibility=True, source_params=json.dumps(source_params)) else: ogc_server_url = urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc layer_url = urlsplit(layer.ows_url).netloc access_token = request.session[ 'access_token'] if request and 'access_token' in request.session else None if access_token and ogc_server_url == layer_url and 'access_token' not in layer.ows_url: url = '%s?access_token=%s' % (layer.ows_url, access_token) else: url = layer.ows_url maplayer = MapLayer( map=map_obj, name=layer.alternate, ows_url=url, # use DjangoJSONEncoder to handle Decimal values layer_params=json.dumps(config, cls=DjangoJSONEncoder), visibility=True) layers.append(maplayer) if bbox and len(bbox) >= 4: minx, maxx, miny, maxy = [float(coord) for coord in bbox] x = (minx + maxx) / 2 y = (miny + maxy) / 2 if getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') == "EPSG:4326": center = list((x, y)) else: center = list(forward_mercator((x, y))) if center[1] == float('-inf'): center[1] = 0 BBOX_DIFFERENCE_THRESHOLD = 1e-5 # Check if the bbox is invalid valid_x = (maxx - minx)**2 > BBOX_DIFFERENCE_THRESHOLD valid_y = (maxy - miny)**2 > BBOX_DIFFERENCE_THRESHOLD if valid_x: width_zoom = math.log(360 / abs(maxx - minx), 2) else: width_zoom = 15 if valid_y: height_zoom = math.log(360 / abs(maxy - miny), 2) else: height_zoom = 15 map_obj.center_x = center[0] map_obj.center_y = center[1] map_obj.zoom = math.ceil(min(width_zoom, height_zoom)) map_obj.handle_moderated_uploads() if add_base_layers: layers_to_add = DEFAULT_BASE_LAYERS + layers else: layers_to_add = layers config = map_obj.viewer_json(request, *layers_to_add) config['fromLayer'] = True return config
def layer_detail(request, layername, template='layers/layer_detail.html'): layer = _resolve_layer(request, layername, 'base.view_resourcebase', _("You are not permitted to view this layer")) # assert False, str(layer_bbox) config = layer.attribute_config() # Add required parameters for GXP lazy-loading layer_bbox = layer.bbox bbox = [float(coord) for coord in list(layer_bbox[0:4])] config["srs"] = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') config["bbox"] = bbox if config["srs"] != 'EPSG:900913' \ else llbbox_to_mercator([float(coord) for coord in bbox]) config["title"] = layer.title config["queryable"] = True if layer.default_style: config["styles"] = layer.default_style.name if layer.storeType == "remoteStore": source_srid = None # Only grab the service proj/bbox if it is valid if None not in layer.service.bbox[0:4]: bbox = [float(coord) for coord in list(layer.service.bbox[0:4])] source_srid = layer.service.srid # Otherwise try the service directly # This is needed since previous services registered # did not store the bbox/srid in the model else: try: service_handler = get_service_handler( base_url=layer.service.base_url, service_type=layer.service.type) if getattr(service_handler.parsed_service, 'initialExtent', None): bbox[0] = service_handler.parsed_service.initialExtent[ 'xmin'] bbox[1] = service_handler.parsed_service.initialExtent[ 'ymin'] bbox[2] = service_handler.parsed_service.initialExtent[ 'xmax'] bbox[3] = service_handler.parsed_service.initialExtent[ 'ymax'] else: logger.info( 'Could not retrieve extent from service: {0}'.format( layer.service)) if getattr(service_handler.parsed_service, 'spatialReference', None): source_srid = \ service_handler.parsed_service.spatialReference[ 'latestWkid'] else: logger.info( 'Could not retrieve srid from service: {0}'.format( layer.service)) except Exception as e: logger.info('Failed to access service endpoint: {0}'.format( layer.service.base_url)) logger.info('Caught error: {0}'.format(e)) if source_srid is None: source_srid = layer.srid target_srid = 3857 if config["srs"] == 'EPSG:900913' else config["srs"] reprojected_bbox = bbox_to_projection(bbox, source_srid=source_srid, target_srid=target_srid) bbox = reprojected_bbox[:4] config['bbox'] = [float(coord) for coord in bbox] service = layer.service source_url = service.base_url use_proxy = (callable(uses_proxy_route) and uses_proxy_route(service.base_url)) components = urlsplit(service.base_url) query_params = None if components.query: query_params = OrderedDict( parse_qsl(components.query, keep_blank_values=True)) removed_query = [ components.scheme, components.netloc, components.path, None, components.fragment ] source_url = urlunsplit(removed_query) source_params = { "ptype": service.ptype, "remote": True, "url": source_url, "name": service.name, "use_proxy": use_proxy } if query_params is not None: source_params["params"] = query_params if layer.alternate is not None: config["layerid"] = layer.alternate maplayer = GXPLayer(name=layer.typename, ows_url=layer.ows_url, layer_params=json.dumps(config), source_params=json.dumps(source_params)) else: maplayer = GXPLayer(name=layer.typename, ows_url=layer.ows_url, layer_params=json.dumps(config)) # Update count for popularity ranking, # but do not includes admins or resource owners if request.user != layer.owner and not request.user.is_superuser: Layer.objects.filter(id=layer.id).update( popular_count=F('popular_count') + 1) # center/zoom don't matter; the viewer will center on the layer bounds map_obj = GXPMap( projection=getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913')) metadata = layer.link_set.metadata().filter( name__in=settings.DOWNLOAD_FORMATS_METADATA) granules = None all_granules = None filter = None if layer.is_mosaic: try: cat = gs_catalog cat._cache.clear() store = cat.get_store(layer.name) coverages = cat.mosaic_coverages(store) filter = None try: if request.GET["filter"]: filter = request.GET["filter"] except: pass offset = 10 * (request.page - 1) granules = cat.mosaic_granules( coverages['coverages']['coverage'][0]['name'], store, limit=10, offset=offset, filter=filter) all_granules = cat.mosaic_granules( coverages['coverages']['coverage'][0]['name'], store, filter=filter) except: granules = {"features": []} all_granules = {"features": []} context_dict = { "resource": layer, 'perms_list': get_perms(request.user, layer.get_self_resource()), "permissions_json": _perms_info_json(layer), "documents": get_related_documents(layer), "metadata": metadata, "is_layer": True, "wps_enabled": settings.OGC_SERVER['default']['WPS_ENABLED'], "granules": granules, "all_granules": all_granules, "filter": filter, } if 'access_token' in request.session: access_token = request.session['access_token'] else: u = uuid.uuid1() access_token = u.hex if bbox is not None: minx, miny, maxx, maxy = [float(coord) for coord in bbox] x = (minx + maxx) / 2 y = (miny + maxy) / 2 if layer.is_remote or getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') == "EPSG:4326": center = list((x, y)) else: center = list(forward_mercator((x, y))) if center[1] == float('-inf'): center[1] = 0 BBOX_DIFFERENCE_THRESHOLD = 1e-5 # Check if the bbox is invalid valid_x = (maxx - minx)**2 > BBOX_DIFFERENCE_THRESHOLD valid_y = (maxy - miny)**2 > BBOX_DIFFERENCE_THRESHOLD if valid_x: width_zoom = math.log(360 / abs(maxx - minx), 2) else: width_zoom = 15 if valid_y: height_zoom = math.log(360 / abs(maxy - miny), 2) else: height_zoom = 15 map_obj.center_x = center[0] map_obj.center_y = center[1] map_obj.zoom = math.ceil(min(width_zoom, height_zoom)) context_dict["viewer"] = json.dumps( map_obj.viewer_json(request.user, access_token, *(default_map_config(request)[1] + [maplayer]))) context_dict["preview"] = getattr(settings, 'LAYER_PREVIEW_LIBRARY', 'leaflet') context_dict["crs"] = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') if layer.storeType == 'dataStore': links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_VECTOR) else: links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_RASTER) links_view = [ item for idx, item in enumerate(links) if item.url and 'wms' in item.url or 'gwc' in item.url ] links_download = [ item for idx, item in enumerate(links) if item.url and 'wms' not in item.url and 'gwc' not in item.url ] for item in links_view: if item.url and access_token: item.url = "%s&access_token=%s&time=%s" % \ (item.url, access_token, "0/9999") for item in links_download: if item.url and access_token: item.url = "%s&access_token=%s" % (item.url, access_token) if request.user.has_perm('view_resourcebase', layer.get_self_resource()): context_dict["links"] = links_view if request.user.has_perm('download_resourcebase', layer.get_self_resource()): if layer.storeType == 'dataStore': links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_VECTOR) else: links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_RASTER) context_dict["links_download"] = links_download if settings.SOCIAL_ORIGINS: context_dict["social_links"] = build_social_links(request, layer) return render_to_response(template, RequestContext(request, context_dict))
def add_layers_to_map_config(request, map_obj, layer_names, add_base_layers=True): DEFAULT_MAP_CONFIG, DEFAULT_BASE_LAYERS = default_map_config(request) if 'access_token' in request.session: access_token = request.session['access_token'] else: access_token = None bbox = [] layers = [] for layer_name in layer_names: try: layer = _resolve_layer(request, layer_name) except ObjectDoesNotExist: # bad layer, skip continue if not layer.is_published: # invisible layer, skip inclusion continue if not request.user.has_perm('view_resourcebase', obj=layer.get_self_resource()): # invisible layer, skip inclusion continue layer_bbox = layer.bbox[0:4] bbox = layer_bbox[:] bbox[0] = layer_bbox[0] bbox[1] = layer_bbox[2] bbox[2] = layer_bbox[1] bbox[3] = layer_bbox[3] # assert False, str(layer_bbox) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) return _bbox def sld_definition(style): from urllib import quote _sld = { "title": style.sld_title or style.name, "legend": { "height": "40", "width": "22", "href": layer.ows_url + "?service=wms&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=" + quote(layer.service_typename, safe=''), "format": "image/png" }, "name": style.name } return _sld config = layer.attribute_config() if hasattr(layer, 'srid'): config['crs'] = {'type': 'name', 'properties': layer.srid} # Add required parameters for GXP lazy-loading attribution = "%s %s" % ( layer.owner.first_name, layer.owner.last_name ) if layer.owner.first_name or layer.owner.last_name else str( layer.owner) srs = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') srs_srid = int(srs.split(":")[1]) if srs != "EPSG:900913" else 3857 config[ "attribution"] = "<span class='gx-attribution-title'>%s</span>" % attribution config["format"] = getattr(settings, 'DEFAULT_LAYER_FORMAT', 'image/png') config["title"] = layer.title config["wrapDateLine"] = True config["visibility"] = True config["srs"] = srs config["bbox"] = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=int(srs.split(":")[1]))[:4]) config["capability"] = { "abstract": layer.abstract, "name": layer.alternate, "title": layer.title, "queryable": True, "bbox": { layer.srid: { "srs": layer.srid, "bbox": decimal_encode(bbox) }, srs: { "srs": srs, "bbox": decimal_encode( bbox_to_projection( [float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=srs_srid)[:4]) }, "EPSG:4326": { "srs": "EPSG:4326", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else decimal_encode( bbox_to_projection( [float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=4326)[:4]) }, "EPSG:900913": { "srs": "EPSG:900913", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:900913' else decimal_encode( bbox_to_projection( [float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=3857)[:4]) } }, "srs": { srs: True }, "formats": [ "image/png", "application/atom xml", "application/atom+xml", "application/json;type=utfgrid", "application/openlayers", "application/pdf", "application/rss xml", "application/rss+xml", "application/vnd.google-earth.kml", "application/vnd.google-earth.kml xml", "application/vnd.google-earth.kml+xml", "application/vnd.google-earth.kml+xml;mode=networklink", "application/vnd.google-earth.kmz", "application/vnd.google-earth.kmz xml", "application/vnd.google-earth.kmz+xml", "application/vnd.google-earth.kmz;mode=networklink", "atom", "image/geotiff", "image/geotiff8", "image/gif", "image/gif;subtype=animated", "image/jpeg", "image/png8", "image/png; mode=8bit", "image/svg", "image/svg xml", "image/svg+xml", "image/tiff", "image/tiff8", "image/vnd.jpeg-png", "kml", "kmz", "openlayers", "rss", "text/html; subtype=openlayers", "utfgrid" ], "attribution": { "title": attribution }, "infoFormats": [ "text/plain", "application/vnd.ogc.gml", "text/xml", "application/vnd.ogc.gml/3.1.1", "text/xml; subtype=gml/3.1.1", "text/html", "application/json" ], "styles": [sld_definition(s) for s in layer.styles.all()], "prefix": layer.alternate.split(":")[0] if ":" in layer.alternate else "", "keywords": [k.name for k in layer.keywords.all()] if layer.keywords else [], "llbbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=4326)[:4]) } if layer.storeType == "remoteStore": service = layer.remote_service source_params = { "ptype": service.ptype, "remote": True, "url": service.service_url, "name": service.name, "title": "[R] %s" % service.title } maplayer = MapLayer(map=map_obj, name=layer.alternate, ows_url=layer.ows_url, layer_params=json.dumps(config), visibility=True, source_params=json.dumps(source_params)) else: ogc_server_url = urlparse.urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc layer_url = urlparse.urlsplit(layer.ows_url).netloc if access_token and ogc_server_url == layer_url and 'access_token' not in layer.ows_url: url = layer.ows_url + '?access_token=' + access_token else: url = layer.ows_url maplayer = MapLayer( map=map_obj, name=layer.alternate, ows_url=url, # use DjangoJSONEncoder to handle Decimal values layer_params=json.dumps(config, cls=DjangoJSONEncoder), visibility=True) layers.append(maplayer) if bbox is not None: minx, maxx, miny, maxy = [float(coord) for coord in bbox] x = (minx + maxx) / 2 y = (miny + maxy) / 2 if getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') == "EPSG:4326": center = list((x, y)) else: center = list(forward_mercator((x, y))) if center[1] == float('-inf'): center[1] = 0 BBOX_DIFFERENCE_THRESHOLD = 1e-5 # Check if the bbox is invalid valid_x = (maxx - minx)**2 > BBOX_DIFFERENCE_THRESHOLD valid_y = (maxy - miny)**2 > BBOX_DIFFERENCE_THRESHOLD if valid_x: width_zoom = math.log(360 / abs(maxx - minx), 2) else: width_zoom = 15 if valid_y: height_zoom = math.log(360 / abs(maxy - miny), 2) else: height_zoom = 15 map_obj.center_x = center[0] map_obj.center_y = center[1] map_obj.zoom = math.ceil(min(width_zoom, height_zoom)) map_obj.handle_moderated_uploads() if add_base_layers: layers_to_add = DEFAULT_BASE_LAYERS + layers else: layers_to_add = layers config = map_obj.viewer_json(request.user, access_token, *layers_to_add) config['fromLayer'] = True return config
def new_map_config(request): ''' View that creates a new map. If the query argument 'copy' is given, the initial map is a copy of the map with the id specified, otherwise the default map configuration is used. If copy is specified and the map specified does not exist a 404 is returned. ''' DEFAULT_MAP_CONFIG, DEFAULT_BASE_LAYERS = default_map_config(request) if 'access_token' in request.session: access_token = request.session['access_token'] else: access_token = None if request.method == 'GET' and 'copy' in request.GET: mapid = request.GET['copy'] map_obj = _resolve_map(request, mapid, 'base.view_resourcebase') map_obj.abstract = DEFAULT_ABSTRACT map_obj.title = DEFAULT_TITLE map_obj.refresh_interval = 60000 if request.user.is_authenticated(): map_obj.owner = request.user config = map_obj.viewer_json(request.user, access_token) del config['id'] else: if request.method == 'GET': params = request.GET elif request.method == 'POST': params = request.POST else: return HttpResponse(status=405) if 'layer' in params: bbox = None map_obj = Map( projection=getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913')) layers = [] for layer_name in params.getlist('layer'): try: layer = _resolve_layer(request, layer_name) except ObjectDoesNotExist: # bad layer, skip continue except Http404: # can't find the layer, skip it. continue if not request.user.has_perm('view_resourcebase', obj=layer.get_self_resource()): # invisible layer, skip inclusion continue layer_bbox = layer.bbox # assert False, str(layer_bbox) if bbox is None: bbox = list(layer_bbox[0:4]) else: bbox = list(bbox) bbox[0] = min(bbox[0], layer_bbox[0]) bbox[1] = max(bbox[1], layer_bbox[1]) bbox[2] = min(bbox[2], layer_bbox[2]) bbox[3] = max(bbox[3], layer_bbox[3]) config = layer.attribute_config() # Add required parameters for GXP lazy-loading config["title"] = layer.title config["queryable"] = True config["srs"] = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') config["bbox"] = bbox if config["srs"] != 'EPSG:900913' \ else llbbox_to_mercator([float(coord) for coord in bbox]) if layer.storeType == "remoteStore": service = layer.service # Probably not a good idea to send the access token # to every remote service. This should never match, # so no access token should be sent to remote services. ogc_server_url = urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc service_url = urlsplit(service.base_url).netloc if config["srs"] == 'EPSG:900913': target_srid = 3857 else: target_srid = config["srs"] reprojected_bbox = bbox_to_projection( bbox, source_srid=layer.srid, target_srid=target_srid) bbox = reprojected_bbox[:4] config['bbox'] = [float(coord) for coord in bbox] if access_token and ogc_server_url == service_url and \ 'access_token' not in service.base_url: url = service.base_url + '?access_token={}'.format( access_token) else: url = service.base_url use_proxy = (callable(uses_proxy_route) and uses_proxy_route(service.base_url)) if layer.alternate is not None: config["layerid"] = layer.alternate maplayer = MapLayer(map=map_obj, name=layer.typename, ows_url=layer.ows_url, layer_params=json.dumps( config, cls=DjangoJSONEncoder), visibility=True, source_params=json.dumps({ "ptype": service.ptype, "remote": True, "url": url, "name": service.name, "use_proxy": use_proxy })) else: ogc_server_url = urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc layer_url = urlsplit(layer.ows_url).netloc if access_token and ogc_server_url == layer_url and \ 'access_token' not in layer.ows_url: url = layer.ows_url + '?access_token=' + access_token else: url = layer.ows_url maplayer = MapLayer( map=map_obj, name=layer.typename, ows_url=url, # use DjangoJSONEncoder to handle Decimal values layer_params=json.dumps(config, cls=DjangoJSONEncoder), visibility=True) layers.append(maplayer) if bbox is not None: minx, miny, maxx, maxy = [float(coord) for coord in bbox] x = (minx + maxx) / 2 y = (miny + maxy) / 2 if layer.is_remote or getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') == "EPSG:4326": center = list((x, y)) else: center = list(forward_mercator((x, y))) if center[1] == float('-inf'): center[1] = 0 BBOX_DIFFERENCE_THRESHOLD = 1e-5 # Check if the bbox is invalid valid_x = (maxx - minx)**2 > BBOX_DIFFERENCE_THRESHOLD valid_y = (maxy - miny)**2 > BBOX_DIFFERENCE_THRESHOLD if valid_x: width_zoom = math.log(360 / abs(maxx - minx), 2) else: width_zoom = 15 if valid_y: height_zoom = math.log(360 / abs(maxy - miny), 2) else: height_zoom = 15 map_obj.center_x = center[0] map_obj.center_y = center[1] map_obj.zoom = math.ceil(min(width_zoom, height_zoom)) config = map_obj.viewer_json(request.user, access_token, *(DEFAULT_BASE_LAYERS + layers)) config['fromLayer'] = True else: config = DEFAULT_MAP_CONFIG return json.dumps(config)
def create_gs_thumbnail_geonode(instance, overwrite=False, check_bbox=False): """ Create a thumbnail with a GeoServer request. """ layers = None bbox = None # x0, x1, y0, y1 local_layers = [] local_bboxes = [] if isinstance(instance, Map): # a map could be empty! if not instance.layers: return for layer in instance.layers: if layer.local: local_layers.append(layer.name) # Compute Bounds _l = Layer.objects.get(alternate=layer.name) wgs84_bbox = bbox_to_projection(_l.bbox) local_bboxes.append(wgs84_bbox) layers = ",".join(local_layers).encode('utf-8') else: layers = instance.alternate.encode('utf-8') # Compute Bounds _l = Layer.objects.get(alternate=layers) wgs84_bbox = bbox_to_projection(_l.bbox) local_bboxes.append(wgs84_bbox) if local_bboxes: for _bbox in local_bboxes: if bbox is None: bbox = list(_bbox) else: if bbox[0] > _bbox[0]: bbox[0] = _bbox[0] if bbox[1] < _bbox[1]: bbox[1] = _bbox[1] if bbox[2] > _bbox[2]: bbox[2] = _bbox[2] if bbox[3] < _bbox[3]: bbox[3] = _bbox[3] wms_endpoint = getattr(ogc_server_settings, 'WMS_ENDPOINT') or 'ows' wms_version = getattr(ogc_server_settings, 'WMS_VERSION') or '1.1.1' wms_format = getattr(ogc_server_settings, 'WMS_FORMAT') or 'image/png8' params = { 'service': 'WMS', 'version': wms_version, 'request': 'GetMap', 'layers': layers, 'format': wms_format, # 'TIME': '-99999999999-01-01T00:00:00.0Z/99999999999-01-01T00:00:00.0Z' } if bbox: params['bbox'] = "%s,%s,%s,%s" % (bbox[0], bbox[2], bbox[1], bbox[3]) params['crs'] = 'EPSG:4326' params['width'] = 240 params['height'] = 180 user = None try: username = ogc_server_settings.credentials.username user = get_user_model().objects.get(username=username) except BaseException as e: logger.exception(e) access_token = None if user: access_token = get_or_create_token(user) if access_token and not access_token.is_expired(): params['access_token'] = access_token.token # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. _p = "&".join("%s=%s" % item for item in params.items()) import posixpath thumbnail_remote_url = posixpath.join( ogc_server_settings.PUBLIC_LOCATION, wms_endpoint) + "?" + _p thumbnail_create_url = posixpath.join( ogc_server_settings.LOCATION, wms_endpoint) + "?" + _p create_thumbnail(instance, thumbnail_remote_url, thumbnail_create_url, overwrite=overwrite, check_bbox=check_bbox)
def add_layers_to_map_config( request, map_obj, layer_names, add_base_layers=True): DEFAULT_MAP_CONFIG, DEFAULT_BASE_LAYERS = default_map_config(request) bbox = [] layers = [] for layer_name in layer_names: try: layer = _resolve_layer(request, layer_name) except ObjectDoesNotExist: # bad layer, skip continue except Http404: # can't find the layer, skip it. continue if not request.user.has_perm( 'view_resourcebase', obj=layer.get_self_resource()): # invisible layer, skip inclusion continue layer_bbox = layer.bbox[0:4] bbox = layer_bbox[:] bbox[0] = layer_bbox[0] bbox[1] = layer_bbox[2] bbox[2] = layer_bbox[1] bbox[3] = layer_bbox[3] # assert False, str(layer_bbox) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) # Must be in the form : [x0, x1, y0, y1 return [_bbox[0], _bbox[2], _bbox[1], _bbox[3]] def sld_definition(style): from urllib import quote _sld = { "title": style.sld_title or style.name, "legend": { "height": "40", "width": "22", "href": layer.ows_url + "?service=wms&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=" + quote(layer.service_typename, safe=''), "format": "image/png" }, "name": style.name } return _sld config = layer.attribute_config() if hasattr(layer, 'srid'): config['crs'] = { 'type': 'name', 'properties': layer.srid } # Add required parameters for GXP lazy-loading attribution = "%s %s" % (layer.owner.first_name, layer.owner.last_name) if layer.owner.first_name or layer.owner.last_name else str( layer.owner) srs = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') srs_srid = int(srs.split(":")[1]) if srs != "EPSG:900913" else 3857 config["attribution"] = "<span class='gx-attribution-title'>%s</span>" % attribution config["format"] = getattr( settings, 'DEFAULT_LAYER_FORMAT', 'image/png') config["title"] = layer.title config["wrapDateLine"] = True config["visibility"] = True config["srs"] = srs config["bbox"] = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=int(srs.split(":")[1]))[:4]) config["capability"] = { "abstract": layer.abstract, "name": layer.alternate, "title": layer.title, "queryable": True, "storeType": layer.storeType, "bbox": { layer.srid: { "srs": layer.srid, "bbox": decimal_encode(bbox) }, srs: { "srs": srs, "bbox": decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=srs_srid)[:4]) }, "EPSG:4326": { "srs": "EPSG:4326", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else decimal_encode(bbox_to_projection( [float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=4326)[:4]) }, "EPSG:900913": { "srs": "EPSG:900913", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:900913' else decimal_encode(bbox_to_projection( [float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=3857)[:4]) } }, "srs": { srs: True }, "formats": ["image/png", "application/atom xml", "application/atom+xml", "application/json;type=utfgrid", "application/openlayers", "application/pdf", "application/rss xml", "application/rss+xml", "application/vnd.google-earth.kml", "application/vnd.google-earth.kml xml", "application/vnd.google-earth.kml+xml", "application/vnd.google-earth.kml+xml;mode=networklink", "application/vnd.google-earth.kmz", "application/vnd.google-earth.kmz xml", "application/vnd.google-earth.kmz+xml", "application/vnd.google-earth.kmz;mode=networklink", "atom", "image/geotiff", "image/geotiff8", "image/gif", "image/gif;subtype=animated", "image/jpeg", "image/png8", "image/png; mode=8bit", "image/svg", "image/svg xml", "image/svg+xml", "image/tiff", "image/tiff8", "image/vnd.jpeg-png", "kml", "kmz", "openlayers", "rss", "text/html; subtype=openlayers", "utfgrid"], "attribution": { "title": attribution }, "infoFormats": ["text/plain", "application/vnd.ogc.gml", "text/xml", "application/vnd.ogc.gml/3.1.1", "text/xml; subtype=gml/3.1.1", "text/html", "application/json"], "styles": [sld_definition(s) for s in layer.styles.all()], "prefix": layer.alternate.split(":")[0] if ":" in layer.alternate else "", "keywords": [k.name for k in layer.keywords.all()] if layer.keywords else [], "llbbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else decimal_encode(bbox_to_projection( [float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=4326)[:4]) } all_times = None if check_ogc_backend(geoserver.BACKEND_PACKAGE): from geonode.geoserver.views import get_capabilities workspace, layername = layer.alternate.split( ":") if ":" in layer.alternate else (None, layer.alternate) # WARNING Please make sure to have enabled DJANGO CACHE as per # https://docs.djangoproject.com/en/2.0/topics/cache/#filesystem-caching wms_capabilities_resp = get_capabilities( request, layer.id, tolerant=True) if wms_capabilities_resp.status_code >= 200 and wms_capabilities_resp.status_code < 400: wms_capabilities = wms_capabilities_resp.getvalue() if wms_capabilities: import xml.etree.ElementTree as ET namespaces = {'wms': 'http://www.opengis.net/wms', 'xlink': 'http://www.w3.org/1999/xlink', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'} e = ET.fromstring(wms_capabilities) for atype in e.findall( "./[wms:Name='%s']/wms:Dimension[@name='time']" % (layer.alternate), namespaces): dim_name = atype.get('name') if dim_name: dim_name = str(dim_name).lower() if dim_name == 'time': dim_values = atype.text if dim_values: all_times = dim_values.split(",") break if all_times: config["capability"]["dimensions"] = { "time": { "name": "time", "units": "ISO8601", "unitsymbol": None, "nearestVal": False, "multipleVal": False, "current": False, "default": "current", "values": all_times } } if layer.storeType == "remoteStore": service = layer.remote_service source_params = {} if service.type in ('REST_MAP', 'REST_IMG'): source_params = { "ptype": service.ptype, "remote": True, "url": service.service_url, "name": service.name, "title": "[R] %s" % service.title} maplayer = MapLayer(map=map_obj, name=layer.alternate, ows_url=layer.ows_url, layer_params=json.dumps(config), visibility=True, source_params=json.dumps(source_params) ) else: ogc_server_url = urlparse.urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc layer_url = urlparse.urlsplit(layer.ows_url).netloc access_token = request.session['access_token'] if request and 'access_token' in request.session else None if access_token and ogc_server_url == layer_url and 'access_token' not in layer.ows_url: url = '%s?access_token=%s' % (layer.ows_url, access_token) else: url = layer.ows_url maplayer = MapLayer( map=map_obj, name=layer.alternate, ows_url=url, # use DjangoJSONEncoder to handle Decimal values layer_params=json.dumps(config, cls=DjangoJSONEncoder), visibility=True ) layers.append(maplayer) if bbox and len(bbox) >= 4: minx, maxx, miny, maxy = [float(coord) for coord in bbox] x = (minx + maxx) / 2 y = (miny + maxy) / 2 if getattr( settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') == "EPSG:4326": center = list((x, y)) else: center = list(forward_mercator((x, y))) if center[1] == float('-inf'): center[1] = 0 BBOX_DIFFERENCE_THRESHOLD = 1e-5 # Check if the bbox is invalid valid_x = (maxx - minx) ** 2 > BBOX_DIFFERENCE_THRESHOLD valid_y = (maxy - miny) ** 2 > BBOX_DIFFERENCE_THRESHOLD if valid_x: width_zoom = math.log(360 / abs(maxx - minx), 2) else: width_zoom = 15 if valid_y: height_zoom = math.log(360 / abs(maxy - miny), 2) else: height_zoom = 15 map_obj.center_x = center[0] map_obj.center_y = center[1] map_obj.zoom = math.ceil(min(width_zoom, height_zoom)) map_obj.handle_moderated_uploads() if add_base_layers: layers_to_add = DEFAULT_BASE_LAYERS + layers else: layers_to_add = layers config = map_obj.viewer_json( request, *layers_to_add) config['fromLayer'] = True return config
def layer_detail(request, layername, template='layers/layer_detail.html'): layer = _resolve_layer(request, layername, 'base.view_resourcebase', _PERMISSION_MSG_VIEW) # assert False, str(layer_bbox) config = layer.attribute_config() # Add required parameters for GXP lazy-loading layer_bbox = layer.bbox[0:4] bbox = layer_bbox[:] bbox[0] = float(layer_bbox[0]) bbox[1] = float(layer_bbox[2]) bbox[2] = float(layer_bbox[1]) bbox[3] = float(layer_bbox[3]) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) # Must be in the form : [x0, x1, y0, y1 return [_bbox[0], _bbox[2], _bbox[1], _bbox[3]] def sld_definition(style): from urllib import quote _sld = { "title": style.sld_title or style.name, "legend": { "height": "40", "width": "22", "href": layer.ows_url + "?service=wms&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=" + quote(layer.service_typename, safe=''), "format": "image/png" }, "name": style.name } return _sld if hasattr(layer, 'srid'): config['crs'] = {'type': 'name', 'properties': layer.srid} # Add required parameters for GXP lazy-loading attribution = "%s %s" % ( layer.owner.first_name, layer.owner.last_name ) if layer.owner.first_name or layer.owner.last_name else str(layer.owner) srs = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') srs_srid = int(srs.split(":")[1]) if srs != "EPSG:900913" else 3857 config[ "attribution"] = "<span class='gx-attribution-title'>%s</span>" % attribution config["format"] = getattr(settings, 'DEFAULT_LAYER_FORMAT', 'image/png') config["title"] = layer.title config["wrapDateLine"] = True config["visibility"] = True config["srs"] = srs config["bbox"] = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=int(srs.split(":")[1]))[:4]) config["capability"] = { "abstract": layer.abstract, "name": layer.alternate, "title": layer.title, "queryable": True, "storeType": layer.storeType, "bbox": { layer.srid: { "srs": layer.srid, "bbox": decimal_encode(bbox) }, srs: { "srs": srs, "bbox": decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=srs_srid)[:4]) }, "EPSG:4326": { "srs": "EPSG:4326", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=4326)[:4]) }, "EPSG:900913": { "srs": "EPSG:900913", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:900913' else decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=3857)[:4]) } }, "srs": { srs: True }, "formats": [ "image/png", "application/atom xml", "application/atom+xml", "application/json;type=utfgrid", "application/openlayers", "application/pdf", "application/rss xml", "application/rss+xml", "application/vnd.google-earth.kml", "application/vnd.google-earth.kml xml", "application/vnd.google-earth.kml+xml", "application/vnd.google-earth.kml+xml;mode=networklink", "application/vnd.google-earth.kmz", "application/vnd.google-earth.kmz xml", "application/vnd.google-earth.kmz+xml", "application/vnd.google-earth.kmz;mode=networklink", "atom", "image/geotiff", "image/geotiff8", "image/gif", "image/gif;subtype=animated", "image/jpeg", "image/png8", "image/png; mode=8bit", "image/svg", "image/svg xml", "image/svg+xml", "image/tiff", "image/tiff8", "image/vnd.jpeg-png", "kml", "kmz", "openlayers", "rss", "text/html; subtype=openlayers", "utfgrid" ], "attribution": { "title": attribution }, "infoFormats": [ "text/plain", "application/vnd.ogc.gml", "text/xml", "application/vnd.ogc.gml/3.1.1", "text/xml; subtype=gml/3.1.1", "text/html", "application/json" ], "styles": [sld_definition(s) for s in layer.styles.all()], "prefix": layer.alternate.split(":")[0] if ":" in layer.alternate else "", "keywords": [k.name for k in layer.keywords.all()] if layer.keywords else [], "llbbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=4326)[:4]) } all_times = None if check_ogc_backend(geoserver.BACKEND_PACKAGE): from geonode.geoserver.views import get_capabilities workspace, layername = layer.alternate.split( ":") if ":" in layer.alternate else (None, layer.alternate) # WARNING Please make sure to have enabled DJANGO CACHE as per # https://docs.djangoproject.com/en/2.0/topics/cache/#filesystem-caching wms_capabilities_resp = get_capabilities(request, layer.id, tolerant=True) if wms_capabilities_resp.status_code >= 200 and wms_capabilities_resp.status_code < 400: wms_capabilities = wms_capabilities_resp.getvalue() if wms_capabilities: import xml.etree.ElementTree as ET e = ET.fromstring(wms_capabilities) for atype in e.findall("./[Name='%s']/Extent[@name='time']" % (layername)): dim_name = atype.get('name') if dim_name: dim_name = str(dim_name).lower() if dim_name == 'time': dim_values = atype.text if dim_values: all_times = dim_values.split(",") break if all_times: config["capability"]["dimensions"] = { "time": { "name": "time", "units": "ISO8601", "unitsymbol": None, "nearestVal": False, "multipleVal": False, "current": False, "default": "current", "values": all_times } } if layer.storeType == "remoteStore": service = layer.remote_service source_params = {} if service.type in ('REST_MAP', 'REST_IMG'): source_params = { "ptype": service.ptype, "remote": True, "url": service.service_url, "name": service.name, "title": "[R] %s" % service.title } maplayer = GXPLayer(name=layer.alternate, ows_url=layer.ows_url, layer_params=json.dumps(config), source_params=json.dumps(source_params)) else: maplayer = GXPLayer(name=layer.alternate, ows_url=layer.ows_url, layer_params=json.dumps(config)) # Update count for popularity ranking, # but do not includes admins or resource owners layer.view_count_up(request.user) # center/zoom don't matter; the viewer will center on the layer bounds map_obj = GXPMap(sender=Layer, projection=getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857')) NON_WMS_BASE_LAYERS = [ la for la in default_map_config(request)[1] if la.ows_url is None ] metadata = layer.link_set.metadata().filter( name__in=settings.DOWNLOAD_FORMATS_METADATA) granules = None all_granules = None all_times = None filter = None if layer.is_mosaic: try: cat = gs_catalog cat._cache.clear() store = cat.get_store(layer.name) coverages = cat.mosaic_coverages(store) filter = None try: if request.GET["filter"]: filter = request.GET["filter"] except BaseException: pass offset = 10 * (request.page - 1) granules = cat.mosaic_granules( coverages['coverages']['coverage'][0]['name'], store, limit=10, offset=offset, filter=filter) all_granules = cat.mosaic_granules( coverages['coverages']['coverage'][0]['name'], store, filter=filter) except BaseException: granules = {"features": []} all_granules = {"features": []} if check_ogc_backend(geoserver.BACKEND_PACKAGE): from geonode.geoserver.views import get_capabilities workspace, layername = layer.alternate.split( ":") if ":" in layer.alternate else (None, layer.alternate) # WARNING Please make sure to have enabled DJANGO CACHE as per # https://docs.djangoproject.com/en/2.0/topics/cache/#filesystem-caching wms_capabilities_resp = get_capabilities(request, layer.id, tolerant=True) if wms_capabilities_resp.status_code >= 200 and wms_capabilities_resp.status_code < 400: wms_capabilities = wms_capabilities_resp.getvalue() if wms_capabilities: import xml.etree.ElementTree as ET e = ET.fromstring(wms_capabilities) for atype in e.findall("./[Name='%s']/Extent[@name='time']" % (layername)): dim_name = atype.get('name') if dim_name: dim_name = str(dim_name).lower() if dim_name == 'time': dim_values = atype.text if dim_values: all_times = dim_values.split(",") break group = None if layer.group: try: group = GroupProfile.objects.get(slug=layer.group.name) except GroupProfile.DoesNotExist: group = None # a flag to be used for qgis server show_popup = False if 'show_popup' in request.GET and request.GET["show_popup"]: show_popup = True ### # MapStory Specific Changes ### keywords = json.dumps([tag.name for tag in layer.keywords.all()]) if request.method == "POST": keywords_form = KeywordsForm(request.POST, instance=layer) metadata_form = MetadataForm(instance=layer) distributionurl_form = DistributionUrlForm(request.POST, instance=layer) if 'keywords' in request.POST: if keywords_form.is_valid(): keywords_form.save() new_keywords = keywords_form.cleaned_data['keywords'] layer.keywords.set(*new_keywords) layer.save() metadata_form = MetadataForm(instance=layer) elif 'title' in request.POST: metadata_form = MetadataForm(request.POST, instance=layer) if metadata_form.is_valid(): metadata_form.save() # update all the metadata if metadata_form.cleaned_data['category'] is not None: new_category = TopicCategory.objects.get( id=metadata_form.cleaned_data['category'].id) Layer.objects.filter(id=layer.id).update( category=new_category) layer.title = metadata_form.cleaned_data['title'] layer.language = metadata_form.cleaned_data['language'] layer.data_quality_statement = metadata_form.cleaned_data[ 'data_quality_statement'] layer.purpose = metadata_form.cleaned_data['purpose'] layer.is_published = metadata_form.cleaned_data['is_published'] layer.save() if distributionurl_form.is_valid(): layer.distribution_url = distributionurl_form.cleaned_data[ 'distribution_url'] keywords_form = KeywordsForm(instance=layer) if 'add_keyword' in request.POST: layer.keywords.add(request.POST['add_keyword']) layer.save() if 'remove_keyword' in request.POST: layer.keywords.remove(request.POST['remove_keyword']) layer.save() else: keywords_form = KeywordsForm(instance=layer) metadata_form = MetadataForm(instance=layer) distributionurl_form = DistributionUrlForm(instance=layer) content_moderators = Group.objects.filter(name='content_moderator').first() thumbnail = layer.get_thumbnail_url # This will get URL encoded later and is used for the social media share URL share_url = "https://%s/layers/%s" % (request.get_host(), layer.typename) share_title = "%s by %s." % (layer.title, layer.owner) share_description = layer.abstract # Get membership buttons ready: admin_memberships = [] # Check if user is admin in one of those organizations users_org_memberships = OrganizationMembership.objects.filter( user_id=request.user.pk) for membership in users_org_memberships.all(): # We have permission if we own the layer, or if we are an organization's admin. if (layer.owner == request.user) or membership.is_admin: admin_memberships.append(membership) if len(admin_memberships) < 1: admin_memberships = None ini_memberships = [] # Checks if user is admin for Inititives user_ini_memberships = InitiativeMembership.objects.filter( user_id=request.user.pk) for membership in user_ini_memberships.all(): if (layer.owner == request.user) or membership.is_admin: ini_memberships.append(membership) if len(ini_memberships) < 1: ini_memberships = None shapefile_link = layer.link_set.download().filter(mime='SHAPE-ZIP').first() if shapefile_link is not None: shapefile_link = shapefile_link.url + '&featureID=fakeID' + '&maxFeatures=1' request.session['shp_name'] = layer.typename request.session['shp_link'] = shapefile_link csv_link = layer.link_set.download().filter(mime='csv').first() if csv_link is not None: csv_link = csv_link.url + '&featureID=fakeID' + '&maxFeatures=1' request.session['csv_name'] = layer.typename request.session['csv_link'] = csv_link ### # End MapStory Specific Changes ### context_dict = { 'resource': layer, 'group': group, 'perms_list': get_perms(request.user, layer.get_self_resource()), "permissions_json": _perms_info_json(layer), "documents": get_related_documents(layer), "metadata": metadata, "is_layer": True, "wps_enabled": settings.OGC_SERVER['default']['WPS_ENABLED'], "granules": granules, "all_granules": all_granules, "all_times": all_times, "show_popup": show_popup, "filter": filter, "storeType": layer.storeType, # MapStory Specific Additions "keywords": keywords, "keywords_form": keywords_form, "metadata_form": metadata_form, "distributionurl_form": distributionurl_form, "content_moderators": content_moderators, "thumbnail": thumbnail, "share_url": share_url, "share_title": share_title, "share_description": share_description, "organizations": admin_memberships, "initiatives": ini_memberships # "online": (layer.remote_service.probe == 200) if layer.storeType == "remoteStore" else True } if request and 'access_token' in request.session: access_token = request.session['access_token'] else: u = uuid.uuid1() access_token = u.hex context_dict["viewer"] = json.dumps( map_obj.viewer_json(request, *(NON_WMS_BASE_LAYERS + [maplayer]))) context_dict["preview"] = getattr(settings, 'GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY', 'geoext') context_dict["crs"] = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') # provide bbox in EPSG:4326 for leaflet if context_dict["preview"] == 'leaflet': srid, wkt = layer.geographic_bounding_box.split(';') srid = re.findall(r'\d+', srid) geom = GEOSGeometry(wkt, srid=int(srid[0])) geom.transform(4326) context_dict["layer_bbox"] = ','.join([str(c) for c in geom.extent]) if layer.storeType == 'dataStore': links = layer.link_set.download().filter( Q(name__in=settings.DOWNLOAD_FORMATS_VECTOR) | Q(link_type='original')) else: links = layer.link_set.download().filter( Q(name__in=settings.DOWNLOAD_FORMATS_RASTER) | Q(link_type='original')) links_view = [ item for idx, item in enumerate(links) if item.url and 'wms' in item.url or 'gwc' in item.url ] links_download = [ item for idx, item in enumerate(links) if item.url and 'wms' not in item.url and 'gwc' not in item.url ] for item in links_view: if item.url and access_token and 'access_token' not in item.url: params = {'access_token': access_token} item.url = Request('GET', item.url, params=params).prepare().url for item in links_download: if item.url and access_token and 'access_token' not in item.url: params = {'access_token': access_token} item.url = Request('GET', item.url, params=params).prepare().url if request.user.has_perm('view_resourcebase', layer.get_self_resource()): context_dict["links"] = links_view if request.user.has_perm('download_resourcebase', layer.get_self_resource()): if layer.storeType == 'dataStore': links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_VECTOR) else: links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_RASTER) context_dict["links_download"] = links_download if settings.SOCIAL_ORIGINS: context_dict["social_links"] = build_social_links(request, layer) layers_names = layer.alternate try: if settings.DEFAULT_WORKSPACE and settings.DEFAULT_WORKSPACE in layers_names: workspace, name = layers_names.split(':', 1) else: name = layers_names except BaseException: logger.error("Can not identify workspace type and layername") context_dict["layer_name"] = json.dumps(layers_names) try: # get type of layer (raster or vector) if layer.storeType == 'coverageStore': context_dict["layer_type"] = "raster" elif layer.storeType == 'dataStore': if layer.has_time: context_dict["layer_type"] = "vector_time" else: context_dict["layer_type"] = "vector" location = "{location}{service}".format( **{ 'location': settings.OGC_SERVER['default']['LOCATION'], 'service': 'wms', }) # get schema for specific layer username = settings.OGC_SERVER['default']['USER'] password = settings.OGC_SERVER['default']['PASSWORD'] schema = get_schema(location, name, username=username, password=password) # get the name of the column which holds the geometry if 'the_geom' in schema['properties']: schema['properties'].pop('the_geom', None) elif 'geom' in schema['properties']: schema['properties'].pop("geom", None) # filter the schema dict based on the values of layers_attributes layer_attributes_schema = [] for key in schema['properties'].keys(): layer_attributes_schema.append(key) filtered_attributes = layer_attributes_schema context_dict["schema"] = schema context_dict["filtered_attributes"] = filtered_attributes except BaseException: logger.error( "Possible error with OWSLib. Turning all available properties to string" ) if settings.GEOTIFF_IO_ENABLED: from geonode.contrib.geotiffio import create_geotiff_io_url context_dict["link_geotiff_io"] = create_geotiff_io_url( layer, access_token) # maps owned by user needed to fill the "add to existing map section" in template if request.user.is_authenticated(): context_dict["maps"] = Map.objects.filter(owner=request.user) return TemplateResponse(request, template, context=context_dict)
def gxp2wm(config, map_obj=None): """ Convert a GeoNode map json or string config to the WorldMap client format. """ config_is_string = False # let's first see if it is a string, in which case must be converted to json if isinstance(config, basestring): config = json.loads(config) config_is_string = True if map_obj: config['id'] = map_obj.id topics = TopicCategory.objects.all() topicArray = [] for topic in topics: topicArray.append([topic.identifier, topic.gn_description]) topicArray.append(['General', 'General']) groups = set() config['topic_categories'] = topicArray config['proxy'] = '/proxy/?url=' # TODO check permissions here config['edit_map'] = True # 3 different layer types # # 1. background layer: group: background, ows_url: None # # 2. WM local layer: # ows_url: http://localhost:8080/geoserver/wms, # layer_params = {"selected": true, "title": "camer_hyd_basins_vm0_2007", # "url": "http://localhost:8080/geoserver/wms", # "tiled": true, "detail_url": "http://worldmap.harvard.edu/data/geonode:camer_hyd_basins_vm0_2007", # "local": true, # "llbbox": [-94.549682617, 9.553222656, -82.972412109, 18.762207031]} # # 3. WM remote layer (HH): # ows_url: # http://192.168.33.15:8002/registry/hypermap/layer/13ff2fea-d479-4fc7-87a6-3eab7d349def/map/wmts/market/default_grid/$%7Bz%7D/$%7Bx%7D/$%7By%7D.png # layer_params = {"title": "market", "selected": true, # "detail_url": "http://192.168.33.15:8002/registry/hypermap/layer/13ff2fea-d479-4fc7-87a6-3eab7d349def/", # "local": false} # let's detect WM or HH layers and alter configuration as needed bbox = [-180, -90, 180, 90] valid_layers = [] for layer_config in config['map']['layers']: is_valid = True is_wm = False is_hh = False if 'source' not in layer_config: is_valid = False print 'Skipping this layer as it is missing source... %s' % layer_config else: source_id = layer_config['source'] source = config['sources'][source_id] if 'url' in source: source_url = source['url'] if settings.GEOSERVER_PUBLIC_LOCATION in source_url: config['sources'][source_id]['url'] = source_url if 'name' in layer_config: is_wm = True if 'registry/hypermap' in source_url: is_hh = True group = 'General' layer_config['tiled'] = True if is_wm: source = layer_config['source'] config['sources'][source]['ptype'] = 'gxp_gnsource' config['sources'][source]['url'] = config['sources'][source][ 'url'].replace('ows', 'wms') layer_config['local'] = True layer_config['queryable'] = True alternate = layer_config['name'] layer = None try: layer = Layer.objects.get(alternate=alternate) except Layer.DoesNotExist: is_valid = False print 'Skipping this layer as it is not existing in GeoNode... %s' % layer_config if layer: layer_config['attributes'] = (get_layer_attributes(layer)) layer_config['url'] = layer.ows_url.replace('ows', 'wms') if 'styles' not in layer_config: if layer.default_style: layer_config['styles'] = [ layer.default_style.name, ] else: if layer.styles.all().count() > 0: layer_config['styles'] = [ layer.styles.all()[0].name, ] else: if isinstance(layer_config['styles'], unicode): try: layer_config['styles'] = ast.literal_eval( layer_config['styles']) except: # noqa layer_config['styles'] = [ layer_config['styles'], ] if 'styles' not in layer_config: is_valid = False print 'Skipping this layer as it has not a style... %s' % layer_config if layer.category: group = layer.category.gn_description layer_config["srs"] = layer.srid layer_bbox = layer.bbox[0:4] bbox = layer_bbox[:] bbox[0] = float(layer_bbox[0]) bbox[1] = float(layer_bbox[2]) bbox[2] = float(layer_bbox[1]) bbox[3] = float(layer_bbox[3]) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) # Must be in the form : [x0, x1, y0, y1 return [_bbox[0], _bbox[2], _bbox[1], _bbox[3]] layer_config["bbox"] = decimal_encode( bbox_to_projection( [float(coord) for coord in layer_bbox] + [ layer.srid, ], target_srid=int(layer.srid.split(":")[1]))[:4]) if is_hh: layer_config['local'] = False layer_config['styles'] = '' hh_url = ('%smap/wmts/%s/default_grid/${z}/${x}/${y}.png' % (layer_config['detail_url'], layer_config['name'])) layer_config['url'] = hh_url if is_wm or is_hh: # bbox if is_wm: layer_config['llbbox'] = [ float(layer.ll_bbox[0]), float(layer.ll_bbox[2]), float(layer.ll_bbox[1]), float(layer.ll_bbox[3]) ] else: layer_config['llbbox'] = [float(coord) for coord in bbox] # group if 'group' not in layer_config: layer_config['group'] = group else: group = layer_config['group'] if group not in groups: groups.add(group) # let's make sure the group exists in topicArray (it could be a custom group create from user in GXP) is_in_topicarray = False for cat in topicArray: if group == cat[1]: is_in_topicarray = True if not is_in_topicarray: topicArray.append([group, group]) if is_valid: valid_layers.append(layer_config) config['map']['layers'] = valid_layers config['map']['groups'] = [] # about and groups from existing map if map_obj: config['about']['introtext'] = map_obj.extmap.content_map config['about']['urlsuffix'] = map_obj.urlsuffix if map_obj.extmap.group_params: config["map"]["groups"] = uniqifydict( json.loads(map_obj.extmap.group_params), 'group') else: # TODO check if this works with different languages config['about']['introtext'] = settings.DEFAULT_MAP_ABSTRACT if not [d for d in config['map']['groups'] if d['group'] == group]: for group in groups: config['map']['groups'].append({ "expanded": "true", "group": group }) if config_is_string: config = json.dumps(config) return config
def layer_detail(request, layername, template='layers/layer_detail.html'): layer = _resolve_layer( request, layername, 'base.view_resourcebase', _("You are not permitted to view this layer")) # assert False, str(layer_bbox) config = layer.attribute_config() # Add required parameters for GXP lazy-loading layer_bbox = layer.bbox bbox = [float(coord) for coord in list(layer_bbox[0:4])] config["srs"] = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') config["bbox"] = bbox if config["srs"] != 'EPSG:900913' \ else llbbox_to_mercator([float(coord) for coord in bbox]) config["title"] = layer.title config["queryable"] = True if layer.default_style: config["styles"] = layer.default_style.name if layer.storeType == "remoteStore": source_srid = None # Only grab the service proj/bbox if it is valid if None not in layer.service.bbox[0:4]: bbox = [float(coord) for coord in list(layer.service.bbox[0:4])] source_srid = layer.service.srid # Otherwise try the service directly # This is needed since previous services registered # did not store the bbox/srid in the model else: try: service_handler = get_service_handler( base_url=layer.service.base_url, service_type=layer.service.type) if getattr(service_handler.parsed_service, 'initialExtent', None): bbox[0] = service_handler.parsed_service.initialExtent[ 'xmin'] bbox[1] = service_handler.parsed_service.initialExtent[ 'ymin'] bbox[2] = service_handler.parsed_service.initialExtent[ 'xmax'] bbox[3] = service_handler.parsed_service.initialExtent[ 'ymax'] else: logger.info('Could not retrieve extent from service: {0}' .format(layer.service)) if getattr(service_handler.parsed_service, 'spatialReference', None): source_srid = \ service_handler.parsed_service.spatialReference[ 'latestWkid'] else: logger.info('Could not retrieve srid from service: {0}' .format(layer.service)) except Exception as e: logger.info('Failed to access service endpoint: {0}' .format(layer.service.base_url)) logger.info('Caught error: {0}'.format(e)) if source_srid is None: source_srid = layer.srid target_srid = 3857 if config["srs"] == 'EPSG:900913' else config["srs"] reprojected_bbox = bbox_to_projection(bbox, source_srid=source_srid, target_srid=target_srid) bbox = reprojected_bbox[:4] config['bbox'] = [float(coord) for coord in bbox] service = layer.service source_url = service.base_url use_proxy = (callable(uses_proxy_route) and uses_proxy_route(service.base_url)) components = urlsplit(service.base_url) query_params = None if components.query: query_params = OrderedDict( parse_qsl(components.query, keep_blank_values=True)) removed_query = [components.scheme, components.netloc, components.path, None, components.fragment] source_url = urlunsplit(removed_query) source_params = { "ptype": service.ptype, "remote": True, "url": source_url, "name": service.name, "use_proxy": use_proxy} if query_params is not None: source_params["params"] = query_params if layer.alternate is not None: config["layerid"] = layer.alternate maplayer = GXPLayer( name=layer.typename, ows_url=layer.ows_url, layer_params=json.dumps(config), source_params=json.dumps(source_params)) else: maplayer = GXPLayer( name=layer.typename, ows_url=layer.ows_url, layer_params=json.dumps(config)) # Update count for popularity ranking, # but do not includes admins or resource owners if request.user != layer.owner and not request.user.is_superuser: Layer.objects.filter( id=layer.id).update(popular_count=F('popular_count') + 1) # center/zoom don't matter; the viewer will center on the layer bounds map_obj = GXPMap( projection=getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913')) metadata = layer.link_set.metadata().filter( name__in=settings.DOWNLOAD_FORMATS_METADATA) granules = None all_granules = None filter = None if layer.is_mosaic: try: cat = gs_catalog cat._cache.clear() store = cat.get_store(layer.name) coverages = cat.mosaic_coverages(store) filter = None try: if request.GET["filter"]: filter = request.GET["filter"] except: pass offset = 10 * (request.page - 1) granules = cat.mosaic_granules( coverages['coverages']['coverage'][0]['name'], store, limit=10, offset=offset, filter=filter) all_granules = cat.mosaic_granules( coverages['coverages']['coverage'][0]['name'], store, filter=filter) except: granules = {"features": []} all_granules = {"features": []} context_dict = { "resource": layer, 'perms_list': get_perms(request.user, layer.get_self_resource()), "permissions_json": _perms_info_json(layer), "documents": get_related_documents(layer), "metadata": metadata, "is_layer": True, "wps_enabled": settings.OGC_SERVER['default']['WPS_ENABLED'], "granules": granules, "all_granules": all_granules, "filter": filter, } if 'access_token' in request.session: access_token = request.session['access_token'] else: u = uuid.uuid1() access_token = u.hex if bbox is not None: minx, miny, maxx, maxy = [float(coord) for coord in bbox] x = (minx + maxx) / 2 y = (miny + maxy) / 2 if layer.is_remote or getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') == "EPSG:4326": center = list((x, y)) else: center = list(forward_mercator((x, y))) if center[1] == float('-inf'): center[1] = 0 BBOX_DIFFERENCE_THRESHOLD = 1e-5 # Check if the bbox is invalid valid_x = (maxx - minx) ** 2 > BBOX_DIFFERENCE_THRESHOLD valid_y = (maxy - miny) ** 2 > BBOX_DIFFERENCE_THRESHOLD if valid_x: width_zoom = math.log(360 / abs(maxx - minx), 2) else: width_zoom = 15 if valid_y: height_zoom = math.log(360 / abs(maxy - miny), 2) else: height_zoom = 15 map_obj.center_x = center[0] map_obj.center_y = center[1] map_obj.zoom = math.ceil(min(width_zoom, height_zoom)) context_dict["viewer"] = json.dumps( map_obj.viewer_json(request.user, access_token, *(default_map_config(request)[1] + [maplayer]))) context_dict["preview"] = getattr( settings, 'LAYER_PREVIEW_LIBRARY', 'leaflet') context_dict["crs"] = getattr( settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') if layer.storeType == 'dataStore': links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_VECTOR) else: links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_RASTER) links_view = [item for idx, item in enumerate(links) if item.url and 'wms' in item.url or 'gwc' in item.url] links_download = [item for idx, item in enumerate(links) if item.url and 'wms' not in item.url and 'gwc' not in item.url] for item in links_view: if item.url and access_token: item.url = "%s&access_token=%s&time=%s" % \ (item.url, access_token, "0/9999") for item in links_download: if item.url and access_token: item.url = "%s&access_token=%s" % (item.url, access_token) if request.user.has_perm('view_resourcebase', layer.get_self_resource()): context_dict["links"] = links_view if request.user.has_perm('download_resourcebase', layer.get_self_resource()): if layer.storeType == 'dataStore': links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_VECTOR) else: links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_RASTER) context_dict["links_download"] = links_download if settings.SOCIAL_ORIGINS: context_dict["social_links"] = build_social_links(request, layer) return render_to_response(template, RequestContext(request, context_dict))
def create_gs_thumbnail_geonode(instance, overwrite=False, check_bbox=False): """ Create a thumbnail with a GeoServer request. """ layers = None bbox = None # x0, x1, y0, y1 local_layers = [] local_bboxes = [] if isinstance(instance, Map): # a map could be empty! if not instance.layers: return for layer in instance.layers: if layer.local: local_layers.append(layer.name) # Compute Bounds _l = Layer.objects.get(alternate=layer.name) wgs84_bbox = bbox_to_projection(_l.bbox) local_bboxes.append(wgs84_bbox) layers = ",".join(local_layers).encode('utf-8') else: layers = instance.alternate.encode('utf-8') # Compute Bounds _l = Layer.objects.get(alternate=layers) wgs84_bbox = bbox_to_projection(_l.bbox) local_bboxes.append(wgs84_bbox) if local_bboxes: for _bbox in local_bboxes: if bbox is None: bbox = list(_bbox) else: if bbox[0] > _bbox[0]: bbox[0] = _bbox[0] if bbox[1] < _bbox[1]: bbox[1] = _bbox[1] if bbox[2] > _bbox[2]: bbox[2] = _bbox[2] if bbox[3] < _bbox[3]: bbox[3] = _bbox[3] wms_endpoint = getattr(ogc_server_settings, 'WMS_ENDPOINT') or 'ows' wms_version = getattr(ogc_server_settings, 'WMS_VERSION') or '1.1.1' wms_format = getattr(ogc_server_settings, 'WMS_FORMAT') or 'image/png8' params = { 'service': 'WMS', 'version': wms_version, 'request': 'GetMap', 'layers': layers, 'format': wms_format, # 'TIME': '-99999999999-01-01T00:00:00.0Z/99999999999-01-01T00:00:00.0Z' } if bbox: params['bbox'] = "%s,%s,%s,%s" % (bbox[0], bbox[2], bbox[1], bbox[3]) params['crs'] = 'EPSG:4326' params['width'] = 240 params['height'] = 180 user = None try: username = ogc_server_settings.credentials.username user = get_user_model().objects.get(username=username) except BaseException as e: logger.exception(e) access_token = None if user: access_token = get_or_create_token(user) if access_token and not access_token.is_expired(): params['access_token'] = access_token.token # Avoid using urllib.urlencode here because it breaks the url. # commas and slashes in values get encoded and then cause trouble # with the WMS parser. _p = "&".join("%s=%s" % item for item in params.items()) import posixpath thumbnail_remote_url = posixpath.join(ogc_server_settings.PUBLIC_LOCATION, wms_endpoint) + "?" + _p thumbnail_create_url = posixpath.join(ogc_server_settings.LOCATION, wms_endpoint) + "?" + _p create_thumbnail(instance, thumbnail_remote_url, thumbnail_create_url, overwrite=overwrite, check_bbox=check_bbox)
def new_map_config(request): ''' View that creates a new map. If the query argument 'copy' is given, the initial map is a copy of the map with the id specified, otherwise the default map configuration is used. If copy is specified and the map specified does not exist a 404 is returned. ''' DEFAULT_MAP_CONFIG, DEFAULT_BASE_LAYERS = default_map_config(request) if 'access_token' in request.session: access_token = request.session['access_token'] else: access_token = None if request.method == 'GET' and 'copy' in request.GET: mapid = request.GET['copy'] map_obj = _resolve_map(request, mapid, 'base.view_resourcebase') map_obj.abstract = DEFAULT_ABSTRACT map_obj.title = DEFAULT_TITLE map_obj.refresh_interval = 60000 if request.user.is_authenticated(): map_obj.owner = request.user config = map_obj.viewer_json(request.user, access_token) del config['id'] else: if request.method == 'GET': params = request.GET elif request.method == 'POST': params = request.POST else: return HttpResponse(status=405) if 'layer' in params: bbox = None map_obj = Map(projection=getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913')) layers = [] for layer_name in params.getlist('layer'): try: layer = _resolve_layer(request, layer_name) except ObjectDoesNotExist: # bad layer, skip continue except Http404: # can't find the layer, skip it. continue if not request.user.has_perm( 'view_resourcebase', obj=layer.get_self_resource()): # invisible layer, skip inclusion continue layer_bbox = layer.bbox # assert False, str(layer_bbox) if bbox is None: bbox = list(layer_bbox[0:4]) else: bbox = list(bbox) bbox[0] = min(bbox[0], layer_bbox[0]) bbox[1] = max(bbox[1], layer_bbox[1]) bbox[2] = min(bbox[2], layer_bbox[2]) bbox[3] = max(bbox[3], layer_bbox[3]) config = layer.attribute_config() # Add required parameters for GXP lazy-loading config["title"] = layer.title config["queryable"] = True config["srs"] = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') config["bbox"] = bbox if config["srs"] != 'EPSG:900913' \ else llbbox_to_mercator([float(coord) for coord in bbox]) if layer.storeType == "remoteStore": service = layer.service # Probably not a good idea to send the access token # to every remote service. This should never match, # so no access token should be sent to remote services. ogc_server_url = urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc service_url = urlsplit(service.base_url).netloc if config["srs"] == 'EPSG:900913': target_srid = 3857 else: target_srid = config["srs"] reprojected_bbox = bbox_to_projection( bbox, source_srid=layer.srid, target_srid=target_srid ) bbox = reprojected_bbox[:4] config['bbox'] = [float(coord) for coord in bbox] if access_token and ogc_server_url == service_url and \ 'access_token' not in service.base_url: url = service.base_url + '?access_token={}'.format( access_token) else: url = service.base_url use_proxy = (callable(uses_proxy_route) and uses_proxy_route(service.base_url)) if layer.alternate is not None: config["layerid"] = layer.alternate maplayer = MapLayer( map=map_obj, name=layer.typename, ows_url=layer.ows_url, layer_params=json.dumps(config, cls=DjangoJSONEncoder), visibility=True, source_params=json.dumps({ "ptype": service.ptype, "remote": True, "url": url, "name": service.name, "use_proxy": use_proxy}) ) else: ogc_server_url = urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc layer_url = urlsplit(layer.ows_url).netloc if access_token and ogc_server_url == layer_url and \ 'access_token' not in layer.ows_url: url = layer.ows_url + '?access_token=' + access_token else: url = layer.ows_url maplayer = MapLayer( map=map_obj, name=layer.typename, ows_url=url, # use DjangoJSONEncoder to handle Decimal values layer_params=json.dumps(config, cls=DjangoJSONEncoder), visibility=True ) layers.append(maplayer) if bbox is not None: minx, miny, maxx, maxy = [float(coord) for coord in bbox] x = (minx + maxx) / 2 y = (miny + maxy) / 2 if layer.is_remote or getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') == "EPSG:4326": center = list((x, y)) else: center = list(forward_mercator((x, y))) if center[1] == float('-inf'): center[1] = 0 BBOX_DIFFERENCE_THRESHOLD = 1e-5 # Check if the bbox is invalid valid_x = (maxx - minx) ** 2 > BBOX_DIFFERENCE_THRESHOLD valid_y = (maxy - miny) ** 2 > BBOX_DIFFERENCE_THRESHOLD if valid_x: width_zoom = math.log(360 / abs(maxx - minx), 2) else: width_zoom = 15 if valid_y: height_zoom = math.log(360 / abs(maxy - miny), 2) else: height_zoom = 15 map_obj.center_x = center[0] map_obj.center_y = center[1] map_obj.zoom = math.ceil(min(width_zoom, height_zoom)) config = map_obj.viewer_json( request.user, access_token, *(DEFAULT_BASE_LAYERS + layers)) config['fromLayer'] = True else: config = DEFAULT_MAP_CONFIG return json.dumps(config)
def layer_detail(request, layername, template='layers/layer_detail.html'): layer = _resolve_layer( request, layername, 'base.view_resourcebase', _PERMISSION_MSG_VIEW) # assert False, str(layer_bbox) config = layer.attribute_config() # Add required parameters for GXP lazy-loading layer_bbox = layer.bbox[0:4] bbox = layer_bbox[:] bbox[0] = float(layer_bbox[0]) bbox[1] = float(layer_bbox[2]) bbox[2] = float(layer_bbox[1]) bbox[3] = float(layer_bbox[3]) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) # Must be in the form : [x0, x1, y0, y1 return [_bbox[0], _bbox[2], _bbox[1], _bbox[3]] def sld_definition(style): from urllib import quote _sld = { "title": style.sld_title or style.name, "legend": { "height": "40", "width": "22", "href": layer.ows_url + "?service=wms&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=" + quote(layer.service_typename, safe=''), "format": "image/png" }, "name": style.name } return _sld if hasattr(layer, 'srid'): config['crs'] = { 'type': 'name', 'properties': layer.srid } # Add required parameters for GXP lazy-loading attribution = "%s %s" % (layer.owner.first_name, layer.owner.last_name) if layer.owner.first_name or layer.owner.last_name else str( layer.owner) srs = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') srs_srid = int(srs.split(":")[1]) if srs != "EPSG:900913" else 3857 config["attribution"] = "<span class='gx-attribution-title'>%s</span>" % attribution config["format"] = getattr( settings, 'DEFAULT_LAYER_FORMAT', 'image/png') config["title"] = layer.title config["wrapDateLine"] = True config["visibility"] = True config["srs"] = srs config["bbox"] = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=int(srs.split(":")[1]))[:4]) config["capability"] = { "abstract": layer.abstract, "name": layer.alternate, "title": layer.title, "queryable": True, "storeType": layer.storeType, "bbox": { layer.srid: { "srs": layer.srid, "bbox": decimal_encode(bbox) }, srs: { "srs": srs, "bbox": decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=srs_srid)[:4]) }, "EPSG:4326": { "srs": "EPSG:4326", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else decimal_encode(bbox_to_projection( [float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=4326)[:4]) }, "EPSG:900913": { "srs": "EPSG:900913", "bbox": decimal_encode(bbox) if layer.srid == 'EPSG:900913' else decimal_encode(bbox_to_projection( [float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=3857)[:4]) } }, "srs": { srs: True }, "formats": ["image/png", "application/atom xml", "application/atom+xml", "application/json;type=utfgrid", "application/openlayers", "application/pdf", "application/rss xml", "application/rss+xml", "application/vnd.google-earth.kml", "application/vnd.google-earth.kml xml", "application/vnd.google-earth.kml+xml", "application/vnd.google-earth.kml+xml;mode=networklink", "application/vnd.google-earth.kmz", "application/vnd.google-earth.kmz xml", "application/vnd.google-earth.kmz+xml", "application/vnd.google-earth.kmz;mode=networklink", "atom", "image/geotiff", "image/geotiff8", "image/gif", "image/gif;subtype=animated", "image/jpeg", "image/png8", "image/png; mode=8bit", "image/svg", "image/svg xml", "image/svg+xml", "image/tiff", "image/tiff8", "image/vnd.jpeg-png", "kml", "kmz", "openlayers", "rss", "text/html; subtype=openlayers", "utfgrid"], "attribution": { "title": attribution }, "infoFormats": ["text/plain", "application/vnd.ogc.gml", "text/xml", "application/vnd.ogc.gml/3.1.1", "text/xml; subtype=gml/3.1.1", "text/html", "application/json"], "styles": [sld_definition(s) for s in layer.styles.all()], "prefix": layer.alternate.split(":")[0] if ":" in layer.alternate else "", "keywords": [k.name for k in layer.keywords.all()] if layer.keywords else [], "llbbox": decimal_encode(bbox) if layer.srid == 'EPSG:4326' else decimal_encode(bbox_to_projection( [float(coord) for coord in layer_bbox] + [layer.srid, ], target_srid=4326)[:4]) } all_times = None if check_ogc_backend(geoserver.BACKEND_PACKAGE): from geonode.geoserver.views import get_capabilities workspace, layername = layer.alternate.split( ":") if ":" in layer.alternate else (None, layer.alternate) # WARNING Please make sure to have enabled DJANGO CACHE as per # https://docs.djangoproject.com/en/2.0/topics/cache/#filesystem-caching wms_capabilities_resp = get_capabilities( request, layer.id, tolerant=True) if wms_capabilities_resp.status_code >= 200 and wms_capabilities_resp.status_code < 400: wms_capabilities = wms_capabilities_resp.getvalue() if wms_capabilities: import xml.etree.ElementTree as ET e = ET.fromstring(wms_capabilities) for atype in e.findall( "./[Name='%s']/Extent[@name='time']" % (layername)): dim_name = atype.get('name') if dim_name: dim_name = str(dim_name).lower() if dim_name == 'time': dim_values = atype.text if dim_values: all_times = dim_values.split(",") break if all_times: config["capability"]["dimensions"] = { "time": { "name": "time", "units": "ISO8601", "unitsymbol": None, "nearestVal": False, "multipleVal": False, "current": False, "default": "current", "values": all_times } } if layer.storeType == "remoteStore": service = layer.remote_service source_params = {} if service.type in ('REST_MAP', 'REST_IMG'): source_params = { "ptype": service.ptype, "remote": True, "url": service.service_url, "name": service.name, "title": "[R] %s" % service.title} maplayer = GXPLayer( name=layer.alternate, ows_url=layer.ows_url, layer_params=json.dumps(config), source_params=json.dumps(source_params) ) else: maplayer = GXPLayer( name=layer.alternate, ows_url=layer.ows_url, layer_params=json.dumps(config) ) # Update count for popularity ranking, # but do not includes admins or resource owners layer.view_count_up(request.user) # center/zoom don't matter; the viewer will center on the layer bounds map_obj = GXPMap( sender=Layer, projection=getattr( settings, 'DEFAULT_MAP_CRS', 'EPSG:3857')) NON_WMS_BASE_LAYERS = [ la for la in default_map_config(request)[1] if la.ows_url is None] metadata = layer.link_set.metadata().filter( name__in=settings.DOWNLOAD_FORMATS_METADATA) granules = None all_granules = None all_times = None filter = None if layer.is_mosaic: try: cat = gs_catalog cat._cache.clear() store = cat.get_store(layer.name) coverages = cat.mosaic_coverages(store) filter = None try: if request.GET["filter"]: filter = request.GET["filter"] except BaseException: pass offset = 10 * (request.page - 1) granules = cat.mosaic_granules( coverages['coverages']['coverage'][0]['name'], store, limit=10, offset=offset, filter=filter) all_granules = cat.mosaic_granules( coverages['coverages']['coverage'][0]['name'], store, filter=filter) except BaseException: granules = {"features": []} all_granules = {"features": []} if check_ogc_backend(geoserver.BACKEND_PACKAGE): from geonode.geoserver.views import get_capabilities workspace, layername = layer.alternate.split( ":") if ":" in layer.alternate else (None, layer.alternate) # WARNING Please make sure to have enabled DJANGO CACHE as per # https://docs.djangoproject.com/en/2.0/topics/cache/#filesystem-caching wms_capabilities_resp = get_capabilities( request, layer.id, tolerant=True) if wms_capabilities_resp.status_code >= 200 and wms_capabilities_resp.status_code < 400: wms_capabilities = wms_capabilities_resp.getvalue() if wms_capabilities: import xml.etree.ElementTree as ET e = ET.fromstring(wms_capabilities) for atype in e.findall( "./[Name='%s']/Extent[@name='time']" % (layername)): dim_name = atype.get('name') if dim_name: dim_name = str(dim_name).lower() if dim_name == 'time': dim_values = atype.text if dim_values: all_times = dim_values.split(",") break group = None if layer.group: try: group = GroupProfile.objects.get(slug=layer.group.name) except GroupProfile.DoesNotExist: group = None # a flag to be used for qgis server show_popup = False if 'show_popup' in request.GET and request.GET["show_popup"]: show_popup = True ### # MapStory Specific Changes ### keywords = json.dumps([tag.name for tag in layer.keywords.all()]) if request.method == "POST": keywords_form = KeywordsForm(request.POST, instance=layer) metadata_form = MetadataForm(instance=layer) distributionurl_form = DistributionUrlForm( request.POST, instance=layer) if 'keywords' in request.POST: if keywords_form.is_valid(): keywords_form.save() new_keywords = keywords_form.cleaned_data['keywords'] layer.keywords.set(*new_keywords) layer.save() metadata_form = MetadataForm(instance=layer) elif 'title' in request.POST: metadata_form = MetadataForm(request.POST, instance=layer) if metadata_form.is_valid(): metadata_form.save() # update all the metadata if metadata_form.cleaned_data['category'] is not None: new_category = TopicCategory.objects.get( id=metadata_form.cleaned_data['category'].id) Layer.objects.filter(id=layer.id).update( category=new_category) layer.title = metadata_form.cleaned_data['title'] layer.language = metadata_form.cleaned_data['language'] layer.data_quality_statement = metadata_form.cleaned_data['data_quality_statement'] layer.purpose = metadata_form.cleaned_data['purpose'] layer.is_published = metadata_form.cleaned_data['is_published'] layer.save() if distributionurl_form.is_valid(): layer.distribution_url = distributionurl_form.cleaned_data['distribution_url'] keywords_form = KeywordsForm(instance=layer) if 'add_keyword' in request.POST: layer.keywords.add(request.POST['add_keyword']) layer.save() if 'remove_keyword' in request.POST: layer.keywords.remove(request.POST['remove_keyword']) layer.save() else: keywords_form = KeywordsForm(instance=layer) metadata_form = MetadataForm(instance=layer) distributionurl_form = DistributionUrlForm(instance=layer) content_moderators = Group.objects.filter(name='content_moderator').first() thumbnail = layer.get_thumbnail_url # This will get URL encoded later and is used for the social media share URL share_url = "https://%s/layers/%s" % (request.get_host(), layer.typename) share_title = "%s by %s." % (layer.title, layer.owner) share_description = layer.abstract # Get membership buttons ready: admin_memberships = [] # Check if user is admin in one of those organizations users_org_memberships = OrganizationMembership.objects.filter( user_id=request.user.pk) for membership in users_org_memberships.all(): # We have permission if we own the layer, or if we are an organization's admin. if (layer.owner == request.user) or membership.is_admin: admin_memberships.append(membership) if len(admin_memberships) < 1: admin_memberships = None ini_memberships = [] # Checks if user is admin for Inititives user_ini_memberships = InitiativeMembership.objects.filter( user_id=request.user.pk) for membership in user_ini_memberships.all(): if(layer.owner == request.user) or membership.is_admin: ini_memberships.append(membership) if len(ini_memberships) < 1: ini_memberships = None shapefile_link = layer.link_set.download().filter(mime='SHAPE-ZIP').first() if shapefile_link is not None: shapefile_link = shapefile_link.url + '&featureID=fakeID' + '&maxFeatures=1' request.session['shp_name'] = layer.typename request.session['shp_link'] = shapefile_link csv_link = layer.link_set.download().filter(mime='csv').first() if csv_link is not None: csv_link = csv_link.url + '&featureID=fakeID' + '&maxFeatures=1' request.session['csv_name'] = layer.typename request.session['csv_link'] = csv_link ### # End MapStory Specific Changes ### context_dict = { 'resource': layer, 'group': group, 'perms_list': get_perms(request.user, layer.get_self_resource()), "permissions_json": _perms_info_json(layer), "documents": get_related_documents(layer), "metadata": metadata, "is_layer": True, "wps_enabled": settings.OGC_SERVER['default']['WPS_ENABLED'], "granules": granules, "all_granules": all_granules, "all_times": all_times, "show_popup": show_popup, "filter": filter, "storeType": layer.storeType, # MapStory Specific Additions "keywords": keywords, "keywords_form": keywords_form, "metadata_form": metadata_form, "distributionurl_form": distributionurl_form, "content_moderators": content_moderators, "thumbnail": thumbnail, "share_url": share_url, "share_title": share_title, "share_description": share_description, "organizations": admin_memberships, "initiatives": ini_memberships # "online": (layer.remote_service.probe == 200) if layer.storeType == "remoteStore" else True } if request and 'access_token' in request.session: access_token = request.session['access_token'] else: u = uuid.uuid1() access_token = u.hex context_dict["viewer"] = json.dumps(map_obj.viewer_json( request, * (NON_WMS_BASE_LAYERS + [maplayer]))) context_dict["preview"] = getattr( settings, 'GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY', 'geoext') context_dict["crs"] = getattr( settings, 'DEFAULT_MAP_CRS', 'EPSG:3857') # provide bbox in EPSG:4326 for leaflet if context_dict["preview"] == 'leaflet': srid, wkt = layer.geographic_bounding_box.split(';') srid = re.findall(r'\d+', srid) geom = GEOSGeometry(wkt, srid=int(srid[0])) geom.transform(4326) context_dict["layer_bbox"] = ','.join([str(c) for c in geom.extent]) if layer.storeType == 'dataStore': links = layer.link_set.download().filter( Q(name__in=settings.DOWNLOAD_FORMATS_VECTOR) | Q(link_type='original')) else: links = layer.link_set.download().filter( Q(name__in=settings.DOWNLOAD_FORMATS_RASTER) | Q(link_type='original')) links_view = [item for idx, item in enumerate(links) if item.url and 'wms' in item.url or 'gwc' in item.url] links_download = [item for idx, item in enumerate( links) if item.url and 'wms' not in item.url and 'gwc' not in item.url] for item in links_view: if item.url and access_token and 'access_token' not in item.url: params = {'access_token': access_token} item.url = Request('GET', item.url, params=params).prepare().url for item in links_download: if item.url and access_token and 'access_token' not in item.url: params = {'access_token': access_token} item.url = Request('GET', item.url, params=params).prepare().url if request.user.has_perm('view_resourcebase', layer.get_self_resource()): context_dict["links"] = links_view if request.user.has_perm( 'download_resourcebase', layer.get_self_resource()): if layer.storeType == 'dataStore': links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_VECTOR) else: links = layer.link_set.download().filter( name__in=settings.DOWNLOAD_FORMATS_RASTER) context_dict["links_download"] = links_download if settings.SOCIAL_ORIGINS: context_dict["social_links"] = build_social_links(request, layer) layers_names = layer.alternate try: if settings.DEFAULT_WORKSPACE and settings.DEFAULT_WORKSPACE in layers_names: workspace, name = layers_names.split(':', 1) else: name = layers_names except BaseException: logger.error("Can not identify workspace type and layername") context_dict["layer_name"] = json.dumps(layers_names) try: # get type of layer (raster or vector) if layer.storeType == 'coverageStore': context_dict["layer_type"] = "raster" elif layer.storeType == 'dataStore': if layer.has_time: context_dict["layer_type"] = "vector_time" else: context_dict["layer_type"] = "vector" location = "{location}{service}".format(** { 'location': settings.OGC_SERVER['default']['LOCATION'], 'service': 'wms', }) # get schema for specific layer username = settings.OGC_SERVER['default']['USER'] password = settings.OGC_SERVER['default']['PASSWORD'] schema = get_schema( location, name, username=username, password=password) # get the name of the column which holds the geometry if 'the_geom' in schema['properties']: schema['properties'].pop('the_geom', None) elif 'geom' in schema['properties']: schema['properties'].pop("geom", None) # filter the schema dict based on the values of layers_attributes layer_attributes_schema = [] for key in schema['properties'].keys(): layer_attributes_schema.append(key) filtered_attributes = layer_attributes_schema context_dict["schema"] = schema context_dict["filtered_attributes"] = filtered_attributes except BaseException: logger.error( "Possible error with OWSLib. Turning all available properties to string") if settings.GEOTIFF_IO_ENABLED: from geonode.contrib.geotiffio import create_geotiff_io_url context_dict["link_geotiff_io"] = create_geotiff_io_url( layer, access_token) # maps owned by user needed to fill the "add to existing map section" in template if request.user.is_authenticated(): context_dict["maps"] = Map.objects.filter(owner=request.user) return TemplateResponse( request, template, context=context_dict)
def facets(context): request = context['request'] title_filter = request.GET.get('title__icontains', '') extent_filter = request.GET.get('extent', None) keywords_filter = request.GET.getlist('keywords__slug__in', None) category_filter = request.GET.getlist('category__identifier__in', None) regions_filter = request.GET.getlist('regions__name__in', None) owner_filter = request.GET.getlist('owner__username__in', None) date_gte_filter = request.GET.get('date__gte', None) date_lte_filter = request.GET.get('date__lte', None) date_range_filter = request.GET.get('date__range', None) facet_type = context['facet_type'] if 'facet_type' in context else 'all' if not settings.SKIP_PERMS_FILTER: authorized = [] try: authorized = get_objects_for_user( request.user, 'base.view_resourcebase').values('id') except Exception: pass if facet_type == 'documents': documents = Document.objects.filter(title__icontains=title_filter) if category_filter: documents = documents.filter(category__identifier__in=category_filter) if regions_filter: documents = documents.filter(regions__name__in=regions_filter) if owner_filter: documents = documents.filter(owner__username__in=owner_filter) if date_gte_filter: documents = documents.filter(date__gte=date_gte_filter) if date_lte_filter: documents = documents.filter(date__lte=date_lte_filter) if date_range_filter: documents = documents.filter(date__range=date_range_filter.split(',')) documents = get_visible_resources( documents, request.user if request else None, admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, unpublished_not_visible=settings.RESOURCE_PUBLISHING, private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) if keywords_filter: treeqs = HierarchicalKeyword.objects.none() for keyword in keywords_filter: try: kws = HierarchicalKeyword.objects.filter(name__iexact=keyword) for kw in kws: treeqs = treeqs | HierarchicalKeyword.get_tree(kw) except Exception: # Ignore keywords not actually used? pass documents = documents.filter(Q(keywords__in=treeqs)) if not settings.SKIP_PERMS_FILTER: documents = documents.filter(id__in=authorized) counts = documents.values('doc_type').annotate(count=Count('doc_type')) facets = dict([(count['doc_type'], count['count']) for count in counts]) return facets else: layers = Layer.objects.filter(title__icontains=title_filter) if category_filter: layers = layers.filter(category__identifier__in=category_filter) if regions_filter: layers = layers.filter(regions__name__in=regions_filter) if owner_filter: layers = layers.filter(owner__username__in=owner_filter) if date_gte_filter: layers = layers.filter(date__gte=date_gte_filter) if date_lte_filter: layers = layers.filter(date__lte=date_lte_filter) if date_range_filter: layers = layers.filter(date__range=date_range_filter.split(',')) layers = get_visible_resources( layers, request.user if request else None, admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, unpublished_not_visible=settings.RESOURCE_PUBLISHING, private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) if extent_filter: from geonode.utils import bbox_to_projection bbox = extent_filter.split(',') bbox = list(map(str, bbox)) intersects = (Q(bbox_x0__gt=bbox[0]) & Q(bbox_x1__lt=bbox[2]) & Q(bbox_y0__gt=bbox[1]) & Q(bbox_y1__lt=bbox[3])) for proj in Layer.objects.order_by('srid').values('srid').distinct(): if proj['srid'] != 'EPSG:4326': proj_bbox = bbox_to_projection(bbox + ['4326', ], target_srid=int(proj['srid'][5:])) if proj_bbox[-1] != 4326: intersects = intersects | (Q(bbox_x0__gt=proj_bbox[0]) & Q(bbox_x1__lt=proj_bbox[2]) & Q( bbox_y0__gt=proj_bbox[1]) & Q(bbox_y1__lt=proj_bbox[3])) layers = layers.filter(intersects) if keywords_filter: treeqs = HierarchicalKeyword.objects.none() for keyword in keywords_filter: try: kws = HierarchicalKeyword.objects.filter(name__iexact=keyword) for kw in kws: treeqs = treeqs | HierarchicalKeyword.get_tree(kw) except Exception: # Ignore keywords not actually used? pass layers = layers.filter(Q(keywords__in=treeqs)) if not settings.SKIP_PERMS_FILTER: layers = layers.filter(id__in=authorized) counts = layers.values('storeType').annotate(count=Count('storeType')) counts_array = [] try: for count in counts: counts_array.append((count['storeType'], count['count'])) except Exception: pass count_dict = dict(counts_array) vector_time_series = layers.exclude(has_time=False).filter(storeType='dataStore'). \ values('storeType').annotate(count=Count('storeType')) if vector_time_series: count_dict['vectorTimeSeries'] = vector_time_series[0]['count'] facets = { 'raster': count_dict.get('coverageStore', 0), 'vector': count_dict.get('dataStore', 0), 'vector_time': count_dict.get('vectorTimeSeries', 0), 'remote': count_dict.get('remoteStore', 0), 'wms': count_dict.get('wmsStore', 0), } # Break early if only_layers is set. if facet_type == 'layers': return facets maps = Map.objects.filter(title__icontains=title_filter) documents = Document.objects.filter(title__icontains=title_filter) if category_filter: maps = maps.filter(category__identifier__in=category_filter) documents = documents.filter(category__identifier__in=category_filter) if regions_filter: maps = maps.filter(regions__name__in=regions_filter) documents = documents.filter(regions__name__in=regions_filter) if owner_filter: maps = maps.filter(owner__username__in=owner_filter) documents = documents.filter(owner__username__in=owner_filter) if date_gte_filter: maps = maps.filter(date__gte=date_gte_filter) documents = documents.filter(date__gte=date_gte_filter) if date_lte_filter: maps = maps.filter(date__lte=date_lte_filter) documents = documents.filter(date__lte=date_lte_filter) if date_range_filter: maps = maps.filter(date__range=date_range_filter.split(',')) documents = documents.filter(date__range=date_range_filter.split(',')) maps = get_visible_resources( maps, request.user if request else None, admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, unpublished_not_visible=settings.RESOURCE_PUBLISHING, private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) documents = get_visible_resources( documents, request.user if request else None, admin_approval_required=settings.ADMIN_MODERATE_UPLOADS, unpublished_not_visible=settings.RESOURCE_PUBLISHING, private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES) if extent_filter: bbox = extent_filter.split( ',') # TODO: Why is this different when done through haystack? bbox = map(str, bbox) # 2.6 compat - float to decimal conversion intersects = ~(Q(bbox_x0__gt=bbox[2]) | Q(bbox_x1__lt=bbox[0]) | Q(bbox_y0__gt=bbox[3]) | Q(bbox_y1__lt=bbox[1])) maps = maps.filter(intersects) documents = documents.filter(intersects) if keywords_filter: treeqs = HierarchicalKeyword.objects.none() for keyword in keywords_filter: try: kws = HierarchicalKeyword.objects.filter(name__iexact=keyword) for kw in kws: treeqs = treeqs | HierarchicalKeyword.get_tree(kw) except Exception: # Ignore keywords not actually used? pass maps = maps.filter(Q(keywords__in=treeqs)) documents = documents.filter(Q(keywords__in=treeqs)) if not settings.SKIP_PERMS_FILTER: maps = maps.filter(id__in=authorized) documents = documents.filter(id__in=authorized) facets['map'] = maps.count() facets['document'] = documents.count() if facet_type == 'home': facets['user'] = get_user_model().objects.exclude( username='******').count() facets['group'] = GroupProfile.objects.exclude( access="private").count() facets['layer'] = facets['raster'] + facets['vector'] + facets['remote'] + facets['wms'] return facets
def add_layers_to_map_config(request, map_obj, layer_names, add_base_layers=True): DEFAULT_MAP_CONFIG, DEFAULT_BASE_LAYERS = default_map_config(request) bbox = None layers = [] for layer_name in layer_names: try: layer = _resolve_layer(request, layer_name) except ObjectDoesNotExist: # bad layer, skip continue if not layer.is_published: # invisible layer, skip inclusion continue if not request.user.has_perm('view_resourcebase', obj=layer.get_self_resource()): # invisible layer, skip inclusion continue #layer_bbox = layer.bbox layer_bbox = layer.ll_bbox # assert False, str(layer_bbox) if bbox is None: bbox = list(layer_bbox[0:4]) else: bbox[0] = min(bbox[0], layer_bbox[0]) bbox[1] = max(bbox[1], layer_bbox[1]) bbox[2] = min(bbox[2], layer_bbox[2]) bbox[3] = max(bbox[3], layer_bbox[3]) config = layer.attribute_config() # Add required parameters for a WM layer title = 'No title' if layer.title: title = layer.title config["title"] = title config["queryable"] = True default_srs = getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') config["srs"] = default_srs config["bbox"] = bbox if config["srs"] != 'EPSG:900913' \ else llbbox_to_mercator([float(coord) for coord in bbox]) def decimal_encode(bbox): import decimal _bbox = [] for o in [float(coord) for coord in bbox]: if isinstance(o, decimal.Decimal): o = (str(o) for o in [o]) _bbox.append(o) # Must be in the form : [x0, x1, y0, y1 return [_bbox[0], _bbox[2], _bbox[1], _bbox[3]] config["bbox"] = decimal_encode( bbox_to_projection([float(coord) for coord in layer_bbox[0:4]] + [ layer.srid, ], target_srid=int(default_srs.split(":")[1]))[:4]) access_token = request.session[ 'access_token'] if request and 'access_token' in request.session else None if layer.storeType == "remoteStore": service = layer.service # Probably not a good idea to send the access token to every remote service. # This should never match, so no access token should be # sent to remote services. ogc_server_url = urlparse.urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc service_url = urlparse.urlsplit(service.base_url).netloc if access_token and ogc_server_url == service_url and 'access_token' not in service.base_url: url = '%s?access_token=%s' % (service.base_url, access_token) else: url = service.base_url maplayer = MapLayer(map=map_obj, name=layer.alternate, ows_url=layer.ows_url, layer_params=json.dumps(config), visibility=True, source_params=json.dumps({ "ptype": service.ptype, "remote": True, "url": url, "name": service.name })) else: ogc_server_url = urlparse.urlsplit( ogc_server_settings.PUBLIC_LOCATION).netloc layer_url = urlparse.urlsplit(layer.ows_url).netloc if access_token and ogc_server_url == layer_url and 'access_token' not in layer.ows_url: url = '%s?access_token=%s' % (layer.ows_url, access_token) else: url = layer.ows_url maplayer = MapLayer( map=map_obj, name=layer.alternate, ows_url=url, # use DjangoJSONEncoder to handle Decimal values layer_params=json.dumps(config, cls=DjangoJSONEncoder), visibility=True) layers.append(maplayer) if bbox is not None: minx, maxx, miny, maxy = [float(coord) for coord in bbox] x = (minx + maxx) / 2 y = (miny + maxy) / 2 if getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913') == "EPSG:4326": center = list((x, y)) else: center = list(forward_mercator((x, y))) if center[1] == float('-inf'): center[1] = 0 BBOX_DIFFERENCE_THRESHOLD = 1e-5 # Check if the bbox is invalid valid_x = (maxx - minx)**2 > BBOX_DIFFERENCE_THRESHOLD valid_y = (maxy - miny)**2 > BBOX_DIFFERENCE_THRESHOLD if valid_x: width_zoom = math.log(360 / abs(maxx - minx), 2) else: width_zoom = 15 if valid_y: height_zoom = math.log(360 / abs(maxy - miny), 2) else: height_zoom = 15 map_obj.center_x = center[0] map_obj.center_y = center[1] map_obj.zoom = math.ceil(min(width_zoom, height_zoom)) map_obj.handle_moderated_uploads() if add_base_layers: layers_to_add = DEFAULT_BASE_LAYERS + layers else: layers_to_add = layers config = map_obj.viewer_json(request, *layers_to_add) config['fromLayer'] = True return config