Example #1
0
    def test_add_delete_style(self):
        """Test add new style using qgis_server views."""
        filename = os.path.join(gisdata.GOOD_DATA, 'raster/test_grid.tif')
        layer = file_upload(filename)
        """:type: geonode.layers.models.Layer"""

        self.client.login(username='******', password='******')

        qml_path = self.data_path('test_grid.qml')
        add_style_url = reverse('qgis_server:upload-qml',
                                kwargs={'layername': layer.name})

        with open(qml_path) as file_handle:
            form_data = {
                'name': 'new_style',
                'title': 'New Style',
                'qml': file_handle
            }
            response = self.client.post(add_style_url, data=form_data)

        self.assertEqual(response.status_code, 201)

        actual_list_style = style_list(layer, internal=False)
        if actual_list_style:
            expected_list_style = ['default', 'new_style']
            self.assertEqual(set(expected_list_style),
                             set([style.name for style in actual_list_style]))

        # Test delete request
        delete_style_url = reverse('qgis_server:remove-qml',
                                   kwargs={
                                       'layername': layer.name,
                                       'style_name': 'default'
                                   })

        response = self.client.delete(delete_style_url)
        self.assertEqual(response.status_code, 200)

        actual_list_style = style_list(layer, internal=False)
        if actual_list_style:
            expected_list_style = ['new_style']
            self.assertEqual(set(expected_list_style),
                             set([style.name for style in actual_list_style]))

        # Check new default
        default_style_url = reverse('qgis_server:default-qml',
                                    kwargs={'layername': layer.name})

        response = self.client.get(default_style_url)

        self.assertEqual(response.status_code, 200)
        expected_default_style_retval = {
            'name': 'new_style',
        }
        actual_default_style_retval = json.loads(response.content)

        for key, value in expected_default_style_retval.iteritems():
            self.assertEqual(actual_default_style_retval[key], value)

        layer.delete()
Example #2
0
def legend(request, layername, layertitle=False, style=None):
    """Get the legend from a layer.

    :param layername: The layer name in Geonode.
    :type layername: basestring

    :param layertitle: Add the layer title in the legend. Default to False.
    :type layertitle: bool

    :param style: Layer style to choose
    :type style: str

    :return: The HTTPResponse with a PNG.
    """
    layer = get_object_or_404(Layer, name=layername)
    qgis_layer = get_object_or_404(QGISServerLayer, layer=layer)

    # get default style name
    if not style:
        # generate style cache
        if not qgis_layer.default_style:
            try:
                style_list(layer, internal=False)
            except Exception:
                logger.warning("Failed to fetch styles")

            # refresh values
            qgis_layer.refresh_from_db()
        if qgis_layer.default_style:
            style = qgis_layer.default_style.name

    tiles_directory = QGIS_SERVER_CONFIG['tiles_directory']
    legend_path = QGIS_SERVER_CONFIG['legend_path']
    legend_filename = legend_path % (qgis_layer.qgis_layer_name, style)
    # GOOD -- Verify with normalised version of path
    legend_filename = os.path.normpath(legend_filename)
    if not legend_filename.startswith(tiles_directory):
        return HttpResponseServerError()

    if not os.path.exists(legend_filename):
        if not os.path.exists(os.path.dirname(legend_filename)):
            os.makedirs(os.path.dirname(legend_filename))
        url = legend_url(layer, layertitle, style=style, internal=True)
        result = cache_request.apply_async((url, legend_filename))

        # Attempt to run task synchronously
        if not result.get():
            # If not succeded, provides error message.
            return HttpResponseServerError('Failed to fetch legend.')

    if image_format(legend_filename) != 'png':
        logger.error('%s is not valid PNG.' % legend_filename)
        os.remove(legend_filename)

    if not os.path.exists(legend_filename):
        return HttpResponse('The legend could not be found.', status=409)

    with open(legend_filename, 'rb') as f:
        return HttpResponse(f.read(), content_type='image/png')
Example #3
0
def legend(request, layername, layertitle=False, style=None):
    """Get the legend from a layer.

    :param layername: The layer name in Geonode.
    :type layername: basestring

    :param layertitle: Add the layer title in the legend. Default to False.
    :type layertitle: bool

    :param style: Layer style to choose
    :type style: str

    :return: The HTTPResponse with a PNG.
    """
    layer = get_object_or_404(Layer, name=layername)
    qgis_layer = get_object_or_404(QGISServerLayer, layer=layer)

    # get default style name
    if not style:
        # generate style cache
        if not qgis_layer.default_style:
            try:
                style_list(layer, internal=False)
            except BaseException:
                print 'Failed to fetch styles'

            # refresh values
            qgis_layer.refresh_from_db()
        if qgis_layer.default_style:
            style = qgis_layer.default_style.name

    legend_path = QGIS_SERVER_CONFIG['legend_path']
    legend_filename = legend_path % (qgis_layer.qgis_layer_name, style)

    if not os.path.exists(legend_filename):

        if not os.path.exists(os.path.dirname(legend_filename)):
            os.makedirs(os.path.dirname(legend_filename))

        url = legend_url(layer, layertitle, style=style, internal=True)

        result = cache_request.delay(url, legend_filename)

        # Attempt to run task synchronously
        if not result.get():
            # If not succeded, provides error message.
            return HttpResponseServerError('Failed to fetch legend.')

    if image_format(legend_filename) != 'png':
        logger.error('%s is not valid PNG.' % legend_filename)
        os.remove(legend_filename)

    if not os.path.exists(legend_filename):
        return HttpResponse('The legend could not be found.', status=409)

    with open(legend_filename, 'rb') as f:
        return HttpResponse(f.read(), content_type='image/png')
Example #4
0
    def test_list_style(self):
        """Test querying list of styles from QGIS Server."""
        filename = os.path.join(gisdata.GOOD_DATA, 'raster/test_grid.tif')
        layer = file_upload(filename)
        """:type: geonode.layers.models.Layer"""

        actual_list_style = style_list(layer, internal=False)
        expected_list_style = ['default']

        # There will be a default style
        self.assertEqual(
            set(expected_list_style),
            set([style.name for style in actual_list_style]))

        style_list_url = reverse(
            'qgis_server:download-qml',
            kwargs={
                'layername': layer.name
            })
        response = self.client.get(style_list_url)
        self.assertEqual(response.status_code, 200)
        actual_list_style = json.loads(response.content)

        # There will be a default style
        self.assertEqual(
            set(expected_list_style),
            set([style['name'] for style in actual_list_style]))

        layer.delete()
Example #5
0
    def test_list_style(self):
        """Test querying list of styles from QGIS Server."""
        filename = os.path.join(gisdata.GOOD_DATA, 'raster/test_grid.tif')
        layer = file_upload(filename)
        """:type: geonode.layers.models.Layer"""

        actual_list_style = style_list(layer, internal=False)
        expected_list_style = ['default']

        # There will be a default style
        if actual_list_style:
            self.assertEqual(
                set(expected_list_style),
                set([style.name for style in actual_list_style]))

            style_list_url = reverse(
                'qgis_server:download-qml',
                kwargs={
                    'layername': layer.name
                })
            response = self.client.get(style_list_url)
            self.assertEqual(response.status_code, 200)
            content = ensure_string(response.content)
            if isinstance(content, bytes):
                content = content.decode('UTF-8')
            actual_list_style = json.loads(content)

            # There will be a default style
            self.assertEqual(
                set(expected_list_style),
                set([style['name'] for style in actual_list_style]))

        layer.delete()
    def handle(self, *args, **options):
        layers = Layer.objects.all()

        for l in layers:
            try:
                l.qgis_layer
            except Exception:
                print("Layer {} has no associated qgis_layer".format(l.name))
                continue

            if l.qgis_layer:
                print("Fetching styles for layer %s".format(l.name))

                try:
                    styles = style_list(l, internal=False)
                except Exception:
                    print("Failed to fetch styles")
                    continue

                print("Successfully fetch %d style(s)\n".format(len(styles)))
Example #7
0
    def handle(self, *args, **options):
        layers = Layer.objects.all()

        for l in layers:
            try:
                l.qgis_layer
            except:
                print 'Layer %s has no associated qgis_layer' % l.name
                continue

            if l.qgis_layer:
                print 'Fetching styles for layer %s' % l.name

                try:
                    styles = style_list(l, internal=False)
                except:
                    print 'Failed to fetch styles'
                    continue

                print 'Successfully fetch %d style(s)' % len(styles)
                print ''
Example #8
0
def qml_style(request, layername, style_name=None):
    """Update/Retrieve QML style of a given QGIS Layer.

    :param layername: The layer name in Geonode.
    :type layername: basestring

    :param style_name: The style name recognized by QGIS Server
    :type style_name: str
    """
    layer = get_object_or_404(Layer, name=layername)

    if request.method == 'GET':

        # Request QML from QGIS server
        if not style_name:
            # If no style name provided, then it is a List request
            styles_obj = None
            try:
                styles_obj = style_list(layer, internal=False)
            except BaseException:
                print 'Failed to fetch styles'

            styles_dict = []
            if styles_obj:
                styles_dict = [model_to_dict(s) for s in styles_obj]

                # If no style returned by GetCapabilities, this is a bug in QGIS
                # Attempt to generate default style name
                if not styles_dict:
                    style_url = style_get_url(layer, 'default')
                    response = requests.get(style_url)
                    if response.status_code == 200:
                        style_url = style_add_url(layer, 'default')
                        with open(layer.qgis_layer.qml_path, 'w') as f:
                            f.write(response.content)
                        response = requests.get(style_url)
                        if response.status_code == 200:
                            styles_obj = style_list(layer, internal=False)
                            styles_dict = [model_to_dict(s) for s in styles_obj]

            response = HttpResponse(
                json.dumps(styles_dict), content_type='application/json')
            return response

        # Return XML file of the style
        style_url = style_get_url(layer, style_name, internal=False)
        response = requests.get(style_url)
        if response.status_code == 200:
            response = HttpResponse(
                response.content, content_type='text/xml')
            response[
                'Content-Disposition'] = 'attachment; filename=%s.qml' % (
                style_name, )
        else:
            response = HttpResponse(
                response.content, status=response.status_code)
        return response
    elif request.method == 'POST':

        # For people who uses API request
        if not request.user.has_perm(
                'change_resourcebase', layer.get_self_resource()):
            return HttpResponse(
                'User does not have permission to change QML style.',
                status=403)

        # Request about adding new QML style

        form = QGISLayerStyleUploadForm(request.POST, request.FILES)

        if not form.is_valid():
            return TemplateResponse(
                request,
                'qgis_server/forms/qml_style.html',
                {
                    'resource': layer,
                    'style_upload_form': form
                },
                status=400).render()

        try:
            uploaded_qml = request.FILES['qml']

            # update qml in uploaded media folder
            # check upload session, is qml file exists?
            layerfile_set = layer.upload_session.layerfile_set
            try:
                qml_layer_file = layerfile_set.get(name='qml')
                # if it is exists, we need to delete it, because it won't be
                # managed by geonode
                qml_layer_file.delete()
            except LayerFile.DoesNotExist:
                pass

            # update qml in QGIS Layer folder
            content = uploaded_qml.read()
            qgis_layer = get_object_or_404(QGISServerLayer, layer=layer)

            with open(qgis_layer.qml_path, mode='w') as f:
                f.write(content)

            # construct URL to post new QML
            style_name = request.POST['name']
            style_title = request.POST['title']
            if not style_name:
                # Assign default name
                name_format = 'style_%Y%m%d%H%M%S'
                current_time = datetime.datetime.utcnow()
                style_name = current_time.strftime(name_format)

            # Add new style
            style_url = style_add_url(layer, style_name)

            response = requests.get(style_url)

            if not (response.status_code == 200 and response.content == 'OK'):
                try:
                    style_list(layer, internal=False)
                except BaseException:
                    print 'Failed to fetch styles'

                return TemplateResponse(
                    request,
                    'qgis_server/forms/qml_style.html',
                    {
                        'resource': layer,
                        'style_upload_form': QGISLayerStyleUploadForm(),
                        'alert': True,
                        'alert_message': response.content,
                        'alert_class': 'alert-danger'
                    },
                    status=response.status_code).render()

            # We succeeded on adding new style

            # Refresh style models
            try:
                style_list(layer, internal=False)
                qgis_style = layer.qgis_layer.styles.get(name=style_name)
                qgis_style.title = style_title
                qgis_style.save()

                alert_message = 'Successfully add style %s' % style_name
            except BaseException:
                alert_message = 'Failed to fetch styles'

            return TemplateResponse(
                request,
                'qgis_server/forms/qml_style.html',
                {
                    'resource': layer,
                    'style_upload_form': form,
                    'alert': True,
                    'alert_class': 'alert-success',
                    'alert_message': alert_message
                },
                status=201).render()

        except Exception as e:
            logger.exception(e)
            return HttpResponseServerError()
    elif request.method == 'DELETE':
        # Request to delete particular QML Style

        if not style_name:
            # Style name should exists
            return HttpResponseBadRequest('Style name not provided.')

        # Handle removing tile-style cache
        try:
            style = layer.qgis_layer.styles.get(name=style_name)
            shutil.rmtree(style.style_tile_cache_path)
        except BaseException:
            pass

        style_url = style_remove_url(layer, style_name)

        response = requests.get(style_url)

        if not (response.status_code == 200 and response.content == 'OK'):
            alert_message = response.content
            if 'NAME is NOT an existing style.' in response.content:
                alert_message = '%s is not an existing style' % style_name
            try:
                style_list(layer, internal=False)
            except BaseException:
                print 'Failed to fetch styles'

            return TemplateResponse(
                request,
                'qgis_server/forms/qml_style.html',
                {
                    'resource': layer,
                    'style_upload_form': QGISLayerStyleUploadForm(),
                    'alert': True,
                    'alert_message': alert_message,
                    'alert_class': 'alert-danger'
                },
                status=response.status_code).render()

        # Successfully removed styles
        # Handle when default style is deleted.
        # Will be handled by style_list method
        try:
            style_list(layer, internal=False)

            alert_message = 'Successfully deleted style %s' % style_name
        except BaseException:
            alert_message = 'Failed to fetch styles'

        return TemplateResponse(
            request,
            'qgis_server/forms/qml_style.html',
            {
                'resource': layer,
                'style_upload_form': QGISLayerStyleUploadForm(),
                'alert': True,
                'alert_message': alert_message,
                'alert_class': 'alert-success'
            },
            status=200).render()

    return HttpResponseBadRequest()
Example #9
0
def tile(request, layername, z, x, y, style=None):
    """Get the tile from a layer.

    :param layername: The layer name in Geonode.
    :type layername: basestring

    :param z: TMS coordinate, zoom parameter
    :type z: int, str

    :param x: TMS coordinate, longitude parameter
    :type x: int, str

    :param y: TMS coordinate, latitude parameter
    :type y: int, str

    :param style: Layer style to choose
    :type style: str

    :return: The HTTPResponse with a PNG.
    """
    x = int(x)
    y = int(y)
    z = int(z)

    layer = get_object_or_404(Layer, name=layername)
    qgis_layer = get_object_or_404(QGISServerLayer, layer=layer)

    # get default style name
    if not style:
        # generate style cache
        if not qgis_layer.default_style:
            try:
                style_list(layer, internal=False)
            except BaseException:
                print 'Failed to fetch styles'

            # refresh values
            qgis_layer.refresh_from_db()
        if qgis_layer.default_style:
            style = qgis_layer.default_style.name

    tile_path = QGIS_SERVER_CONFIG['tile_path']
    tile_filename = tile_path % (qgis_layer.qgis_layer_name, style, z, x, y)

    if not os.path.exists(tile_filename):

        if not os.path.exists(os.path.dirname(tile_filename)):
            os.makedirs(os.path.dirname(tile_filename))

        # Use internal url
        url = tile_url(layer, z, x, y, style=style, internal=True)

        result = cache_request.delay(url, tile_filename)

        # Attempt to run task synchronously
        if not result.get():
            # If not succeded, provides error message.
            return HttpResponseServerError('Failed to fetch tile.')

    if image_format(tile_filename) != 'png':
        logger.error('%s is not valid PNG.' % tile_filename)
        os.remove(tile_filename)

    if not os.path.exists(tile_filename):
        return HttpResponse('The tile could not be found.', status=409)

    with open(tile_filename, 'rb') as f:
        return HttpResponse(f.read(), content_type='image/png')
Example #10
0
def qgis_server_post_save(instance, sender, **kwargs):
    """Save keywords to QGIS Server.

    The way keywords are implemented requires the layer to be saved to the
    database before accessing them.

    This hook also creates QGIS Project. Which is essentials for QGIS Server.
    There are also several Geonode Links generated, like thumbnail and legends

    :param instance: geonode Layer
    :type instance: Layer

    :param sender: geonode Layer type
    :type sender: type(Layer)
    """
    if not sender == Layer:
        return
    # TODO
    # 1. Create or update associated QGISServerLayer [Done]
    # 2. Create Link for the tile and legend.
    logger.debug('QGIS Server Post Save')

    # copy layer to QGIS Layer Directory
    try:
        geonode_layer_path = instance.get_base_file()[0].file.path
    except AttributeError:
        logger.debug('Layer does not have base file')
        return

    qgis_layer, created = QGISServerLayer.objects.get_or_create(
        layer=instance)
    logger.debug('Geonode Layer Path %s' % geonode_layer_path)

    base_filename, original_ext = os.path.splitext(geonode_layer_path)
    extensions = QGISServerLayer.accepted_format

    is_shapefile = False

    for ext in extensions:
        if os.path.exists(base_filename + '.' + ext):
            is_shapefile = is_shapefile or ext == 'shp'
            try:
                if created:
                    # Assuming different layer has different filename because
                    # geonode rename it
                    shutil.copy2(
                        base_filename + '.' + ext,
                        QGIS_layer_directory
                    )
                    logger.debug('Create new basefile')
                else:
                    # If there is already a file, replace the old one
                    qgis_layer_base_filename = qgis_layer.qgis_layer_path_prefix
                    shutil.copy2(
                        base_filename + '.' + ext,
                        qgis_layer_base_filename + '.' + ext
                    )
                    logger.debug('Overwrite existing basefile')
                logger.debug(
                    'Copying %s' % base_filename + '.' + ext + ' Success')
                logger.debug('Into %s' % QGIS_layer_directory)
            except IOError as e:
                logger.debug(
                    'Copying %s' % base_filename + '.' + ext + ' FAILED ' + e)
    if created:
        # Only set when creating new QGISServerLayer Object
        geonode_filename = os.path.basename(geonode_layer_path)
        basename = os.path.splitext(geonode_filename)[0]
        qgis_layer.base_layer_path = os.path.join(
            QGIS_layer_directory,
            basename + original_ext  # Already with dot
        )
    qgis_layer.save()

    # Set layer crs
    try:
        if is_shapefile:
            dataset = ogr.Open(geonode_layer_path)
            layer = dataset.GetLayer()
            spatial_ref = layer.GetSpatialRef()
            srid = spatial_ref.GetAuthorityCode(None)
            if srid:
                instance.srid = srid
        else:
            dataset = gdal.Open(geonode_layer_path)
            prj = dataset.GetProjection()
            srs = osr.SpatialReference(wkt=prj)
            srid = srs.GetAuthorityCode(None)
            if srid:
                instance.srid = srid
    except Exception as e:
        logger.debug("Can't retrieve projection: {layer}".format(
            layer=geonode_layer_path))
        logger.exception(e)

    # base url for geonode
    base_url = settings.SITEURL

    # Set Link for Download Raw in Zip File
    zip_download_url = reverse(
        'qgis_server:download-zip', kwargs={'layername': instance.name})
    zip_download_url = urljoin(base_url, zip_download_url)
    logger.debug('zip_download_url: %s' % zip_download_url)
    if is_shapefile:
        link_name = 'Zipped Shapefile'
        link_mime = 'SHAPE-ZIP'
    else:
        link_name = 'Zipped All Files'
        link_mime = 'ZIP'

    # Zip file
    Link.objects.update_or_create(
        resource=instance.resourcebase_ptr,
        name=link_name,
        defaults=dict(
            extension='zip',
            mime=link_mime,
            url=zip_download_url,
            link_type='data'
        )
    )

    # WMS link layer workspace
    ogc_wms_url = urljoin(
        settings.SITEURL,
        reverse(
            'qgis_server:layer-request', kwargs={'layername': instance.name}))
    ogc_wms_name = 'OGC WMS: %s Service' % instance.workspace
    ogc_wms_link_type = 'OGC:WMS'
    Link.objects.update_or_create(
        resource=instance.resourcebase_ptr,
        name=ogc_wms_name,
        link_type=ogc_wms_link_type,
        defaults=dict(
            extension='html',
            url=ogc_wms_url,
            mime='text/html',
            link_type=ogc_wms_link_type
        )
    )

    # QGS link layer workspace
    ogc_qgs_url = urljoin(
        base_url,
        reverse(
            'qgis_server:download-qgs',
            kwargs={'layername': instance.name}))
    logger.debug('qgs_download_url: %s' % ogc_qgs_url)
    link_name = 'QGIS project file (.qgs)'
    link_mime = 'application/xml'
    Link.objects.update_or_create(
        resource=instance.resourcebase_ptr,
        name=link_name,
        defaults=dict(
            extension='qgs',
            mime=link_mime,
            url=ogc_qgs_url,
            link_type='data'
        )
    )

    if instance.is_vector():
        # WFS link layer workspace
        ogc_wfs_url = urljoin(
            settings.SITEURL,
            reverse(
                'qgis_server:layer-request',
                kwargs={'layername': instance.name}))
        ogc_wfs_name = 'OGC WFS: %s Service' % instance.workspace
        ogc_wfs_link_type = 'OGC:WFS'
        Link.objects.update_or_create(
            resource=instance.resourcebase_ptr,
            name=ogc_wfs_name,
            link_type=ogc_wfs_link_type,
            defaults=dict(
                extension='html',
                url=ogc_wfs_url,
                mime='text/html',
                link_type=ogc_wfs_link_type
            )
        )

    # QLR link layer workspace
    ogc_qlr_url = urljoin(
        base_url,
        reverse(
            'qgis_server:download-qlr',
            kwargs={'layername': instance.name}))
    logger.debug('qlr_download_url: %s' % ogc_qlr_url)
    link_name = 'QGIS layer file (.qlr)'
    link_mime = 'application/xml'
    Link.objects.update_or_create(
        resource=instance.resourcebase_ptr,
        name=link_name,
        defaults=dict(
            extension='qlr',
            mime=link_mime,
            url=ogc_qlr_url,
            link_type='data'
        )
    )

    # if layer has overwrite attribute, then it probably comes from
    # importlayers management command and needs to be overwritten
    overwrite = getattr(instance, 'overwrite', False)

    # Create the QGIS Project
    response = create_qgis_project(
        instance, qgis_layer.qgis_project_path, overwrite=overwrite,
        internal=True)

    logger.debug('Creating the QGIS Project : %s' % response.url)
    if response.content != 'OK':
        logger.debug('Result : %s' % response.content)

    # Generate style model cache
    style_list(instance, internal=False)

    # Remove QML file if necessary
    try:
        qml_file = instance.upload_session.layerfile_set.get(name='qml')
        if not os.path.exists(qml_file.file.path):
            qml_file.delete()
    except LayerFile.DoesNotExist:
        pass

    Link.objects.update_or_create(
        resource=instance.resourcebase_ptr,
        name="Tiles",
        defaults=dict(
            url=tile_url_format(instance.name),
            extension='tiles',
            mime='image/png',
            link_type='image'
        )
    )

    if original_ext.split('.')[-1] in QGISServerLayer.geotiff_format:
        # geotiff link
        geotiff_url = reverse(
            'qgis_server:geotiff', kwargs={'layername': instance.name})
        geotiff_url = urljoin(base_url, geotiff_url)
        logger.debug('geotif_url: %s' % geotiff_url)

        Link.objects.update_or_create(
            resource=instance.resourcebase_ptr,
            name="GeoTIFF",
            defaults=dict(
                extension=original_ext.split('.')[-1],
                url=geotiff_url,
                mime='image/tiff',
                link_type='image'
            )
        )

    # Create legend link
    legend_url = reverse(
        'qgis_server:legend',
        kwargs={'layername': instance.name}
    )
    legend_url = urljoin(base_url, legend_url)
    Link.objects.update_or_create(
        resource=instance.resourcebase_ptr,
        name='Legend',
        defaults=dict(
            extension='png',
            url=legend_url,
            mime='image/png',
            link_type='image',
        )
    )

    # Create thumbnail
    create_qgis_server_thumbnail.delay(
        instance, overwrite=overwrite)

    # Attributes
    set_attributes(instance)

    # Update xml file

    # Read metadata from layer that InaSAFE use.
    # Some are not found: organisation, email, url
    try:
        new_values = {
            'date': instance.date.isoformat(),
            'abstract': instance.abstract,
            'title': instance.title,
            'license': instance.license_verbose,
        }
    except (TypeError, AttributeError):
        new_values = {}
        pass

    # Get the path of the metadata file
    basename, _ = os.path.splitext(qgis_layer.base_layer_path)
    xml_file_path = basename + '.xml'
    if os.path.exists(xml_file_path):
        try:
            update_xml(xml_file_path, new_values)
        except (TypeError, AttributeError):
            pass

    # Also update xml in QGIS Server
    xml_file_path = qgis_layer.qgis_layer_path_prefix + '.xml'
    if os.path.exists(xml_file_path):
        try:
            update_xml(xml_file_path, new_values)
        except (TypeError, AttributeError):
            pass

    # Remove existing tile caches if overwrite
    if overwrite:
        tiles_directory = settings.QGIS_SERVER_CONFIG['tiles_directory']
        basename, _ = os.path.splitext(qgis_layer.base_layer_path)
        basename = os.path.basename(basename)
        tiles_cache_path = os.path.join(tiles_directory, basename)
        try:
            shutil.rmtree(tiles_cache_path)
        except OSError:
            # The path doesn't exists yet
            pass
Example #11
0
    def test_style_management_url(self):
        """Test QGIS Server style management url construction."""
        filename = os.path.join(gisdata.GOOD_DATA, 'raster/test_grid.tif')
        uploaded = file_upload(filename)

        # Get default style
        # There will always be a default style when uploading a layer
        style_url = style_get_url(uploaded, 'default', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.headers.get('Content-Type'), 'text/xml')

        # it has to contains qgis tags
        style_xml = dlxml.fromstring(response.content)
        self.assertTrue('qgis' in style_xml.tag)

        # Add new style
        # change default style slightly
        self.assertTrue('WhiteToBlack' not in response.content)
        self.assertTrue('BlackToWhite' in response.content)
        new_style_xml = dlxml.fromstring(
            response.content.replace('BlackToWhite', 'WhiteToBlack'))
        new_xml_content = etree.tostring(new_style_xml, pretty_print=True)

        # save it to qml file, accessible by qgis server
        qgis_layer = QGISServerLayer.objects.get(layer=uploaded)
        with open(qgis_layer.qml_path, mode='w') as f:
            f.write(new_xml_content)

        style_url = style_add_url(uploaded, 'new_style', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, 'OK')

        # Get style list
        qml_styles = style_list(uploaded, internal=False)
        if qml_styles:
            expected_style_names = ['default', 'new_style']
            actual_style_names = [s.name for s in qml_styles]
            self.assertEqual(set(expected_style_names),
                             set(actual_style_names))

        # Get new style
        style_url = style_get_url(uploaded, 'new_style', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.headers.get('Content-Type'), 'text/xml')
        self.assertTrue('WhiteToBlack' in response.content)

        # Set default style
        style_url = style_set_default_url(uploaded, 'new_style', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, 'OK')

        # Remove style
        style_url = style_remove_url(uploaded, 'new_style', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, 'OK')

        # Cleanup
        uploaded.delete()
Example #12
0
    def test_add_delete_style(self):
        """Test add new style using qgis_server views."""
        filename = os.path.join(gisdata.GOOD_DATA, 'raster/test_grid.tif')
        layer = file_upload(filename)
        """:type: geonode.layers.models.Layer"""

        self.client.login(username='******', password='******')

        qml_path = self.data_path('test_grid.qml')
        add_style_url = reverse(
            'qgis_server:upload-qml',
            kwargs={
                'layername': layer.name})

        with open(qml_path) as file_handle:
            form_data = {
                'name': 'new_style',
                'title': 'New Style',
                'qml': file_handle
            }
            response = self.client.post(
                add_style_url,
                data=form_data)

        self.assertEqual(response.status_code, 201)

        actual_list_style = style_list(layer, internal=False)

        expected_list_style = ['default', 'new_style']

        self.assertEqual(
            set(expected_list_style),
            set([style.name for style in actual_list_style]))

        # Test delete request
        delete_style_url = reverse(
            'qgis_server:remove-qml',
            kwargs={
                'layername': layer.name,
                'style_name': 'default'})

        response = self.client.delete(delete_style_url)
        self.assertEqual(response.status_code, 200)

        actual_list_style = style_list(layer, internal=False)

        expected_list_style = ['new_style']

        self.assertEqual(
            set(expected_list_style),
            set([style.name for style in actual_list_style]))

        # Check new default
        default_style_url = reverse(
            'qgis_server:default-qml',
            kwargs={
                'layername': layer.name})

        response = self.client.get(default_style_url)

        self.assertEqual(response.status_code, 200)
        expected_default_style_retval = {
            'name': 'new_style',
        }
        actual_default_style_retval = json.loads(response.content)

        for key, value in expected_default_style_retval.iteritems():
            self.assertEqual(actual_default_style_retval[key], value)

        layer.delete()
Example #13
0
    def test_style_management_url(self):
        """Test QGIS Server style management url construction."""
        filename = os.path.join(gisdata.GOOD_DATA, 'raster/test_grid.tif')
        uploaded = file_upload(filename)

        # Get default style
        # There will always be a default style when uploading a layer
        style_url = style_get_url(uploaded, 'default', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.headers.get('Content-Type'), 'text/xml')

        # it has to contains qgis tags
        style_xml = etree.fromstring(response.content)
        self.assertTrue('qgis' in style_xml.tag)

        # Add new style
        # change default style slightly
        self.assertTrue('WhiteToBlack' not in response.content)
        self.assertTrue('BlackToWhite' in response.content)
        new_style_xml = etree.fromstring(
            response.content.replace('BlackToWhite', 'WhiteToBlack'))
        new_xml_content = etree.tostring(new_style_xml, pretty_print=True)

        # save it to qml file, accessible by qgis server
        qgis_layer = QGISServerLayer.objects.get(layer=uploaded)
        with open(qgis_layer.qml_path, mode='w') as f:
            f.write(new_xml_content)

        style_url = style_add_url(uploaded, 'new_style', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, 'OK')

        # Get style list
        qml_styles = style_list(uploaded, internal=False)
        expected_style_names = ['default', 'new_style']
        actual_style_names = [s.name for s in qml_styles]
        self.assertEqual(set(expected_style_names), set(actual_style_names))

        # Get new style
        style_url = style_get_url(uploaded, 'new_style', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.headers.get('Content-Type'), 'text/xml')
        self.assertTrue('WhiteToBlack' in response.content)

        # Set default style
        style_url = style_set_default_url(
            uploaded, 'new_style', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, 'OK')

        # Remove style
        style_url = style_remove_url(uploaded, 'new_style', internal=True)

        response = requests.get(style_url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, 'OK')

        # Cleanup
        uploaded.delete()