Skip to content

Commit

Permalink
[Backport][Fixes #7787] Replace layer_thumbnail method with new API v…
Browse files Browse the repository at this point in the history
…2 endpoint #7791 (#7797)

* [Backport Resolves #7392] Fix upload/replace/append layer

* [Fixes #7787] Replace layer_thumbnail method with new API v2 endpoint
  • Loading branch information
mattiagiupponi authored Jul 14, 2021
1 parent 09297ce commit 17f80ce
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 43 deletions.
68 changes: 68 additions & 0 deletions geonode/layers/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#########################################################################
import django
import logging
import sys
from unittest.mock import patch

from django.urls import reverse
from django.conf.urls import url, include
Expand Down Expand Up @@ -146,3 +148,69 @@ def test_raw_HTML_stripped_properties(self):
self.assertEqual(response.data['layer']['raw_constraints_other'], "None")
self.assertEqual(response.data['layer']['raw_supplemental_information'], "No information provided í £682m")
self.assertEqual(response.data['layer']['raw_data_quality_statement'], "OK 1 2 a b")

def test_datasets_set_thumbnail_from_bbox_from_Anonymous_user_raise_permission_error(self):
"""
Given a request with Anonymous user, should raise an authentication error.
"""
dataset_id = sys.maxsize
url = reverse('layers-set-thumb-from-bbox', args=[dataset_id])
# Anonymous
expected = {
"detail": "Authentication credentials were not provided."
}
response = self.client.post(url, format='json')
self.assertEqual(response.status_code, 403)
self.assertEqual(expected, response.json())

@patch("geonode.layers.api.views.create_thumbnail")
def test_datasets_set_thumbnail_from_bbox_from_logged_user_for_existing_layer(self, mock_create_thumbnail):
"""
Given a logged User and an existing dataset, should create the expected thumbnail url.
"""
mock_create_thumbnail.return_value = "http://localhost:8000/mocked_url.jpg"
# Admin
self.client.login(username="admin", password="admin")
layer_id = Layer.objects.first().resourcebase_ptr_id
url = reverse('layers-set-thumb-from-bbox', args=[layer_id])
payload = {
"bbox": [
-9072629.904175375,
-9043966.018568434,
1491839.8773032012,
1507127.2829602365
],
"srid": "EPSG:3857"
}
response = self.client.post(url, data=payload, format='json')

expected = {
"thumbnail_url": "http://localhost:8000/mocked_url.jpg"
}
self.assertEqual(response.status_code, 200)
self.assertEqual(expected, response.json())

def test_datasets_set_thumbnail_from_bbox_from_logged_user_for_not_existing_layer(self):
"""
Given a logged User and an not existing dataset, should raise a 404 error.
"""
# Admin
self.client.login(username="admin", password="admin")
dataset_id = sys.maxsize
url = reverse('layers-set-thumb-from-bbox', args=[dataset_id])
payload = {
"bbox": [
-9072629.904175375,
-9043966.018568434,
1491839.8773032012,
1507127.2829602365
],
"srid": "EPSG:3857"
}
response = self.client.post(url, data=payload, format='json')

expected = {
"message": f"Dataset selected with id {dataset_id} does not exists"
}
self.assertEqual(response.status_code, 404)
self.assertEqual(expected, response.json())
36 changes: 35 additions & 1 deletion geonode/layers/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
from geonode.thumbs.thumbnails import create_thumbnail
import json
from drf_spectacular.utils import extend_schema
from dynamic_rest.viewsets import DynamicModelViewSet
from dynamic_rest.filters import DynamicFilterBackend, DynamicSortingFilter
from rest_framework.decorators import action

from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from oauth2_provider.contrib.rest_framework import OAuth2Authentication
from rest_framework.response import Response

from geonode.base.api.filters import DynamicSearchFilter, ExtentFilter
from geonode.base.api.permissions import IsOwnerOrReadOnly
Expand All @@ -33,6 +38,7 @@
from .permissions import LayerPermissionsFilter

import logging
import ast

logger = logging.getLogger(__name__)

Expand All @@ -50,3 +56,31 @@ class LayerViewSet(DynamicModelViewSet):
queryset = Layer.objects.all()
serializer_class = LayerSerializer
pagination_class = GeoNodeApiPagination

@extend_schema(
methods=["post"], responses={200}, description="API endpoint allowing to set the thumbnail url for an existing dataset."
)
@action(
detail=False,
url_path="(?P<dataset_id>\d+)/set_thumbnail_from_bbox", # noqa
url_name="set-thumb-from-bbox",
methods=["post"],
permission_classes=[
IsAuthenticated,
],
)
def set_thumbnail_from_bbox(self, request, dataset_id):
try:
layer = Layer.objects.get(resourcebase_ptr_id=ast.literal_eval(dataset_id))
request_body = request.data if request.data else json.loads(request.body)
bbox = request_body["bbox"] + [request_body["srid"]]
zoom = request_body.get("zoom", None)

thumbnail_url = create_thumbnail(layer, bbox=bbox, background_zoom=zoom, overwrite=True)
return Response({"thumbnail_url": thumbnail_url}, status=200)
except Layer.DoesNotExist:
logger.error(f"Dataset selected with id {dataset_id} does not exists")
return Response(data={"message": f"Dataset selected with id {dataset_id} does not exists"}, status=404, exception=True)
except Exception as e:
logger.error(e)
return Response(data={"message": e.args[0]}, status=500, exception=True)
2 changes: 1 addition & 1 deletion geonode/layers/templates/layers/layer_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
{% endif %}
<script type="text/javascript">
// this is used by thumbnail.js to POST to the thumbnail update view
window.thumbnailUpdateUrl = '{% url 'layer_thumbnail' resource.alternate %}';
window.thumbnailUpdateUrl = '{% url 'layers-set-thumb-from-bbox' resource.id %}';
</script>
<script type="text/javascript" src="{% static "geonode/js/utils/thumbnail.js" %}"></script>
{% get_layer_detail %}
Expand Down
2 changes: 1 addition & 1 deletion geonode/layers/templates/layouts/panels.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% load floppyforms %}
<script type="text/javascript">
// this is used by thumbnail.js to POST to the thumbnail update view
window.thumbnailUpdateUrl = '{% url 'layer_thumbnail' resource.alternate %}';
window.thumbnailUpdateUrl = '{% url 'layers-set-thumb-from-bbox' resource.id %}';
</script>
<!--<link href="{% static "lib/css/bootstrap-select.css" %}" rel="stylesheet" />-->
<script type="text/javascript" src="{% static "geonode/js/utils/thumbnail.js" %}"></script>
Expand Down
2 changes: 0 additions & 2 deletions geonode/layers/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@
views.layer_replace, name="layer_replace"),
url(r'^(?P<layername>[^/]*)/append$',
views.layer_append, name="layer_append"),
url(r'^(?P<layername>[^/]*)/thumbnail$',
views.layer_thumbnail, name='layer_thumbnail'),
url(r'^(?P<layername>[^/]*)/get$', views.get_layer, name='get_layer'),
url(r'^(?P<layername>[^/]*)/metadata_detail$',
views.layer_metadata_detail, name='layer_metadata_detail'),
Expand Down
36 changes: 0 additions & 36 deletions geonode/layers/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,11 @@
from django.template.response import TemplateResponse
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators.http import require_http_methods
from django.views.decorators.clickjacking import xframe_options_exempt

from guardian.shortcuts import get_objects_for_user

from geonode import geoserver
from geonode.thumbs.thumbnails import create_thumbnail
from geonode.base.auth import get_or_create_token
from geonode.base.forms import CategoryForm, TKeywordForm, BatchPermissionsForm, ThesaurusAvailableForm
from geonode.base.views import batch_modify, get_url_for_model
Expand Down Expand Up @@ -1477,40 +1475,6 @@ def layer_granule_remove(
return HttpResponse("Not allowed", status=403)


@require_http_methods(["POST"])
def layer_thumbnail(request, layername):
try:
layer_obj = _resolve_layer(request, layername)
except PermissionDenied:
return HttpResponse(_("Not allowed"), status=403)
except Exception:
raise Http404(_("Not found"))
if not layer_obj:
raise Http404(_("Not found"))

try:
request_body = json.loads(request.body)
bbox = request_body['bbox'] + [request_body['srid']]
zoom = request_body.get('zoom', None)

create_thumbnail(
layer_obj,
bbox=bbox,
background_zoom=zoom,
overwrite=True
)

return HttpResponse('Thumbnail saved')

except Exception as e:
logger.exception(e)
return HttpResponse(
content=_('couldn\'t generate thumbnail: %s' % str(e)),
status=500,
content_type='text/plain'
)


def get_layer(request, layername):
"""Get Layer object as JSON"""

Expand Down
3 changes: 2 additions & 1 deletion geonode/static/geonode/js/utils/thumbnail.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var createMapThumbnail = function(obj_id) {
$.ajax({
type: "POST",
url: thumbnailUpdateUrl,
contentType: "application/json",
data: JSON.stringify(body),
async: true,
cache: false,
Expand All @@ -51,7 +52,7 @@ var createMapThumbnail = function(obj_id) {
success: function (data, status, jqXHR) {
try {
$("#_thumbnail_feedbacks").find('.modal-title').text(status);
$("#_thumbnail_feedbacks").find('.modal-body').text(data);
$("#_thumbnail_feedbacks").find('.modal-body').text("Thumbnail saved");
$("#_thumbnail_feedbacks").modal("show");
} catch (err) {
console.log(err);
Expand Down
4 changes: 3 additions & 1 deletion geonode/thumbs/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from geonode.layers.utils import file_upload
from geonode.decorators import on_ogc_backend
from geonode.maps.models import Map
from geonode.layers.models import Layer
from geonode.utils import http_client, DisableDjangoSignals
from geonode.tests.base import GeoNodeBaseTestSupport, GeoNodeBaseSimpleTestSupport
from geonode.thumbs.thumbnails import create_gs_thumbnail_geonode, create_thumbnail
Expand Down Expand Up @@ -564,7 +565,8 @@ def test_layer_custom_thumbs(self):
]

self.client.login(username="norman", password="norman")
thumbnail_post_url = reverse("layer_thumbnail", kwargs={"layername": self.layer_coast_line.alternate})
dataset_id = Layer.objects.get(alternate="geonode:san_andres_y_providencia_coastline").resourcebase_ptr_id
thumbnail_post_url = reverse('layers-set-thumb-from-bbox', args=[dataset_id])

for bbox, expected_thumb_path in zip(bboxes, expected_thumbs_paths):
response = self.client.post(
Expand Down
1 change: 1 addition & 0 deletions geonode/thumbs/thumbnails.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ def create_thumbnail(

# save thumbnail
instance.save_thumbnail(default_thumbnail_name, image=content)
return instance.thumbnail_url


def _generate_thumbnail_name(instance: Union[Layer, Map]) -> Optional[str]:
Expand Down

0 comments on commit 17f80ce

Please sign in to comment.