Esempio n. 1
0
def geoserver_post_save(instance, sender, created, **kwargs):
    from geonode.messaging import producer
    # this is attached to various models, (ResourceBase, Document)
    # so we should select what will be handled here
    if isinstance(instance, Layer):
        instance_dict = model_to_dict(instance)
        payload = json_serializer_producer(instance_dict)
        producer.geoserver_upload_layer(payload)

        if getattr(settings, 'DELAYED_SECURITY_SIGNALS', False):
            instance.set_dirty_state()

        if instance.storeType != 'remoteStore' and created:
            logger.info("... Creating Default Resource Links for Layer [%s]" %
                        (instance.alternate))
            try:
                set_resource_default_links(instance, sender, prune=True)
            except BaseException:
                from django.db import connection
                connection._rollback()
                logger.warn(
                    "Failure Creating Default Resource Links for Layer [%s]" %
                    (instance.alternate))
            logger.info("... Creating Thumbnail for Layer [%s]" %
                        (instance.alternate))
            try:
                create_gs_thumbnail(instance, overwrite=True, check_bbox=True)
            except BaseException:
                logger.warn("Failure Creating Thumbnail for Layer [%s]" %
                            (instance.alternate))
    def handle(self, *args, **options):
        ignore_errors = options.get('ignore_errors')
        filter = options.get('filter')
        if not options.get('username'):
            username = None
        else:
            username = options.get('username')

        all_layers = Layer.objects.all().order_by('name')
        if filter:
            all_layers = all_layers.filter(name__icontains=filter)
        if username:
            all_layers = all_layers.filter(owner__username=username)

        for index, layer in enumerate(all_layers):
            print "[%s / %s] Updating Layer [%s] ..." % (
                (index + 1), len(all_layers), layer.name)
            try:
                # recalculate the layer statistics
                set_attributes(layer, overwrite=True)

                # refresh metadata links
                set_resource_default_links(layer, layer, prune=False)

                # refresh catalogue metadata records
                catalogue_post_save(instance=layer, sender=layer.__class__)
            except BaseException as e:
                # import traceback
                # traceback.print_exc()
                if ignore_errors:
                    print "[ERROR] Layer [%s] couldn't be updated" % (
                        layer.name)
                else:
                    raise e
Esempio n. 3
0
    def handle(self, *args, **options):
        ignore_errors = options.get('ignore_errors')
        filter = options.get('filter')
        if not options.get('username'):
            username = None
        else:
            username = options.get('username')

        all_layers = Layer.objects.all().order_by('name')
        if filter:
            all_layers = all_layers.filter(name__icontains=filter)
        if username:
            all_layers = all_layers.filter(owner__username=username)

        for index, layer in enumerate(all_layers):
            print "[%s / %s] Updating Layer [%s] ..." % ((index + 1), len(all_layers), layer.name)
            try:
                # recalculate the layer statistics
                set_attributes(layer, overwrite=True)

                # refresh metadata links
                set_resource_default_links(layer, layer, prune=True)

                # refresh catalogue metadata records
                catalogue_post_save(instance=layer, sender=layer.__class__)
            except BaseException as e:
                # import traceback
                # traceback.print_exc()
                if ignore_errors:
                    print "[ERROR] Layer [%s] couldn't be updated" % (layer.name)
                else:
                    raise e
    def handle(self, *args, **options):
        ignore_errors = options.get('ignore_errors')
        remove_duplicates = options.get('remove_duplicates')
        filter = options.get('filter')
        if not options.get('username'):
            username = None
        else:
            username = options.get('username')

        all_layers = Layer.objects.all().order_by('name')
        if filter:
            all_layers = all_layers.filter(name__icontains=filter)
        if username:
            all_layers = all_layers.filter(owner__username=username)

        for index, layer in enumerate(all_layers):
            print "[%s / %s] Updating Layer [%s] ..." % (
                (index + 1), len(all_layers), layer.name)
            try:
                # recalculate the layer statistics
                set_attributes(layer, overwrite=True)

                # refresh metadata links
                set_resource_default_links(layer, layer, prune=False)

                # refresh catalogue metadata records
                catalogue_post_save(instance=layer, sender=layer.__class__)

                if remove_duplicates:
                    # remove duplicates
                    for _n in _names:
                        _links = Link.objects.filter(resource__id=layer.id,
                                                     name=_n)
                        while _links.count() > 1:
                            _links.last().delete()
                            print '.',
                    # fixup Legend links
                    legend_url_template = ogc_server_settings.PUBLIC_LOCATION + \
                        'ows?service=WMS&request=GetLegendGraphic&format=image/png&WIDTH=20&HEIGHT=20&LAYER=' + \
                        '{alternate}&STYLE={style_name}' + \
                        '&legend_options=fontAntiAliasing:true;fontSize:12;forceLabels:on'
                    if layer.default_style and not layer.get_legend_url(
                            style_name=layer.default_style.name):
                        Link.objects.update_or_create(
                            resource=layer.resourcebase_ptr,
                            name='Legend',
                            extension='png',
                            url=legend_url_template.format(
                                alternate=layer.alternate,
                                style_name=layer.default_style.name),
                            mime='image/png',
                            link_type='image')
            except BaseException as e:
                import traceback
                traceback.print_exc()
                if ignore_errors:
                    print "[ERROR] Layer [%s] couldn't be updated" % (
                        layer.name)
                else:
                    raise e
Esempio n. 5
0
    def handle(self, *args, **options):
        ignore_errors = options.get('ignore_errors')
        remove_duplicates = options.get('remove_duplicates')
        prune = options.get('prune')
        set_uuid = ast.literal_eval(options.get('set_uuid', 'False'))
        set_attrib = ast.literal_eval(options.get('set_attrib', 'True'))
        set_links = ast.literal_eval(options.get('set_links', 'True'))

        delete_orphaned_thumbnails = options.get('delete_orphaned_thumbnails')
        filter = options.get('filter')
        if not options.get('username'):
            username = None
        else:
            username = options.get('username')

        all_layers = Layer.objects.all().order_by('name')
        if filter:
            all_layers = all_layers.filter(name__icontains=filter)
        if username:
            all_layers = all_layers.filter(owner__username=username)

        for index, layer in enumerate(all_layers):
            print(f"[{(index + 1)} / {len(all_layers)}] Updating Layer [{layer.name}] ...")
            try:
                # recalculate the layer statistics
                if set_attrib:
                    set_attributes(layer, overwrite=True)

                if set_uuid and hasattr(settings, 'LAYER_UUID_HANDLER') and settings.LAYER_UUID_HANDLER != '':
                    from geonode.layers.utils import get_uuid_handler
                    uuid = get_uuid_handler()(layer).create_uuid()
                    la = Layer.objects.filter(resourcebase_ptr=layer.resourcebase_ptr)
                    la.update(uuid=uuid)
                    layer.refresh_from_db()
                # refresh metadata links

                if set_links:
                    set_resource_default_links(layer, layer, prune=prune)

                # refresh catalogue metadata records
                catalogue_post_save(instance=layer, sender=layer.__class__)

                # remove duplicates
                if remove_duplicates:
                    remove_duplicate_links(layer)
            except Exception as e:
                import traceback
                traceback.print_exc()
                if ignore_errors:
                    logger.error(f"[ERROR] Layer [{layer.name}] couldn't be updated")
                else:
                    raise e

        # delete orphaned thumbs
        if delete_orphaned_thumbnails:
            delete_orphaned_thumbs()
    def handle(self, *args, **options):
        ignore_errors = options.get('ignore_errors')
        remove_duplicates = options.get('remove_duplicates')
        prune = options.get('prune')
        delete_orphaned_thumbnails = options.get('delete_orphaned_thumbnails')
        filter = options.get('filter')
        if not options.get('username'):
            username = None
        else:
            username = options.get('username')

        all_layers = Layer.objects.all().order_by('name')
        if filter:
            all_layers = all_layers.filter(name__icontains=filter)
        if username:
            all_layers = all_layers.filter(owner__username=username)

        for index, layer in enumerate(all_layers):
            print(
                f"[{(index + 1)} / {len(all_layers)}] Updating Layer [{layer.name}] ..."
            )
            try:
                # recalculate the layer statistics
                set_attributes(layer, overwrite=True)

                # refresh metadata links
                set_resource_default_links(layer, layer, prune=prune)

                # refresh catalogue metadata records
                catalogue_post_save(instance=layer, sender=layer.__class__)

                # remove duplicates
                if remove_duplicates:
                    remove_duplicate_links(layer)
            except Exception as e:
                import traceback
                traceback.print_exc()
                if ignore_errors:
                    logger.error(
                        f"[ERROR] Layer [{layer.name}] couldn't be updated")
                else:
                    raise e

        # delete orphaned thumbs
        if delete_orphaned_thumbnails:
            delete_orphaned_thumbs()
Esempio n. 7
0
def set_resource_links(*args, **kwargs):

    from geonode.utils import set_resource_default_links
    from geonode.catalogue.models import catalogue_post_save
    from geonode.layers.models import Layer

    if settings.UPDATE_RESOURCE_LINKS_AT_MIGRATE:
        _all_layers = Layer.objects.all()
        for index, layer in enumerate(_all_layers, start=1):
            _lyr_name = layer.name
            message = f"[{index} / {len(_all_layers)}] Updating Layer [{_lyr_name}] ..."
            logger.debug(message)
            try:
                set_resource_default_links(layer, layer)
                catalogue_post_save(instance=layer, sender=layer.__class__)
            except Exception:
                logger.exception(
                    f"[ERROR] Layer [{_lyr_name}] couldn't be updated")
Esempio n. 8
0
def set_resource_links(*args, **kwargs):

    from geonode.utils import set_resource_default_links
    from geonode.catalogue.models import catalogue_post_save
    from geonode.layers.models import Layer

    _all_layers = Layer.objects.all()
    for index, layer in enumerate(_all_layers, start=1):
        _lyr_name = layer.name
        message = "[%s / %s] Updating Layer [%s] ..." % (
            index, len(_all_layers), _lyr_name)
        print(message)
        logger.debug(message)
        try:
            set_resource_default_links(layer, layer)
            catalogue_post_save(instance=layer, sender=layer.__class__)
        except BaseException:
            logger.exception("[ERROR] Layer [%s] couldn't be updated" %
                             _lyr_name)
Esempio n. 9
0
def geoserver_post_save(instance, sender, created, **kwargs):
    from geonode.messaging import producer
    # this is attached to various models, (ResourceBase, Document)
    # so we should select what will be handled here
    if isinstance(instance, Layer):
        instance_dict = model_to_dict(instance)
        payload = json_serializer_producer(instance_dict)
        producer.geoserver_upload_layer(payload)

        if getattr(settings, 'DELAYED_SECURITY_SIGNALS', False):
            instance.set_dirty_state()

        if instance.storeType != 'remoteStore' and created:
            logger.info("... Creating Default Resource Linkks for Layer [%s]" % (instance.alternate))
            set_resource_default_links(instance, sender, prune=True)
            logger.info("... Creating Thumbnail for Layer [%s]" % (instance.alternate))
            try:
                create_gs_thumbnail(instance, overwrite=True, check_bbox=True)
            except BaseException:
                logger.warn("!WARNING! - Failure while Creating Thumbnail for Layer [%s]" % (instance.alternate))
Esempio n. 10
0
def geoserver_post_save_local(instance, *args, **kwargs):
    """Send information to geoserver.

       The attributes sent include:

        * Title
        * Abstract
        * Name
        * Keywords
        * Metadata Links,
        * Point of Contact name and url
    """
    instance.refresh_from_db()

    # Don't run this signal if is a Layer from a remote service
    if getattr(instance, "remote_service", None) is not None:
        return

    # Don't run this signal handler if it is a tile layer or a remote store (Service)
    #    Currently only gpkg files containing tiles will have this type & will be served via MapProxy.
    if hasattr(instance, 'storeType') and getattr(instance, 'storeType') in ['tileStore', 'remoteStore']:
        return instance

    gs_resource = None
    values = None
    _tries = 0
    _max_tries = getattr(ogc_server_settings, "MAX_RETRIES", 2)

    # If the store in None then it's a new instance from an upload,
    # only in this case run the geoserver_upload method
    if not instance.store or getattr(instance, 'overwrite', False):
        base_file, info = instance.get_base_file()

        # There is no need to process it if there is not file.
        if base_file is None:
            return
        gs_name, workspace, values, gs_resource = geoserver_upload(instance,
                                                                   base_file.file.path,
                                                                   instance.owner,
                                                                   instance.name,
                                                                   overwrite=True,
                                                                   title=instance.title,
                                                                   abstract=instance.abstract,
                                                                   # keywords=instance.keywords,
                                                                   charset=instance.charset)

    def fetch_gs_resource(values, tries):
        try:
            gs_resource = gs_catalog.get_resource(
                name=instance.name,
                store=instance.store,
                workspace=instance.workspace)
        except Exception:
            try:
                gs_resource = gs_catalog.get_resource(
                    name=instance.alternate,
                    store=instance.store,
                    workspace=instance.workspace)
            except Exception:
                try:
                    gs_resource = gs_catalog.get_resource(
                        name=instance.alternate or instance.typename)
                except Exception:
                    gs_resource = None

        if gs_resource:
            gs_resource.title = instance.title or ""
            gs_resource.abstract = instance.abstract or ""
            gs_resource.name = instance.name or ""

            if not values:
                values = dict(store=gs_resource.store.name,
                              storeType=gs_resource.store.resource_type,
                              alternate=gs_resource.store.workspace.name + ':' + gs_resource.name,
                              title=gs_resource.title or gs_resource.store.name,
                              abstract=gs_resource.abstract or '',
                              owner=instance.owner)
        else:
            msg = "There isn't a geoserver resource for this layer: %s" % instance.name
            logger.exception(msg)
            if tries >= _max_tries:
                # raise GeoNodeException(msg)
                return (values, None)
            gs_resource = None
            sleep(3.00)

        return (values, gs_resource)

    while not gs_resource and _tries < _max_tries:
        values, gs_resource = fetch_gs_resource(values, _tries)
        _tries += 1

    # Get metadata links
    metadata_links = []
    for link in instance.link_set.metadata():
        metadata_links.append((link.mime, link.name, link.url))

    if gs_resource:
        logger.debug("Found geoserver resource for this layer: %s" % instance.name)
        gs_resource.metadata_links = metadata_links
        # gs_resource should only be called if
        # ogc_server_settings.BACKEND_WRITE_ENABLED == True
        if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
            try:
                gs_catalog.save(gs_resource)
            except geoserver.catalog.FailedRequestError as e:
                msg = ('Error while trying to save resource named %s in GeoServer, '
                       'try to use: "%s"' % (gs_resource, str(e)))
                e.args = (msg,)
                logger.exception(e)

        # Update Attribution link
        if instance.poc:
            # gsconfig now utilizes an attribution dictionary
            gs_resource.attribution = {'title': str(instance.poc),
                                       'width': None,
                                       'height': None,
                                       'href': None,
                                       'url': None,
                                       'type': None}
            profile = get_user_model().objects.get(username=instance.poc.username)
            site_url = settings.SITEURL.rstrip('/') if settings.SITEURL.startswith('http') else settings.SITEURL
            gs_resource.attribution_link = site_url + profile.get_absolute_url()
            # gs_resource should only be called if
            # ogc_server_settings.BACKEND_WRITE_ENABLED == True
            if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
                try:
                    gs_catalog.save(gs_resource)
                except geoserver.catalog.FailedRequestError as e:
                    msg = ('Error while trying to save layer named %s in GeoServer, '
                           'try to use: "%s"' % (gs_resource, str(e)))
                    e.args = (msg,)
                    logger.exception(e)
    else:
        msg = "There isn't a geoserver resource for this layer: %s" % instance.name
        logger.warn(msg)

    if isinstance(instance, ResourceBase):
        if hasattr(instance, 'layer'):
            instance = instance.layer
        else:
            return

    # Save layer attributes
    set_attributes_from_geoserver(instance)

    # Save layer styles
    set_styles(instance, gs_catalog)

    # Invalidate GeoWebCache for the updated resource
    try:
        _stylefilterparams_geowebcache_layer(instance.alternate)
        _invalidate_geowebcache_layer(instance.alternate)
    except Exception:
        pass

    if instance.storeType == "remoteStore":
        return

    if gs_resource:
        """Get information from geoserver.

           The attributes retrieved include:

           * Bounding Box
           * SRID
           * Download links (WMS, WCS or WFS and KML)
           * Styles (SLD)
        """
        try:
            instance.abstract = gs_resource.abstract or ''
        except Exception as e:
            logger.exception(e)
            instance.abstract = ''
        instance.workspace = gs_resource.store.workspace.name
        instance.store = gs_resource.store.name

        try:
            bbox = gs_resource.native_bbox

            # Set bounding box values
            instance.bbox_x0 = bbox[0]
            instance.bbox_x1 = bbox[1]
            instance.bbox_y0 = bbox[2]
            instance.bbox_y1 = bbox[3]
            instance.srid = bbox[4]
        except Exception as e:
            logger.exception(e)

    if instance.srid:
        instance.srid_url = "http://www.spatialreference.org/ref/" + \
            instance.srid.replace(':', '/').lower() + "/"
    elif instance.bbox_x0 and instance.bbox_x1 and instance.bbox_y0 and instance.bbox_y1:
        # Guessing 'EPSG:4326' by default
        instance.srid = 'EPSG:4326'
    else:
        raise GeoNodeException("Invalid Projection. Layer is missing CRS!")

    # Iterate over values from geoserver.
    if gs_resource:
        for key in ['alternate', 'store', 'storeType']:
            # attr_name = key if 'typename' not in key else 'alternate'
            # print attr_name
            setattr(instance, key, values[key])

    if gs_resource:
        try:
            if settings.RESOURCE_PUBLISHING:
                if instance.is_published != gs_resource.advertised:
                    if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
                        gs_resource.advertised = 'true'
                        gs_catalog.save(gs_resource)

            if not settings.FREETEXT_KEYWORDS_READONLY:
                # AF: Warning - this won't allow people to have empty keywords on GeoNode
                if len(instance.keyword_list()) == 0 and gs_resource.keywords:
                    for keyword in gs_resource.keywords:
                        if keyword not in instance.keyword_list():
                            instance.keywords.add(keyword)

            if any(instance.keyword_list()):
                keywords = instance.keyword_list()
                gs_resource.keywords = [kw for kw in list(set(keywords))]

                # gs_resource should only be called if
                # ogc_server_settings.BACKEND_WRITE_ENABLED == True
                if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
                    gs_catalog.save(gs_resource)
        except Exception as e:
            msg = ('Error while trying to save resource named %s in GeoServer, '
                   'try to use: "%s"' % (gs_resource, str(e)))
            e.args = (msg,)
            logger.exception(e)

    to_update = {
        'title': instance.title or instance.name,
        'abstract': instance.abstract or "",
        'alternate': instance.alternate,
        'bbox_x0': instance.bbox_x0,
        'bbox_x1': instance.bbox_x1,
        'bbox_y0': instance.bbox_y0,
        'bbox_y1': instance.bbox_y1,
        'srid': instance.srid
    }

    # Update ResourceBase
    resources = ResourceBase.objects.filter(id=instance.resourcebase_ptr.id)
    resources.update(**to_update)

    # to_update['name'] = instance.name,
    to_update['workspace'] = instance.workspace
    to_update['store'] = instance.store
    to_update['storeType'] = instance.storeType
    to_update['typename'] = instance.alternate

    # Save all the modified information in the instance without triggering signals.
    Layer.objects.filter(id=instance.id).update(**to_update)

    # Refresh from DB
    instance.refresh_from_db()

    # Updating the Catalogue
    catalogue_post_save(instance=instance, sender=instance.__class__)

    # store the resource to avoid another geoserver call in the post_save
    if gs_resource:
        instance.gs_resource = gs_resource

    # some thumbnail generators will update thumbnail_url.  If so, don't
    # immediately re-generate the thumbnail here.  use layer#save(update_fields=['thumbnail_url'])
    if gs_resource:
        logger.debug("... Creating Default Resource Links for Layer [%s]" % (instance.alternate))
        set_resource_default_links(instance, instance, prune=True)

        if 'update_fields' in kwargs and kwargs['update_fields'] is not None and \
                'thumbnail_url' in kwargs['update_fields']:
            logger.debug("... Creating Thumbnail for Layer [%s]" % (instance.alternate))
            create_gs_thumbnail(instance, overwrite=True)

    # Updating HAYSTACK Indexes if needed
    if settings.HAYSTACK_SEARCH:
        from django.core.management import call_command
        call_command('update_index')
Esempio n. 11
0
    def test_layer_links(self):
        lyr = Layer.objects.filter(storeType="dataStore").first()
        self.assertEquals(lyr.storeType, "dataStore")
        if check_ogc_backend(geoserver.BACKEND_PACKAGE):
            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="metadata")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
            for ll in links:
                self.assertEquals(ll.link_type, "metadata")

            _def_link_types = ('data', 'image', 'original', 'html', 'OGC:WMS',
                               'OGC:WFS', 'OGC:WCS')
            Link.objects.filter(resource=lyr.resourcebase_ptr,
                                link_type__in=_def_link_types).delete()
            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="data")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 0)

            set_resource_default_links(lyr, lyr)

            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="metadata")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
            for ll in links:
                self.assertEquals(ll.link_type, "metadata")

            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="data")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 6)

            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="image")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 3)

        lyr = Layer.objects.filter(storeType="coverageStore").first()
        self.assertEquals(lyr.storeType, "coverageStore")
        if check_ogc_backend(geoserver.BACKEND_PACKAGE):
            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="metadata")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
            for ll in links:
                self.assertEquals(ll.link_type, "metadata")

            _def_link_types = ('data', 'image', 'original', 'html', 'OGC:WMS',
                               'OGC:WFS', 'OGC:WCS')
            Link.objects.filter(resource=lyr.resourcebase_ptr,
                                link_type__in=_def_link_types).delete()
            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="data")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 0)

            set_resource_default_links(lyr, lyr)

            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="metadata")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
            for ll in links:
                self.assertEquals(ll.link_type, "metadata")

            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="data")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 2)

            links = Link.objects.filter(resource=lyr.resourcebase_ptr,
                                        link_type="image")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
Esempio n. 12
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()

    # refresh to get QGIS Layer
    instance.refresh_from_db()

    # 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 spatial_ref else 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 srs else 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)

    # Refresh and create the instance default links
    set_resource_default_links(instance,
                               qgis_layer,
                               is_shapefile=is_shapefile,
                               original_ext=original_ext)

    # Create thumbnail
    overwrite = getattr(instance, 'overwrite', False)
    create_qgis_server_thumbnail.delay(get_model_path(instance),
                                       instance.id,
                                       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
Esempio n. 13
0
    def test_base_resources(self):
        """
        Ensure we can access the Resource Base list.
        """
        url = reverse('base-resources-list')
        # Anonymous
        response = self.client.get(url, format='json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data), 5)
        self.assertEqual(response.data['total'], 26)
        # Pagination
        self.assertEqual(len(response.data['resources']), 10)
        logger.debug(response.data)

        # Remove public permissions to Layers
        from geonode.layers.utils import set_layers_permissions
        set_layers_permissions(
            "read",  # permissions_name
            None,  # resources_names == None (all layers)
            [get_anonymous_user()],  # users_usernames
            None,  # groups_names
            True,  # delete_flag
        )
        response = self.client.get(url, format='json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data), 5)
        self.assertEqual(response.data['total'], 26)
        # Pagination
        self.assertEqual(len(response.data['resources']), 10)

        # Admin
        self.assertTrue(self.client.login(username='******', password='******'))
        response = self.client.get(url, format='json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data), 5)
        self.assertEqual(response.data['total'], 26)
        # response has link to the response
        self.assertTrue('link' in response.data['resources'][0].keys())
        # Pagination
        self.assertEqual(len(response.data['resources']), 10)
        logger.debug(response.data)

        # Bobby
        self.assertTrue(self.client.login(username='******', password='******'))
        response = self.client.get(url, format='json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data), 5)
        self.assertEqual(response.data['total'], 26)
        # Pagination
        self.assertEqual(len(response.data['resources']), 10)
        logger.debug(response.data)

        # Norman
        self.assertTrue(self.client.login(username='******',
                                          password='******'))
        response = self.client.get(url, format='json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data), 5)
        self.assertEqual(response.data['total'], 26)
        # Pagination
        self.assertEqual(len(response.data['resources']), 10)
        logger.debug(response.data)

        # Pagination
        # Admin
        self.assertTrue(self.client.login(username='******', password='******'))

        response = self.client.get(f"{url}?page_size=17", format='json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.data), 5)
        self.assertEqual(response.data['total'], 26)
        # Pagination
        self.assertEqual(len(response.data['resources']), 17)

        # Check user permissions
        resource = ResourceBase.objects.filter(owner__username='******').first()
        # Admin
        response = self.client.get(f"{url}/{resource.id}/", format='json')
        self.assertTrue(
            'change_resourcebase' in list(response.data['resource']['perms']))
        # Annonymous
        self.assertIsNone(self.client.logout())
        response = self.client.get(f"{url}/{resource.id}/", format='json')
        self.assertFalse(
            'change_resourcebase' in list(response.data['resource']['perms']))
        # user owner
        self.assertTrue(self.client.login(username='******', password='******'))
        response = self.client.get(f"{url}/{resource.id}/", format='json')
        self.assertTrue(
            'change_resourcebase' in list(response.data['resource']['perms']))
        # user not owner and not assigned
        self.assertTrue(self.client.login(username='******',
                                          password='******'))
        response = self.client.get(f"{url}/{resource.id}/", format='json')
        self.assertFalse(
            'change_resourcebase' in list(response.data['resource']['perms']))
        # response has links property
        # create link
        if check_ogc_backend(geoserver.BACKEND_PACKAGE):
            layer = Layer.objects.first()
            set_resource_default_links(layer, layer)
            response = self.client.get(f"{url}/{layer.id}/", format='json')
            self.assertTrue('links' in response.data['resource'].keys())
Esempio n. 14
0
    def test_layer_links(self):
        lyr = Layer.objects.filter(storeType="dataStore").first()
        self.assertEquals(lyr.storeType, "dataStore")
        if check_ogc_backend(geoserver.BACKEND_PACKAGE):
            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="metadata")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
            for ll in links:
                self.assertEquals(ll.link_type, "metadata")

            _def_link_types = (
                'data', 'image', 'original', 'html', 'OGC:WMS', 'OGC:WFS', 'OGC:WCS')
            Link.objects.filter(resource=lyr.resourcebase_ptr, link_type__in=_def_link_types).delete()
            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="data")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 0)

            set_resource_default_links(lyr, lyr)

            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="metadata")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
            for ll in links:
                self.assertEquals(ll.link_type, "metadata")

            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="data")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 6)

            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="image")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 3)

        lyr = Layer.objects.filter(storeType="coverageStore").first()
        self.assertEquals(lyr.storeType, "coverageStore")
        if check_ogc_backend(geoserver.BACKEND_PACKAGE):
            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="metadata")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
            for ll in links:
                self.assertEquals(ll.link_type, "metadata")

            _def_link_types = (
                'data', 'image', 'original', 'html', 'OGC:WMS', 'OGC:WFS', 'OGC:WCS')
            Link.objects.filter(resource=lyr.resourcebase_ptr, link_type__in=_def_link_types).delete()
            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="data")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 0)

            set_resource_default_links(lyr, lyr)

            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="metadata")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
            for ll in links:
                self.assertEquals(ll.link_type, "metadata")

            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="data")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 2)

            links = Link.objects.filter(resource=lyr.resourcebase_ptr, link_type="image")
            self.assertIsNotNone(links)
            self.assertEquals(len(links), 7)
Esempio n. 15
0
def geoserver_post_save_layers(self, instance_id, *args, **kwargs):
    """
    Runs update layers.
    """
    instance = None
    try:
        instance = Layer.objects.get(id=instance_id)
    except Layer.DoesNotExist:
        logger.debug(f"Layer id {instance_id} does not exist yet!")
        raise

    lock_id = f'{self.request.id}'
    with AcquireLock(lock_id) as lock:
        if lock.acquire() is True:
            # Don't run this signal if is a Layer from a remote service
            if getattr(instance, "remote_service", None) is not None:
                return

            if instance.storeType == "remoteStore":
                return

            # Don't run this signal handler if it is a tile layer or a remote store (Service)
            #    Currently only gpkg files containing tiles will have this type & will be served via MapProxy.
            if hasattr(instance, 'storeType') and getattr(
                    instance, 'storeType') in ['tileStore', 'remoteStore']:
                return instance

            if isinstance(instance, ResourceBase):
                if hasattr(instance, 'layer'):
                    instance = instance.layer
                else:
                    return

            geonode_upload_sessions = UploadSession.objects.filter(
                resource=instance)
            geonode_upload_sessions.update(processed=False)

            gs_resource = None
            values = None
            _tries = 0
            _max_tries = getattr(ogc_server_settings, "MAX_RETRIES", 2)

            # If the store in None then it's a new instance from an upload,
            # only in this case run the geoserver_upload method
            if not instance.store or getattr(instance, 'overwrite', False):
                base_file, info = instance.get_base_file()

                # There is no need to process it if there is no file.
                if base_file is None:
                    return
                gs_name, workspace, values, gs_resource = geoserver_upload(
                    instance,
                    base_file.file.path,
                    instance.owner,
                    instance.name,
                    overwrite=True,
                    title=instance.title,
                    abstract=instance.abstract,
                    charset=instance.charset)

            values, gs_resource = fetch_gs_resource(instance, values, _tries)
            while not gs_resource and _tries < _max_tries:
                values, gs_resource = fetch_gs_resource(
                    instance, values, _tries)
                _tries += 1

            # Get metadata links
            metadata_links = []
            for link in instance.link_set.metadata():
                metadata_links.append((link.mime, link.name, link.url))

            if gs_resource:
                logger.debug("Found geoserver resource for this layer: %s" %
                             instance.name)
                gs_resource.metadata_links = metadata_links
                instance.gs_resource = gs_resource

                # Update Attribution link
                if instance.poc:
                    # gsconfig now utilizes an attribution dictionary
                    gs_resource.attribution = {
                        'title': str(instance.poc),
                        'width': None,
                        'height': None,
                        'href': None,
                        'url': None,
                        'type': None
                    }
                    profile = get_user_model().objects.get(
                        username=instance.poc.username)
                    site_url = settings.SITEURL.rstrip(
                        '/') if settings.SITEURL.startswith(
                            'http') else settings.SITEURL
                    gs_resource.attribution_link = site_url + profile.get_absolute_url(
                    )
                """Get information from geoserver.

                The attributes retrieved include:

                * Bounding Box
                * SRID
                * Download links (WMS, WCS or WFS and KML)
                * Styles (SLD)
                """
                try:
                    # This is usually done in Layer.pre_save, however if the hooks
                    # are bypassed by custom create/updates we need to ensure the
                    # bbox is calculated properly.
                    bbox = gs_resource.native_bbox
                    instance.set_bbox_polygon(
                        [bbox[0], bbox[2], bbox[1], bbox[3]],
                        gs_resource.projection)
                except Exception as e:
                    logger.exception(e)

                if instance.srid:
                    instance.srid_url = "http://www.spatialreference.org/ref/" + \
                        instance.srid.replace(':', '/').lower() + "/"
                elif instance.bbox_polygon is not None:
                    # Guessing 'EPSG:4326' by default
                    instance.srid = 'EPSG:4326'
                else:
                    raise GeoNodeException(
                        "Invalid Projection. Layer is missing CRS!")

                # Iterate over values from geoserver.
                for key in ['alternate', 'store', 'storeType']:
                    # attr_name = key if 'typename' not in key else 'alternate'
                    # print attr_name
                    setattr(instance, key, values[key])

                try:
                    if settings.RESOURCE_PUBLISHING:
                        if instance.is_published != gs_resource.advertised:
                            gs_resource.advertised = 'true'

                    if not settings.FREETEXT_KEYWORDS_READONLY:
                        # AF: Warning - this won't allow people to have empty keywords on GeoNode
                        if len(instance.keyword_list()
                               ) == 0 and gs_resource.keywords:
                            for keyword in gs_resource.keywords:
                                if keyword not in instance.keyword_list():
                                    instance.keywords.add(keyword)

                    if any(instance.keyword_list()):
                        keywords = instance.keyword_list()
                        gs_resource.keywords = [
                            kw for kw in list(set(keywords))
                        ]

                    # gs_resource should only be called if
                    # ogc_server_settings.BACKEND_WRITE_ENABLED == True
                    if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED",
                               True):
                        gs_catalog.save(gs_resource)
                except Exception as e:
                    msg = (
                        'Error while trying to save resource named %s in GeoServer, '
                        'try to use: "%s"' % (gs_resource, str(e)))
                    e.args = (msg, )
                    logger.exception(e)

                # store the resource to avoid another geoserver call in the post_save
                to_update = {
                    'title': instance.title or instance.name,
                    'abstract': instance.abstract or "",
                    'alternate': instance.alternate,
                    'bbox_polygon': instance.bbox_polygon,
                    'srid': 'EPSG:4326'
                }

                if is_monochromatic_image(instance.thumbnail_url):
                    to_update['thumbnail_url'] = staticfiles.static(
                        settings.MISSING_THUMBNAIL)

                # Save all the modified information in the instance without triggering signals.
                try:
                    with transaction.atomic():
                        ResourceBase.objects.filter(
                            id=instance.resourcebase_ptr.id).update(
                                **to_update)

                        # to_update['name'] = instance.name,
                        to_update[
                            'workspace'] = gs_resource.store.workspace.name
                        to_update['store'] = gs_resource.store.name
                        to_update['storeType'] = instance.storeType
                        to_update['typename'] = instance.alternate

                        Layer.objects.filter(id=instance.id).update(
                            **to_update)

                        # Refresh from DB
                        instance.refresh_from_db()
                except Exception as e:
                    logger.exception(e)

                # Refreshing CSW records
                logger.debug(
                    f"... Updating the Catalogue entries for Layer {instance.title}"
                )
                try:
                    catalogue_post_save(instance=instance,
                                        sender=instance.__class__)
                except Exception as e:
                    logger.exception(e)

                # Refreshing layer links
                logger.debug(
                    f"... Creating Default Resource Links for Layer {instance.title}"
                )
                try:
                    set_resource_default_links(instance, instance, prune=True)
                except Exception as e:
                    logger.exception(e)

                # Save layer attributes
                logger.debug(
                    f"... Refresh GeoServer attributes list for Layer {instance.title}"
                )
                try:
                    set_attributes_from_geoserver(instance)
                except Exception as e:
                    logger.exception(e)

                # Save layer styles
                logger.debug(
                    f"... Refresh Legend links for Layer {instance.title}")
                try:
                    set_styles(instance, gs_catalog)
                except Exception as e:
                    logger.exception(e)

                # Invalidate GeoWebCache for the updated resource
                try:
                    _stylefilterparams_geowebcache_layer(instance.alternate)
                    _invalidate_geowebcache_layer(instance.alternate)
                except Exception:
                    pass

                # Creating Layer Thumbnail by sending a signal
                from geonode.geoserver.signals import geoserver_post_save_complete
                geoserver_post_save_complete.send(sender=instance.__class__,
                                                  instance=instance)
            try:
                geonode_upload_sessions = UploadSession.objects.filter(
                    resource=instance)
                geonode_upload_sessions.update(processed=True)
            except Exception as e:
                logger.exception(e)

            # Updating HAYSTACK Indexes if needed
            if settings.HAYSTACK_SEARCH:
                call_command('update_index')
Esempio n. 16
0
def geoserver_post_save_local(instance, *args, **kwargs):
    """Send information to geoserver.

       The attributes sent include:

        * Title
        * Abstract
        * Name
        * Keywords
        * Metadata Links,
        * Point of Contact name and url
    """
    # Don't run this signal if is a Layer from a remote service
    if getattr(instance, "remote_service", None) is not None:
        return

    # Don't run this signal handler if it is a tile layer or a remote store (Service)
    #    Currently only gpkg files containing tiles will have this type & will be served via MapProxy.
    if hasattr(instance, 'storeType') and getattr(instance, 'storeType') in ['tileStore', 'remoteStore']:
        return instance

    gs_resource = None
    values = None

    # If the store in None then it's a new instance from an upload,
    # only in this case run the geoserver_upload method
    if not instance.store or getattr(instance, 'overwrite', False):
        base_file, info = instance.get_base_file()

        # There is no need to process it if there is not file.
        if base_file is None:
            return
        gs_name, workspace, values, gs_resource = geoserver_upload(instance,
                                                                   base_file.file.path,
                                                                   instance.owner,
                                                                   instance.name,
                                                                   overwrite=True,
                                                                   title=instance.title,
                                                                   abstract=instance.abstract,
                                                                   # keywords=instance.keywords,
                                                                   charset=instance.charset)

    if not gs_resource:
        gs_resource = gs_catalog.get_resource(
            instance.name,
            store=instance.store,
            workspace=instance.workspace)
        if not gs_resource:
            gs_resource = gs_catalog.get_resource(instance.alternate)

    if gs_resource:
        gs_resource.title = instance.title or ""
        gs_resource.abstract = instance.abstract or ""
        gs_resource.name = instance.name or ""

        if not values:
            values = dict(store=gs_resource.store.name,
                          storeType=gs_resource.store.resource_type,
                          alternate=gs_resource.store.workspace.name + ':' + gs_resource.name,
                          title=gs_resource.title or gs_resource.store.name,
                          abstract=gs_resource.abstract or '',
                          owner=instance.owner)
    else:
        msg = "There isn't a geoserver resource for this layer: %s" % instance.name
        logger.exception(msg)
        raise Exception(msg)

    # Get metadata links
    metadata_links = []
    for link in instance.link_set.metadata():
        metadata_links.append((link.mime, link.name, link.url))

    gs_resource.metadata_links = metadata_links
    # gs_resource should only be called if
    # ogc_server_settings.BACKEND_WRITE_ENABLED == True
    if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
        try:
            gs_catalog.save(gs_resource)
        except geoserver.catalog.FailedRequestError as e:
            msg = ('Error while trying to save resource named %s in GeoServer, '
                   'try to use: "%s"' % (gs_resource, str(e)))
            e.args = (msg,)
            logger.exception(e)

    # Update Attribution link
    if instance.poc:
        # gsconfig now utilizes an attribution dictionary
        gs_resource.attribution = {'title': str(instance.poc),
                                   'width': None,
                                   'height': None,
                                   'href': None,
                                   'url': None,
                                   'type': None}
        profile = Profile.objects.get(username=instance.poc.username)
        site_url = settings.SITEURL.rstrip('/') if settings.SITEURL.startswith('http') else settings.SITEURL
        gs_resource.attribution_link = site_url + profile.get_absolute_url()
        # gs_resource should only be called if
        # ogc_server_settings.BACKEND_WRITE_ENABLED == True
        if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
            try:
                gs_catalog.save(gs_resource)
            except geoserver.catalog.FailedRequestError as e:
                msg = ('Error while trying to save layer named %s in GeoServer, '
                       'try to use: "%s"' % (gs_resource, str(e)))
                e.args = (msg,)
                logger.exception(e)

    if isinstance(instance, ResourceBase):
        if hasattr(instance, 'layer'):
            instance = instance.layer
        else:
            return

    # Save layer attributes
    set_attributes_from_geoserver(instance)

    # Save layer styles
    set_styles(instance, gs_catalog)

    # set SLD
    sld = instance.default_style.sld_body if instance.default_style else None
    if sld:
        set_layer_style(instance, instance.alternate, sld)

    # Invalidate GeoWebCache for the updated resource
    try:
        _stylefilterparams_geowebcache_layer(instance.alternate)
        _invalidate_geowebcache_layer(instance.alternate)
    except BaseException:
        pass

    if instance.storeType == "remoteStore":
        # Save layer attributes
        set_attributes_from_geoserver(instance)
        return

    """Get information from geoserver.

       The attributes retrieved include:

       * Bounding Box
       * SRID
       * Download links (WMS, WCS or WFS and KML)
       * Styles (SLD)
    """
    # instance.name = instance.name or gs_resource.name
    # instance.title = instance.title or gs_resource.title
    instance.abstract = gs_resource.abstract or ''
    instance.workspace = gs_resource.store.workspace.name
    instance.store = gs_resource.store.name

    try:
        logger.debug(" -------------------------------------------------- ")
        bbox = gs_resource.native_bbox
        logger.debug(bbox)
        logger.debug(" -------------------------------------------------- ")
        # Set bounding box values
        instance.bbox_x0 = bbox[0]
        instance.bbox_x1 = bbox[1]
        instance.bbox_y0 = bbox[2]
        instance.bbox_y1 = bbox[3]
        instance.srid = bbox[4]
    except BaseException:
        pass

    if instance.srid:
        instance.srid_url = "http://www.spatialreference.org/ref/" + \
            instance.srid.replace(':', '/').lower() + "/"
    elif instance.bbox_x0 and instance.bbox_x1 and instance.bbox_y0 and instance.bbox_y1:
        # Guessing 'EPSG:4326' by default
        instance.srid = 'EPSG:4326'
    else:
        raise GeoNodeException("Invalid Projection. Layer is missing CRS!")

    # Iterate over values from geoserver.
    for key in ['alternate', 'store', 'storeType']:
        # attr_name = key if 'typename' not in key else 'alternate'
        # print attr_name
        setattr(instance, key, values[key])

    if settings.RESOURCE_PUBLISHING:
        if instance.is_published != gs_resource.advertised:
            if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
                gs_resource.advertised = 'true'
                gs_catalog.save(gs_resource)

    if not settings.FREETEXT_KEYWORDS_READONLY:
        try:
            if len(instance.keyword_list()) == 0 and gs_resource.keywords:
                for keyword in gs_resource.keywords:
                    if keyword not in instance.keyword_list():
                        instance.keywords.add(keyword)
        except BaseException:
            pass

    if any(instance.keyword_list()):
        keywords = instance.keyword_list()
        gs_resource.keywords = [kw for kw in list(set(keywords))]

        # gs_resource should only be called if
        # ogc_server_settings.BACKEND_WRITE_ENABLED == True
        if getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
            try:
                gs_catalog.save(gs_resource)
            except geoserver.catalog.FailedRequestError as e:
                msg = ('Error while trying to save resource named %s in GeoServer, '
                       'try to use: "%s"' % (gs_resource, str(e)))
                e.args = (msg,)
                logger.exception(e)

    to_update = {
        'title': instance.title or instance.name,
        'abstract': instance.abstract or "",
        'alternate': instance.alternate,
        'bbox_x0': instance.bbox_x0,
        'bbox_x1': instance.bbox_x1,
        'bbox_y0': instance.bbox_y0,
        'bbox_y1': instance.bbox_y1,
        'srid': instance.srid
    }

    # Update ResourceBase
    resources = ResourceBase.objects.filter(id=instance.resourcebase_ptr.id)
    resources.update(**to_update)

    # to_update['name'] = instance.name,
    to_update['workspace'] = instance.workspace
    to_update['store'] = instance.store
    to_update['storeType'] = instance.storeType
    to_update['typename'] = instance.alternate

    # Save all the modified information in the instance without triggering signals.
    Layer.objects.filter(id=instance.id).update(**to_update)

    # Refresh from DB
    instance.refresh_from_db()

    # store the resource to avoid another geoserver call in the post_save
    instance.gs_resource = gs_resource

    # Refresh and create the instance default links
    layer = Layer.objects.get(id=instance.id)
    set_resource_default_links(instance, layer, prune=True)

    # some thumbnail generators will update thumbnail_url.  If so, don't
    # immediately re-generate the thumbnail here.  use layer#save(update_fields=['thumbnail_url'])
    if 'update_fields' in kwargs and kwargs['update_fields'] is not None and \
            'thumbnail_url' in kwargs['update_fields']:
        logger.info("... Creating Thumbnail for Layer [%s]" % (instance.alternate))
        create_gs_thumbnail(instance, overwrite=True)

    # NOTTODO by simod: we should not do this!
    # need to be removed when fixing #2015
    catalogue_post_save(instance, Layer)

    # Updating HAYSTACK Indexes if needed
    if settings.HAYSTACK_SEARCH:
        from django.core.management import call_command
        call_command('update_index')
Esempio n. 17
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()

    # refresh to get QGIS Layer
    instance.refresh_from_db()

    # 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 spatial_ref else 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 srs else 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)

    # Refresh and create the instance default links
    set_resource_default_links(instance, qgis_layer, is_shapefile=is_shapefile, original_ext=original_ext)

    # Create thumbnail
    overwrite = getattr(instance, 'overwrite', False)
    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