diff --git a/qgis-app/base/views/processing_view.py b/qgis-app/base/views/processing_view.py index c0fcbde3..8f2ff97d 100644 --- a/qgis-app/base/views/processing_view.py +++ b/qgis-app/base/views/processing_view.py @@ -28,6 +28,7 @@ View, ) from django.views.generic.base import ContextMixin +from django.utils.encoding import escape_uri_path GROUP_NAME = "Style Managers" @@ -484,9 +485,8 @@ def get(self, request, *args, **kwargs): response = HttpResponse( zipfile.getvalue(), content_type="application/x-zip-compressed" ) - response["Content-Disposition"] = "attachment; filename=%s.zip" % ( - slugify(object.name, allow_unicode=True) - ) + zip_name = slugify(object.name, allow_unicode=True) + response["Content-Disposition"] = f"attachment; filename*=utf-8''{escape_uri_path(zip_name)}.zip" return response diff --git "a/qgis-app/styles/tests/stylefiles/\344\270\211\350\260\203\347\254\246\345\217\267\345\272\223.xml" "b/qgis-app/styles/tests/stylefiles/\344\270\211\350\260\203\347\254\246\345\217\267\345\272\223.xml" new file mode 100644 index 00000000..61483af6 --- /dev/null +++ "b/qgis-app/styles/tests/stylefiles/\344\270\211\350\260\203\347\254\246\345\217\267\345\272\223.xml" @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/qgis-app/styles/tests/test_views.py b/qgis-app/styles/tests/test_views.py index 545acda7..35a1cbac 100644 --- a/qgis-app/styles/tests/test_views.py +++ b/qgis-app/styles/tests/test_views.py @@ -8,6 +8,9 @@ from django.test import Client, TestCase, override_settings from django.urls import reverse from styles.models import Style, StyleType +from django.utils.text import slugify +from django.utils.encoding import escape_uri_path + STYLE_DIR = os.path.join(os.path.dirname(__file__), "stylefiles") @@ -274,6 +277,18 @@ def setUp(self): approved=True, ) + self.newstyle_non_ascii = Style.objects.create( + pk=2, + creator=User.objects.get(pk=2), + style_type=StyleType.objects.get(pk=1), + name="三调符号库", + description="This file is saved in styles/tests/stylefiles folder", + thumbnail_image="thumbnail.png", + file="三调符号库.xml", + download_count=0, + approved=True, + ) + @override_settings(MEDIA_ROOT="styles/tests/stylefiles/") def test_anonymous_user_download(self): style = Style.objects.get(pk=1) @@ -286,6 +301,27 @@ def test_anonymous_user_download(self): style = Style.objects.get(pk=1) self.assertEqual(style.download_count, 1) + @override_settings(MEDIA_ROOT="styles/tests/stylefiles/") + def test_non_ascii_name_download(self): + style = Style.objects.get(pk=2) + self.assertEqual(style.download_count, 0) + self.client.logout() + url = reverse("style_download", kwargs={"pk": 2}) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + + # Check if the Content-Disposition header is present in the response + self.assertTrue('Content-Disposition' in response) + + style_name = escape_uri_path(slugify(style.name, allow_unicode=True)) + # Extract the filename from the Content-Disposition header + content_disposition = response['Content-Disposition'] + _, params = content_disposition.split(';') + downloaded_filename = params.split('=')[1].strip(' "').split("utf-8''")[1] + + # Check if the downloaded filename matches the original filename + self.assertEqual(downloaded_filename, f"{style_name}.zip") + class TestStyleApprovalNotify(TestCase): fixtures = [ diff --git a/qgis-app/styles/views.py b/qgis-app/styles/views.py index 57af8249..84cfb874 100644 --- a/qgis-app/styles/views.py +++ b/qgis-app/styles/views.py @@ -148,7 +148,7 @@ class StyleReviewView(ResourceMixin, ResourceBaseReviewView): class StyleDownloadView(ResourceMixin, ResourceBaseDownload): - """Download a GeoPackage""" + """Download a style""" def style_nav_content(request):