69 changes: 44 additions & 25 deletions geonode/layers/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,41 +61,59 @@
from django.db import transaction
from django.db.models import F
from django.forms.utils import ErrorList
from geonode.services.models import Service
from geonode.layers.forms import LayerForm, LayerUploadForm, NewLayerUploadForm, LayerAttributeForm

from geonode.base.auth import get_or_create_token
from geonode.base.forms import CategoryForm, TKeywordForm
from geonode.layers.models import Layer, Attribute, UploadSession
from geonode.base.views import batch_modify
from geonode.base.models import (
Thesaurus,
TopicCategory)
from geonode.base.enumerations import CHARSETS
from geonode.base.models import TopicCategory
from geonode.groups.models import GroupProfile

from geonode.utils import (resolve_object,
default_map_config,
check_ogc_backend,
llbbox_to_mercator,
bbox_to_projection,
GXPLayer,
GXPMap)
from geonode.layers.utils import file_upload, is_raster, is_vector
from geonode.people.forms import ProfileForm, PocForm
from geonode.security.views import _perms_info_json
from geonode.documents.models import get_related_documents
from geonode.utils import build_social_links
from geonode.base.views import batch_modify
from geonode.base.models import Thesaurus
from geonode.layers.forms import (
LayerForm,
LayerUploadForm,
NewLayerUploadForm,
LayerAttributeForm)
from geonode.layers.models import (
Layer,
Attribute,
UploadSession)
from geonode.layers.utils import (
file_upload,
is_raster,
is_vector)

from geonode.maps.models import Map
from geonode.services.models import Service
from geonode.monitoring import register_event
from geonode.geoserver.helpers import (gs_catalog,
ogc_server_settings,
set_layer_style) # cascading_delete
from geonode.groups.models import GroupProfile
from geonode.security.views import _perms_info_json
from geonode.people.forms import ProfileForm, PocForm
from geonode.documents.models import get_related_documents

from geonode.utils import (
resolve_object,
default_map_config,
check_ogc_backend,
llbbox_to_mercator,
bbox_to_projection,
build_social_links,
GXPLayer,
GXPMap)

from .tasks import delete_layer

from geonode.geoserver.helpers import (ogc_server_settings,
set_layer_style) # cascading_delete

if check_ogc_backend(geoserver.BACKEND_PACKAGE):
from geonode.geoserver.helpers import (_render_thumbnail,
_prepare_thumbnail_body_from_opts)
_prepare_thumbnail_body_from_opts,
gs_catalog)
if check_ogc_backend(qgis_server.BACKEND_PACKAGE):
from geonode.qgis_server.models import QGISServerLayer

CONTEXT_LOG_FILE = ogc_server_settings.LOG_FILE

logger = logging.getLogger("geonode.layers.views")
Expand Down Expand Up @@ -1292,6 +1310,7 @@ def layer_replace(request, layername, template='layers/layer_replace.html'):

saved_layer = file_upload(
base_file,
layer=layer,
title=layer.title,
abstract=layer.abstract,
is_approved=layer.is_approved,
Expand All @@ -1307,15 +1326,15 @@ def layer_replace(request, layername, template='layers/layer_replace.html'):
overwrite=True,
charset=form.cleaned_data["charset"],
)

out['success'] = True
out['url'] = reverse(
'layer_detail', args=[
saved_layer.service_typename])
except BaseException as e:
logger.exception(e)
tb = traceback.format_exc()
out['success'] = False
out['errors'] = str(tb)
out['errors'] = str(e)
finally:
if tempdir is not None:
shutil.rmtree(tempdir)
Expand Down
20 changes: 18 additions & 2 deletions geonode/static/geonode/js/upload/LayerInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -609,9 +609,25 @@ define(function (require, exports) {
if(jqXHR.status === 500 || jqXHR.status === 0 || jqXHR.readyState === 0){
self.markError('Server Error: ' + jqXHR.statusText + gettext('<br>Please check your network connection. In case of Layer Upload make sure GeoServer is running and accepting connections.'));
} else if (jqXHR.status === 400 || jqXHR.status === 404) {
self.markError('Client Error: ' + jqXHR.statusText + gettext('<br>Bad request or URL not found.'));
if (jqXHR.responseJSON !== undefined && jqXHR.responseJSON !== null) {
if (jqXHR.responseJSON.errors !== undefined) {
self.markError('Client Error: ' + jqXHR.statusText + gettext('<br>' + jqXHR.responseJSON.errors));
}
} else if (jqXHR.responseText !== undefined && jqXHR.responseText !== null) {
self.markError('Client Error: ' + jqXHR.statusText + gettext('<br>' + jqXHR.responseText));
} else {
self.markError('Client Error: ' + jqXHR.statusText + gettext('<br>Bad request or URL not found.'));
}
} else {
self.markError(gettext('Unexpected Error'));
if (jqXHR.responseJSON !== undefined && jqXHR.responseJSON !== null) {
if (jqXHR.responseJSON.errors !== undefined) {
self.markError('Unexpected Error: ' + jqXHR.statusText + gettext('<br>' + jqXHR.responseJSON.errors));
}
} else if (jqXHR.responseText !== undefined && jqXHR.responseText !== null) {
self.markError('Unexpected Error: ' + jqXHR.statusText + gettext('<br>' + jqXHR.responseText));
} else {
self.markError('Unexpected Error: ' + jqXHR.statusText + gettext('<br>Unknown.'));
}
}

callback(array);
Expand Down
81 changes: 52 additions & 29 deletions geonode/tests/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,15 +413,9 @@ def test_extension_not_implemented(self):
"""
sampletxt = os.path.join(gisdata.VECTOR_DATA,
'points_epsg2249_no_prj.dbf')
try:
with self.\
assertRaisesRegexp(Exception, "You are attempting to replace a vector layer with an unknown format."):
file_upload(sampletxt)
except GeoNodeException:
pass
except Exception:
raise
# msg = ('Was expecting a %s, got %s instead.' %
# (GeoNodeException, type(e)))
# assert e is GeoNodeException, msg

@timeout_decorator.timeout(LOCAL_TIMEOUT)
def test_layer_upload_metadata(self):
Expand Down Expand Up @@ -1025,35 +1019,64 @@ def test_layer_replace(self):
response_dict['errors']:
pass
else:
self.assertEquals(response.status_code, 200)
self.assertEquals(response_dict['success'], True)
# Get a Layer object for the newly created layer.
new_vector_layer = Layer.objects.get(pk=vector_layer.pk)

# Test the replaced layer metadata is equal to the original layer
self.assertEqual(vector_layer.name, new_vector_layer.name)
self.assertEqual(vector_layer.title, new_vector_layer.title)
self.assertEqual(vector_layer.alternate, new_vector_layer.alternate)

# Test the replaced layer bbox is indeed different from the original layer
self.assertNotEqual(vector_layer.bbox_x0, new_vector_layer.bbox_x0)
self.assertNotEqual(vector_layer.bbox_x1, new_vector_layer.bbox_x1)
self.assertNotEqual(vector_layer.bbox_y0, new_vector_layer.bbox_y0)
self.assertNotEqual(vector_layer.bbox_y1, new_vector_layer.bbox_y1)

# test an invalid user without layer replace permission
self.client.logout()
self.client.login(username='norman', password='norman')
self.assertEquals(response.status_code, 400)
self.assertEquals(response_dict['success'], False)

if check_ogc_backend(geoserver.BACKEND_PACKAGE):
# test replace a vector with an updated version of the vector file
new_vector_file = os.path.join(
gisdata.VECTOR_DATA,
'san_andres_y_providencia_administrative.shp')
layer_path, __ = os.path.splitext(new_vector_file)
layer_base = open(layer_path + '.shp', 'rb')
layer_dbf = open(layer_path + '.dbf', 'rb')
layer_shx = open(layer_path + '.shx', 'rb')
layer_prj = open(layer_path + '.prj', 'rb')

response = self.client.post(
vector_replace_url,
{'base_file': layer_base,
'dbf_file': layer_dbf,
'shx_file': layer_shx,
'prj_file': layer_prj,
'charset': 'UTF-8',
'permissions': json.dumps(post_permissions)
})
self.assertTrue(response.status_code in (401, 403))
})
response_dict = json.loads(response.content)

if not response_dict['success'] and 'unknown encoding' in \
response_dict['errors']:
pass
else:
self.assertEquals(response.status_code, 200)
self.assertEquals(response_dict['success'], True)
# Get a Layer object for the newly created layer.
new_vector_layer = Layer.objects.get(pk=vector_layer.pk)

# Test the replaced layer metadata is equal to the original layer
self.assertEqual(vector_layer.name, new_vector_layer.name)
self.assertEqual(vector_layer.title, new_vector_layer.title)
self.assertEqual(vector_layer.alternate, new_vector_layer.alternate)

# Test the replaced layer bbox is indeed different from the original layer
self.assertEqual(vector_layer.bbox_x0, new_vector_layer.bbox_x0)
self.assertEqual(vector_layer.bbox_x1, new_vector_layer.bbox_x1)
self.assertEqual(vector_layer.bbox_y0, new_vector_layer.bbox_y0)
self.assertEqual(vector_layer.bbox_y1, new_vector_layer.bbox_y1)

# test an invalid user without layer replace permission
self.client.logout()
self.client.login(username='norman', password='norman')

response = self.client.post(
vector_replace_url,
{'base_file': layer_base,
'dbf_file': layer_dbf,
'shx_file': layer_shx,
'prj_file': layer_prj,
'permissions': json.dumps(post_permissions)
})
self.assertTrue(response.status_code in (401, 403))
finally:
# Clean up and completely delete the layer
try:
Expand Down
41 changes: 26 additions & 15 deletions geonode/upload/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import json
import logging
import zipfile
import tempfile
import traceback

from osgeo import ogr
Expand Down Expand Up @@ -504,24 +505,34 @@ def filter_name(b):
return att_list


def _fixup_base_file(absolute_base_file, tempdir=None):
if not tempdir:
tempdir = tempfile.mkdtemp()
if not os.path.isfile(absolute_base_file):
tmp_files = [f for f in os.listdir(tempdir) if os.path.isfile(os.path.join(tempdir, f))]
for f in tmp_files:
if zipfile.is_zipfile(os.path.join(tempdir, f)):
absolute_base_file = unzip_file(os.path.join(tempdir, f), '.shp', tempdir=tempdir)
absolute_base_file = os.path.join(tempdir,
absolute_base_file)
elif zipfile.is_zipfile(absolute_base_file):
absolute_base_file = unzip_file(absolute_base_file,
'.shp', tempdir=tempdir)
absolute_base_file = os.path.join(tempdir,
absolute_base_file)
if os.path.exists(absolute_base_file):
return absolute_base_file
else:
raise Exception(_('File does not exist: %s' % absolute_base_file))


def _get_layer_values(layer, upload_session, expand=0):
layer_values = []
if upload_session:
absolute_base_file = upload_session.base_file[0].base_file
tempdir = upload_session.tempdir

if not os.path.isfile(absolute_base_file):
tmp_files = [f for f in os.listdir(tempdir) if os.path.isfile(os.path.join(tempdir, f))]
for f in tmp_files:
if zipfile.is_zipfile(os.path.join(tempdir, f)):
absolute_base_file = unzip_file(os.path.join(tempdir, f), '.shp', tempdir=tempdir)
absolute_base_file = os.path.join(tempdir,
absolute_base_file)
elif zipfile.is_zipfile(absolute_base_file):
absolute_base_file = unzip_file(upload_session.base_file[0].base_file,
'.shp', tempdir=tempdir)
absolute_base_file = os.path.join(tempdir,
absolute_base_file)
absolute_base_file = _fixup_base_file(
upload_session.base_file[0].base_file,
upload_session.tempdir)

inDataSource = ogr.Open(absolute_base_file)
lyr = inDataSource.GetLayer(str(layer.name))
limit = 100
Expand Down