Skip to content

Commit

Permalink
[Backport 3.2.x][Fixes #8312] Thumbnails filenames or URLs should alw…
Browse files Browse the repository at this point in the history
…ays change when generetad to avoid browser caching

(cherry picked from commit edc2d28)
  • Loading branch information
afabiani committed Nov 29, 2021
1 parent 240cd5b commit e0c851f
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 63 deletions.
11 changes: 6 additions & 5 deletions geonode/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,6 @@
send_notification,
get_notification_recipients)
from geonode.people.enumerations import ROLE_VALUES
from geonode.base.thumb_utils import (
thumb_path,
thumb_size,
remove_thumbs)

from pyproj import transform, Proj

Expand Down Expand Up @@ -1566,7 +1562,12 @@ def has_thumbnail(self):
# Note - you should probably broadcast layer#post_save() events to ensure
# that indexing (or other listeners) are notified
def save_thumbnail(self, filename, image):
upload_path = thumb_path(filename)
from geonode.thumbs.utils import (
get_unique_upload_path,
thumb_path,
thumb_size,
remove_thumbs)
upload_path = get_unique_upload_path(self, filename)

try:
# Check that the image is valid
Expand Down
2 changes: 1 addition & 1 deletion geonode/base/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from geonode.maps.models import Map
from geonode.services.models import Service
from geonode.tests.base import GeoNodeBaseTestSupport
from geonode.base import thumb_utils
from geonode.thumbs import utils as thumb_utils
from geonode.base.models import (
ResourceBase,
MenuPlaceholder,
Expand Down
50 changes: 0 additions & 50 deletions geonode/base/thumb_utils.py

This file was deleted.

4 changes: 2 additions & 2 deletions geonode/base/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

from geonode.layers.models import Layer
from geonode.base.models import ResourceBase, Link, Configuration
from geonode.base.thumb_utils import (
from geonode.thumbs.utils import (
get_thumbs,
remove_thumb)
from geonode.utils import get_legend_url
Expand All @@ -51,7 +51,7 @@
'Dublin Core', 'ebRIM', 'FGDC', 'ISO', 'ISO with XSL']

thumb_filename_regex = re.compile(
r"^(document|map|layer)-([a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12})-thumb\.png$")
r"^(document|map|layer)-([a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12})-thumb-([a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12})\.png$")


def get_thumb_uuid(filename):
Expand Down
2 changes: 1 addition & 1 deletion geonode/documents/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from geonode.maps.models import Map
from geonode.layers.models import Layer
from geonode.compat import ensure_string
from geonode.base.thumb_utils import get_thumbs
from geonode.thumbs.utils import get_thumbs
from geonode.base.models import License, Region
from geonode.documents import DocumentsAppConfig
from geonode.documents.forms import DocumentFormMixin
Expand Down
10 changes: 10 additions & 0 deletions geonode/thumbs/tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ def test_generate_thumbnail_name_layer(self):
re.match(f"layer-{self.re_uuid}-thumb.png", layer_name, re.I), "Layer name should meet a provided pattern"
)

def test_get_unique_upload_path(self):

layer = Layer.objects.first()
thumbnail_name = thumbnails._generate_thumbnail_name(layer)
upload_path = utils.thumb_path(thumbnail_name)
new_upload_path = utils.get_unique_upload_path(layer, thumbnail_name)
self.assertNotEqual(upload_path, new_upload_path)
new_upload_path2 = utils.get_unique_upload_path(layer, thumbnail_name)
self.assertNotEqual(new_upload_path, new_upload_path2)

@patch("geonode.maps.models.Map.layers", new_callable=PropertyMock)
def test_generate_thumbnail_name_map_empty(self, layers_mock):
layers_mock.return_value = []
Expand Down
5 changes: 2 additions & 3 deletions geonode/thumbs/thumbnails.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@

from geonode.maps.models import Map, MapLayer
from geonode.layers.models import Layer
from geonode.base.thumb_utils import thumb_exists
from geonode.geoserver.helpers import OGC_Servers_Handler
from geonode.utils import get_layer_name, get_layer_workspace
from geonode.thumbs import utils
Expand Down Expand Up @@ -98,9 +97,9 @@ def create_thumbnail(
# handle custom, uploaded thumbnails, which may have different extensions from the default thumbnail
thumbnail_exists = False
if instance.thumbnail_url and instance.thumbnail_url != settings.MISSING_THUMBNAIL:
thumbnail_exists = thumb_exists(instance.thumbnail_url.rsplit('/')[-1])
thumbnail_exists = utils.thumb_exists(instance.thumbnail_url.rsplit('/')[-1])

if (thumbnail_exists or thumb_exists(default_thumbnail_name)) and not overwrite:
if (thumbnail_exists or utils.thumb_exists(default_thumbnail_name)) and not overwrite:
logger.debug(f"Thumbnail for {instance.name} already exists. Skipping thumbnail generation.")
return

Expand Down
68 changes: 67 additions & 1 deletion geonode/thumbs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################

import os
import time
import base64
import logging

from pyproj import Transformer, CRS
from owslib.wms import WebMapService
from typing import List, Tuple, Callable, Union
from uuid import uuid4

from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.staticfiles.templatetags import staticfiles
from django.core.files.storage import default_storage as storage


from geonode.maps.models import Map
from geonode.layers.models import Layer
Expand Down Expand Up @@ -308,3 +312,65 @@ def exceeds_epsg3857_area_of_use(bbox: List) -> bool:
exceeds = True

return exceeds


def thumb_path(filename):
"""Return the complete path of the provided thumbnail file accessible
via Django storage API"""
return os.path.join(settings.THUMBNAIL_LOCATION, filename)


def thumb_exists(filename):
"""Determine if a thumbnail file exists in storage"""
return storage.exists(thumb_path(filename))


def thumb_size(filepath):
"""Determine if a thumbnail file size in storage"""
if storage.exists(filepath):
return storage.size(filepath)
elif os.path.exists(filepath):
return os.path.getsize(filepath)
return 0


def thumb_open(filename):
"""Returns file handler of a thumbnail on the storage"""
return storage.open(thumb_path(filename))


def get_thumbs():
"""Fetches a list of all stored thumbnails"""
if not storage.exists(settings.THUMBNAIL_LOCATION):
return []
subdirs, thumbs = storage.listdir(settings.THUMBNAIL_LOCATION)
return thumbs


def remove_thumb(filename):
"""Delete a thumbnail from storage"""
storage.delete(thumb_path(filename))


def remove_thumbs(name):
"""Removes all stored thumbnails that start with the same name as the
file specified"""
for thumb in get_thumbs():
if thumb.startswith(name):
remove_thumb(thumb)


def get_unique_upload_path(resource, filename):
""" Generates a unique name from the given filename and
creates a unique file upload path"""
mising_thumb = staticfiles.static(settings.MISSING_THUMBNAIL)
if resource.thumbnail_url and not resource.thumbnail_url == mising_thumb:
# remove thumbnail from storage
thumb_name = os.path.basename(resource.thumbnail_url)
name, _ext = os.path.splitext(thumb_name)
remove_thumbs(name)
# create an upload path from a unique filename
filename, ext = os.path.splitext(filename)
unique_file_name = f'{filename}-{uuid4()}{ext}'
upload_path = thumb_path(unique_file_name)
return upload_path

0 comments on commit e0c851f

Please sign in to comment.