Skip to content

Commit

Permalink
Merge pull request GeoNode#821 from geosolutions-it/nexus_wip_resourc…
Browse files Browse the repository at this point in the history
…e_manager

[References ISSUE #194][Upload / Import refactoring] Upload Workflow review
  • Loading branch information
Alessio Fabiani committed Jun 1, 2021
2 parents b49399a + 947be13 commit 347628c
Show file tree
Hide file tree
Showing 25 changed files with 637 additions and 599 deletions.
71 changes: 1 addition & 70 deletions geonode/base/models.py
Expand Up @@ -37,7 +37,7 @@
from django.contrib.auth.models import Group
from django.core.files.base import ContentFile
from django.contrib.auth import get_user_model
from django.contrib.gis.geos import GEOSGeometry, Polygon, Point
from django.contrib.gis.geos import Polygon, Point
from django.contrib.gis.db.models import PolygonField
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
Expand Down Expand Up @@ -1964,75 +1964,6 @@ class GroupGeoLimit(models.Model):
blank=True)


def resourcebase_post_save(instance, *args, **kwargs):
"""
Used to fill any additional fields after the save.
Has to be called by the children
"""
try:
# set default License if no specified
if instance.license is None:
license = License.objects.filter(name="Not Specified")

if license and len(license) > 0:
instance.license = license[0]

ResourceBase.objects.filter(id=instance.id).update(
thumbnail_url=instance.get_thumbnail_url(),
detail_url=instance.get_absolute_url(),
csw_insert_date=now(),
license=instance.license)
instance.refresh_from_db()
except Exception:
tb = traceback.format_exc()
if tb:
logger.debug(tb)
finally:
instance.set_missing_info()

try:
if not instance.regions or instance.regions.count() == 0:
srid1, wkt1 = instance.geographic_bounding_box.split(";")
srid1 = re.findall(r'\d+', srid1)

poly1 = GEOSGeometry(wkt1, srid=int(srid1[0]))
poly1.transform(4326)

queryset = Region.objects.all().order_by('name')
global_regions = []
regions_to_add = []
for region in queryset:
try:
srid2, wkt2 = region.geographic_bounding_box.split(";")
srid2 = re.findall(r'\d+', srid2)

poly2 = GEOSGeometry(wkt2, srid=int(srid2[0]))
poly2.transform(4326)

if poly2.intersection(poly1):
regions_to_add.append(region)
if region.level == 0 and region.parent is None:
global_regions.append(region)
except Exception:
tb = traceback.format_exc()
if tb:
logger.debug(tb)
if regions_to_add or global_regions:
if regions_to_add and len(
regions_to_add) > 0 and len(regions_to_add) <= 30:
instance.regions.add(*regions_to_add)
else:
instance.regions.add(*global_regions)
except Exception:
tb = traceback.format_exc()
if tb:
logger.debug(tb)
finally:
# refresh catalogue metadata records
from geonode.catalogue.models import catalogue_post_save
catalogue_post_save(instance=instance, sender=instance.__class__)


def rating_post_save(instance, *args, **kwargs):
"""
Used to fill the average rating field on OverallRating change.
Expand Down
3 changes: 1 addition & 2 deletions geonode/documents/models.py
Expand Up @@ -36,7 +36,7 @@
from uuid_upload_path import upload_to

from geonode.layers.models import Layer
from geonode.base.models import ResourceBase, resourcebase_post_save, Link
from geonode.base.models import ResourceBase, Link
from geonode.documents.enumerations import DOCUMENT_TYPE_MAP, DOCUMENT_MIMETYPE_MAP
from geonode.maps.signals import map_changed_signal
from geonode.maps.models import Map
Expand Down Expand Up @@ -267,6 +267,5 @@ def pre_delete_document(instance, sender, **kwargs):

signals.pre_save.connect(pre_save_document, sender=Document)
signals.post_save.connect(post_save_document, sender=Document)
signals.post_save.connect(resourcebase_post_save, sender=Document)
signals.pre_delete.connect(pre_delete_document, sender=Document)
map_changed_signal.connect(update_documents_extent)
7 changes: 1 addition & 6 deletions geonode/geoapps/models.py
Expand Up @@ -21,14 +21,13 @@

from django.db import models
from django.urls import reverse
from django.db.models import signals
from django.utils.translation import ugettext_lazy as _

from jsonfield import JSONField

from guardian.shortcuts import get_anonymous_user

from geonode.base.models import ResourceBase, resourcebase_post_save
from geonode.base.models import ResourceBase

logger = logging.getLogger("geonode.geoapps.models")

Expand Down Expand Up @@ -147,7 +146,3 @@ class GeoAppData(models.Model):
null=False,
blank=False,
on_delete=models.CASCADE)


# signals.pre_delete.connect(pre_delete_app, sender=GeoApp)
signals.post_save.connect(resourcebase_post_save, sender=GeoApp)
11 changes: 1 addition & 10 deletions geonode/geoserver/__init__.py
Expand Up @@ -28,23 +28,14 @@


def run_setup_hooks(*args, **kwargs):

from django.db.models import signals

from geonode.base.models import ResourceBase
from geonode.layers.models import Layer
from geonode.maps.models import Map, MapLayer

from geonode.maps.models import MapLayer
from geonode.geoserver.signals import geoserver_pre_delete
from geonode.geoserver.signals import geoserver_post_save
from geonode.geoserver.signals import geoserver_post_save_map
from geonode.geoserver.signals import geoserver_pre_save_maplayer

signals.post_save.connect(geoserver_post_save, sender=ResourceBase)
signals.pre_delete.connect(geoserver_pre_delete, sender=Layer)
signals.post_save.connect(geoserver_post_save, sender=Layer)
signals.pre_save.connect(geoserver_pre_save_maplayer, sender=MapLayer)
signals.post_save.connect(geoserver_post_save_map, sender=Map)


def set_resource_links(*args, **kwargs):
Expand Down
28 changes: 14 additions & 14 deletions geonode/geoserver/context_processors.py
Expand Up @@ -35,20 +35,20 @@ def geoserver_urls(request):
PRINT_NG_ENABLED=getattr(ogc_server_settings, 'PRINT_NG_ENABLED', False),
GEONODE_SECURITY_ENABLED=getattr(ogc_server_settings, 'GEONODE_SECURITY_ENABLED', False),
TIME_ENABLED=getattr(
settings,
'UPLOADER',
dict()).get(
'OPTIONS',
dict()).get(
'TIME_ENABLED',
False),
settings,
'UPLOADER',
dict()).get(
'OPTIONS',
dict()).get(
'TIME_ENABLED',
False),
MOSAIC_ENABLED=getattr(
settings,
'UPLOADER',
dict()).get(
'OPTIONS',
dict()).get(
'MOSAIC_ENABLED',
False),
settings,
'UPLOADER',
dict()).get(
'OPTIONS',
dict()).get(
'MOSAIC_ENABLED',
False),
)
return defaults
4 changes: 0 additions & 4 deletions geonode/geoserver/helpers.py
Expand Up @@ -42,7 +42,6 @@
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured
from django.db.models.signals import pre_delete
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.translation import ugettext as _
Expand Down Expand Up @@ -816,9 +815,6 @@ def gs_slurp(
status = "delete_succeeded"
except Exception:
status = "delete_failed"
finally:
from .signals import geoserver_pre_delete
pre_delete.connect(geoserver_pre_delete, sender=Layer)

msg = f"[{status}] Layer {layer.name} ({(i + 1)}/{number_deleted})"
info = {'name': layer.name, 'status': status}
Expand Down
130 changes: 130 additions & 0 deletions geonode/geoserver/manager.py
@@ -0,0 +1,130 @@
# -*- coding: utf-8 -*-
#########################################################################
#
# Copyright (C) 2021 OSGeo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
import logging
import tempfile

from django.db.models.query import QuerySet

from geonode.layers.models import Layer
from geonode.base.models import ResourceBase
from geonode.services.enumerations import CASCADED
from geonode.resource.manager import ResourceManager, ResourceManagerInterface

from .tasks import (
geoserver_set_style,
geoserver_create_style,
geoserver_cascading_delete,
geoserver_create_thumbnail)
from .signals import geoserver_post_save_local
from .helpers import (
gs_catalog,
set_time_info,
ogc_server_settings)

logger = logging.getLogger(__name__)


class GeoServerResourceManager(ResourceManagerInterface):

def search(self, filter: dict, /, type: object = None) -> QuerySet:
return type.objects.none()

def exists(self, uuid: str, /, instance: ResourceBase = None) -> bool:
if instance:
_real_instance = instance.get_real_instance()
if hasattr(_real_instance, 'storeType') and _real_instance.storeType not in ['tileStore', 'remoteStore']:
try:
logger.debug(f"Searching GeoServer for layer '{_real_instance.alternate}'")
if gs_catalog.get_layer(_real_instance.alternate):
return True
except Exception as e:
logger.debug(e)
return False
return True
return False

def delete(self, uuid: str, /, instance: ResourceBase = None) -> int:
"""Removes the layer from GeoServer
"""
# cascading_delete should only be called if
# ogc_server_settings.BACKEND_WRITE_ENABLED == True
if instance and getattr(ogc_server_settings, "BACKEND_WRITE_ENABLED", True):
_real_instance = instance.get_real_instance()
if hasattr(_real_instance, 'alternate') and _real_instance.alternate:
if _real_instance.remote_service is None or _real_instance.remote_service.method == CASCADED:
geoserver_cascading_delete.apply_async((_real_instance.alternate,))

def create(self, uuid: str, /, resource_type: object = None, defaults: dict = {}) -> ResourceBase:
if resource_type:
_resource = resource_type.objects.get(uuid=uuid)
if resource_type == Layer:
geoserver_post_save_local(_resource)
return _resource
return None

def update(self, uuid: str, /, instance: ResourceBase = None, xml_file: str = None, metadata_uploaded: bool = False,
vals: dict = {}, regions: dict = {}, keywords: dict = {}, custom: dict = {}, notify: bool = True) -> ResourceBase:
if instance:
if isinstance(instance.get_real_instance(), Layer):
geoserver_post_save_local(instance.get_real_instance())
return instance

def set_permissions(self, uuid: str, /, instance: ResourceBase = None, permissions: dict = {}, created: bool = False) -> bool:
# TODO: move GeoFence set perms logic here
return True

def set_thumbnail(self, uuid: str, /, instance: ResourceBase = None, overwrite: bool = True, check_bbox: bool = True) -> bool:
if instance:
# TODO: missing thumb for documents
geoserver_create_thumbnail.apply_async(((instance.id, overwrite, check_bbox, )))
return True
return False

def exec(self, method: str, uuid: str, /, instance: ResourceBase = None, **kwargs) -> ResourceBase:
raise NotImplementedError

def set_style(self, method: str, uuid: str, /, instance: ResourceBase = None, **kwargs) -> ResourceBase:
instance = instance or ResourceManager._get_instance(uuid)

if instance and isinstance(instance.get_real_instance(), Layer):
try:
logger.info(f'Creating style for Layer {instance.get_real_instance()} / {kwargs}')
_sld_file = kwargs.get('sld_file', None)
_tempdir = kwargs.get('tempdir', tempfile.gettempdir())
if _sld_file and kwargs.get('sld_uploaded', False):
geoserver_set_style(instance.get_real_instance().id, _sld_file)
else:
geoserver_create_style(instance.get_real_instance().id, instance.get_real_instance().name, _sld_file, _tempdir)
except Exception as e:
logger.exception(e)
return None
return instance

def set_time_info(self, method: str, uuid: str, /, instance: ResourceBase = None, **kwargs) -> ResourceBase:
instance = instance or ResourceManager._get_instance(uuid)

if instance and isinstance(instance.get_real_instance(), Layer):
try:
if kwargs.get('time_info', None):
set_time_info(instance.get_real_instance(), kwargs['time_info'])
except Exception as e:
logger.exception(e)
return None
return instance

0 comments on commit 347628c

Please sign in to comment.