Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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
    bbox = [float(coord) for coord in list(layer_bbox[0:4])]
    if hasattr(layer, 'srid'):
        config['crs'] = {'type': 'name', 'properties': layer.srid}
    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.storeType == "remoteStore":
        service = layer.service
        source_params = {
            "ptype": service.ptype,
            "remote": True,
            "url": service.base_url,
            "name": service.name
        }
        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(
        projection=getattr(settings, 'DEFAULT_MAP_CRS', 'EPSG:900913'))

    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 'geonode.geoserver' in settings.INSTALLED_APPS:
        from geonode.geoserver.views import get_capabilities
        if layer.has_time:
            workspace, layername = layer.alternate.split(":")
            # 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(
                            "Capability/Layer/Layer[Name='%s']/Extent" %
                        (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

    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,
    }

    if '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.user, access_token,
                            *(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:900913')

    # 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(
            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 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:
        print "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:
        print "Possible error with OWSLib. Turning all available properties to string"

    # 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,
                            RequestContext(request, context_dict))