Skip to content

Commit 9c05382

Browse files
committed
Merge remote-tracking branch 'upstream/4.4.x' into 52n-4.4.x
2 parents 6dd9b8a + 0ddbdaf commit 9c05382

File tree

47 files changed

+452
-91
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+452
-91
lines changed

geonode/assets/local.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from django.http import HttpResponse, StreamingHttpResponse
88
from django.urls import reverse
99
from django_downloadview import DownloadResponse
10-
from zipstream import ZipStream, walk
10+
from zipstream import ZipStream
1111

1212
from geonode.assets.handlers import asset_handler_registry, AssetHandlerInterface, AssetDownloadHandlerInterface
1313
from geonode.assets.models import LocalAsset
@@ -261,9 +261,7 @@ def create_response(
261261
match attachment:
262262
case True:
263263
logger.info(f"Zipping file '{localfile}' with name '{orig_base}'")
264-
zs = ZipStream(sized=True)
265-
for filepath in walk(LocalAssetHandler._get_managed_dir(asset)):
266-
zs.add_path(filepath, os.path.basename(filepath))
264+
zs = ZipStream(sized=True).from_path(LocalAssetHandler._get_managed_dir(asset), arcname="/")
267265
# closing zip for all contents to be written
268266
return StreamingHttpResponse(
269267
zs,

geonode/assets/management/commands/migrate_file_to_assets.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,19 @@ def handle(self, **options):
9898

9999
logger.info("Moving file to the asset folder")
100100

101-
dest = shutil.move(source, handler._create_asset_dir())
102-
103-
logger.info("Fixing perms")
101+
if len(asset.location) == 1:
102+
# In older installations, all documents are stored in a single folder.
103+
# Instead of moving the entire folder, we can simply move the individual document.
104+
# This approach prevents the risk of breaking the other documents
105+
# that are stored in the same folder
106+
# oldpath = {MEDIA_ROOT}/documents/document/file.extension
107+
dest = shutil.move(asset.location[0], handler._create_asset_dir())
108+
else:
109+
dest = shutil.move(source, handler._create_asset_dir())
110+
111+
logger.info(f"New destination path: {dest}")
112+
113+
logger.info("Fixing file/folder perms if required")
104114
if settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS is not None:
105115
os.chmod(os.path.dirname(dest), settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS)
106116

@@ -113,7 +123,10 @@ def handle(self, **options):
113123

114124
logger.info("Updating location field with new folder value")
115125

116-
asset.location = [x.replace(source, dest) for x in asset.location]
126+
if len(asset.location) == 1:
127+
asset.location = [dest]
128+
else:
129+
asset.location = [x.replace(source, dest) for x in asset.location]
117130
asset.save()
118131

119132
logger.info("Checking if geoserver should be updated")

geonode/base/api/tests.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from django.contrib.auth import get_user_model
4343

4444
from owslib.etree import etree
45+
from avatar.templatetags.avatar_tags import avatar_url
4546

4647
from rest_framework.test import APITestCase
4748
from rest_framework.renderers import JSONRenderer
@@ -1045,13 +1046,13 @@ def test_perms_resources(self):
10451046
"username": bobby.username,
10461047
"first_name": bobby.first_name,
10471048
"last_name": bobby.last_name,
1048-
"avatar": "https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e/?s=240",
1049+
"avatar": build_absolute_uri(avatar_url(bobby)),
10491050
"permissions": "owner",
10501051
"is_staff": False,
10511052
"is_superuser": False,
10521053
},
10531054
{
1054-
"avatar": "https://www.gravatar.com/avatar/7a68c67c8d409ff07e42aa5d5ab7b765/?s=240",
1055+
"avatar": build_absolute_uri(avatar_url(bobby)),
10551056
"first_name": "admin",
10561057
"id": 1,
10571058
"last_name": "",
@@ -1126,7 +1127,7 @@ def test_perms_resources(self):
11261127
"username": bobby.username,
11271128
"first_name": bobby.first_name,
11281129
"last_name": bobby.last_name,
1129-
"avatar": "https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e/?s=240",
1130+
"avatar": build_absolute_uri(avatar_url(bobby)),
11301131
"permissions": "owner",
11311132
"is_staff": False,
11321133
"is_superuser": False,
@@ -1136,13 +1137,13 @@ def test_perms_resources(self):
11361137
"username": norman.username,
11371138
"first_name": norman.first_name,
11381139
"last_name": norman.last_name,
1139-
"avatar": "https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e/?s=240",
1140+
"avatar": build_absolute_uri(avatar_url(bobby)),
11401141
"permissions": "edit",
11411142
"is_staff": False,
11421143
"is_superuser": False,
11431144
},
11441145
{
1145-
"avatar": "https://www.gravatar.com/avatar/7a68c67c8d409ff07e42aa5d5ab7b765/?s=240",
1146+
"avatar": build_absolute_uri(avatar_url(bobby)),
11461147
"first_name": "admin",
11471148
"id": 1,
11481149
"last_name": "",
@@ -1175,13 +1176,13 @@ def test_perms_resources(self):
11751176
"username": bobby.username,
11761177
"first_name": bobby.first_name,
11771178
"last_name": bobby.last_name,
1178-
"avatar": "https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e/?s=240",
1179+
"avatar": build_absolute_uri(avatar_url(bobby)),
11791180
"permissions": "owner",
11801181
"is_staff": False,
11811182
"is_superuser": False,
11821183
},
11831184
{
1184-
"avatar": "https://www.gravatar.com/avatar/7a68c67c8d409ff07e42aa5d5ab7b765/?s=240",
1185+
"avatar": build_absolute_uri(avatar_url(bobby)),
11851186
"first_name": "admin",
11861187
"id": 1,
11871188
"last_name": "",
@@ -1238,13 +1239,13 @@ def test_perms_resources(self):
12381239
"username": bobby.username,
12391240
"first_name": bobby.first_name,
12401241
"last_name": bobby.last_name,
1241-
"avatar": "https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e/?s=240",
1242+
"avatar": build_absolute_uri(avatar_url(bobby)),
12421243
"permissions": "owner",
12431244
"is_staff": False,
12441245
"is_superuser": False,
12451246
},
12461247
{
1247-
"avatar": "https://www.gravatar.com/avatar/7a68c67c8d409ff07e42aa5d5ab7b765/?s=240",
1248+
"avatar": build_absolute_uri(avatar_url(bobby)),
12481249
"first_name": "admin",
12491250
"id": 1,
12501251
"last_name": "",
@@ -2171,7 +2172,7 @@ def test_manager_can_edit_map(self):
21712172
"username": "bobby",
21722173
"first_name": "bobby",
21732174
"last_name": "",
2174-
"avatar": "https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e/?s=240",
2175+
"avatar": build_absolute_uri(avatar_url(bobby)),
21752176
"permissions": "manage",
21762177
"is_superuser": False,
21772178
"is_staff": False,
@@ -2181,7 +2182,7 @@ def test_manager_can_edit_map(self):
21812182
"username": "admin",
21822183
"first_name": "admin",
21832184
"last_name": "",
2184-
"avatar": "https://www.gravatar.com/avatar/7a68c67c8d409ff07e42aa5d5ab7b765/?s=240",
2185+
"avatar": build_absolute_uri(avatar_url(bobby)),
21852186
"permissions": "owner",
21862187
"is_superuser": True,
21872188
"is_staff": True,
@@ -2212,7 +2213,7 @@ def test_manager_can_edit_map(self):
22122213
"username": "bobby",
22132214
"first_name": "bobby",
22142215
"last_name": "",
2215-
"avatar": "https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e/?s=240",
2216+
"avatar": build_absolute_uri(avatar_url(bobby)),
22162217
"permissions": "manage",
22172218
"is_staff": False,
22182219
"is_superuser": False,
@@ -2222,7 +2223,7 @@ def test_manager_can_edit_map(self):
22222223
"username": "admin",
22232224
"first_name": "admin",
22242225
"last_name": "",
2225-
"avatar": "https://www.gravatar.com/avatar/7a68c67c8d409ff07e42aa5d5ab7b765/?s=240",
2226+
"avatar": build_absolute_uri(avatar_url(bobby)),
22262227
"permissions": "owner",
22272228
"is_staff": True,
22282229
"is_superuser": True,
@@ -2251,7 +2252,7 @@ def test_manager_can_edit_map(self):
22512252
"username": "bobby",
22522253
"first_name": "bobby",
22532254
"last_name": "",
2254-
"avatar": "https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e/?s=240",
2255+
"avatar": build_absolute_uri(avatar_url(bobby)),
22552256
"permissions": "manage",
22562257
"is_staff": False,
22572258
"is_superuser": False,
@@ -2261,7 +2262,7 @@ def test_manager_can_edit_map(self):
22612262
"username": "admin",
22622263
"first_name": "admin",
22632264
"last_name": "",
2264-
"avatar": "https://www.gravatar.com/avatar/7a68c67c8d409ff07e42aa5d5ab7b765/?s=240",
2265+
"avatar": build_absolute_uri(avatar_url(bobby)),
22652266
"permissions": "owner",
22662267
"is_staff": True,
22672268
"is_superuser": True,

geonode/base/forms.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ def _get_thesauro_keyword_label(item, lang):
343343

344344
@staticmethod
345345
def _get_thesauro_title_label(item, lang):
346+
lang = remove_country_from_languagecode(lang)
346347
tname = ThesaurusLabel.objects.values_list("label", flat=True).filter(thesaurus=item).filter(lang=lang)
347348
if not tname:
348349
return Thesaurus.objects.get(id=item.id).title

geonode/base/tests.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from unittest.mock import patch, Mock
2828
from guardian.shortcuts import assign_perm
2929

30+
from django.utils.module_loading import import_string
3031
from django.db.utils import IntegrityError, OperationalError
3132
from django.core.exceptions import ObjectDoesNotExist
3233
from django.conf import settings
@@ -57,6 +58,8 @@
5758
HierarchicalKeyword,
5859
ResourceBase,
5960
MenuPlaceholder,
61+
License,
62+
Group,
6063
Menu,
6164
MenuItem,
6265
Configuration,
@@ -1244,6 +1247,14 @@ def test_keyword_raise_db_error(self, add_root_mocked):
12441247
)
12451248

12461249

1250+
def _cache_less_call_storers(instance, custom={}):
1251+
storer_module_path = settings.METADATA_STORERS if hasattr(settings, "METADATA_STORERS") else []
1252+
storers = [import_string(storer_path) for storer_path in storer_module_path]
1253+
for storer in storers:
1254+
storer(instance, custom)
1255+
return instance
1256+
1257+
12471258
class TestRegions(GeoNodeBaseTestSupport):
12481259
def setUp(self):
12491260
self.dataset_inside_region = GEOSGeometry(
@@ -1281,16 +1292,38 @@ def test_region_assignment_for_extent(self):
12811292
region.is_assignable_to_geom(self.dataset_outside_region), "Extent outside a region should be assigned"
12821293
)
12831294

1284-
@override_settings(METADATA_STORERS=["geonode.resource.regions_storer.spatial_predicate_region_assignor"])
1295+
@patch("geonode.resource.utils.call_storers", _cache_less_call_storers)
12851296
def test_regions_are_assigned_if_handler_is_used(self):
1286-
dataset = resource_manager.create(
1287-
None,
1288-
resource_type=Dataset,
1289-
defaults=dict(owner=get_user_model().objects.first(), title="test_region_dataset", is_approved=True),
1290-
)
1291-
self.assertTrue(dataset.regions.exists())
1292-
self.assertEqual(1, dataset.regions.count())
1293-
self.assertEqual("Global", dataset.regions.first().name)
1297+
with override_settings(METADATA_STORERS=["geonode.resource.regions_storer.spatial_predicate_region_assignor"]):
1298+
dataset = resource_manager.create(
1299+
None,
1300+
resource_type=Dataset,
1301+
defaults=dict(owner=get_user_model().objects.first(), title="test_region_dataset", is_approved=True),
1302+
)
1303+
self.assertTrue(dataset.regions.exists())
1304+
self.assertEqual(1, dataset.regions.count())
1305+
self.assertEqual("Global", dataset.regions.first().name)
1306+
1307+
1308+
class TestMetadataStorer(GeoNodeBaseTestSupport):
1309+
1310+
@patch("geonode.resource.utils.call_storers", _cache_less_call_storers)
1311+
def test_create_passing_custom_to_post_save(self):
1312+
1313+
with override_settings(METADATA_STORERS=["geonode.resource.metadata_storer.store_metadata"]):
1314+
User = get_user_model()
1315+
user = User.objects.create(username="test", email="test@test.com")
1316+
license = License.objects.all().first()
1317+
group = Group.objects.all().first()
1318+
dataset = resource_manager.create(
1319+
str(uuid4()),
1320+
resource_type=Dataset,
1321+
defaults=dict(owner=user, title="test"),
1322+
custom=dict(group=group.pk, license=license),
1323+
)
1324+
self.assertIsNotNone(dataset.license)
1325+
self.assertIsNotNone(dataset.group)
1326+
self.assertEqual(group.pk, dataset.group.pk)
12941327

12951328

12961329
class LinkedResourcesTest(GeoNodeBaseTestSupport):

geonode/documents/admin.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,19 @@ class Meta(ResourceBaseAdminForm.Meta):
3737

3838
class DocumentAdmin(TabbedTranslationAdmin):
3939
exclude = ("ll_bbox_polygon", "bbox_polygon", "srid")
40-
list_display = ("id", "title", "date", "category", "group", "is_approved", "is_published", "metadata_completeness")
40+
list_display = (
41+
"id",
42+
"title",
43+
"date",
44+
"category",
45+
"group",
46+
"is_approved",
47+
"is_published",
48+
"advertised",
49+
"metadata_completeness",
50+
)
4151
list_display_links = ("id",)
42-
list_editable = ("title", "category", "group", "is_approved", "is_published")
52+
list_editable = ("title", "category", "group", "is_approved", "is_published", "advertised")
4353
list_filter = (
4454
"date",
4555
"date_type",

geonode/documents/forms.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def clean(self):
169169
raise forms.ValidationError(_("A document cannot have both a file and a url."))
170170

171171
if extension:
172-
cleaned_data["extension"] = extension.replace(".", "")
172+
cleaned_data["extension"] = extension.replace(".", "").lower()
173173

174174
return cleaned_data
175175

geonode/documents/tests.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
from unittest.mock import patch
3434
from urllib.parse import urlparse
35+
from pathlib import Path
3536

3637
from django.urls import reverse
3738
from django.conf import settings
@@ -42,7 +43,7 @@
4243

4344
from guardian.shortcuts import get_anonymous_user
4445

45-
from geonode.assets.utils import create_asset_and_link
46+
from geonode.assets.utils import create_asset_and_link, get_default_asset
4647
from geonode.base.forms import LinkedResourceForm
4748
from geonode.maps.models import Map
4849
from geonode.layers.models import Dataset
@@ -193,6 +194,25 @@ def test_create_document_url_view(self):
193194
d = Document.objects.get(title="GeoNode Map")
194195
self.assertEqual(d.doc_url, "http://www.geonode.org/map.pdf")
195196

197+
def test_uploaded_csv_with_uppercase_extension(self):
198+
"""
199+
The extension of the file should always be lowercase
200+
"""
201+
202+
self.client.login(username="admin", password="admin")
203+
try:
204+
with open(os.path.join(os.path.dirname(__file__), "tests/data/test.CSV"), "rb") as f:
205+
data = {"title": "CSV with uppercase extension", "doc_file": f, "extension": "CSV"}
206+
self.client.post(reverse("document_upload"), data=data)
207+
d = Document.objects.get(title="CSV with uppercase extension")
208+
# verify that the extension is not lowercase
209+
self.assertEqual(d.extension, "csv")
210+
# be sure that also the file extension is not lowercase
211+
asset = get_default_asset(d)
212+
self.assertEqual(Path(asset.location[0]).suffix, ".csv")
213+
finally:
214+
Document.objects.filter(title="CSV with uppercase extension").delete()
215+
196216
def test_upload_document_form(self):
197217
"""
198218
Tests the Upload form.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Username; Identifier;First name;Last name
2+
booker12;9012;Rachel;Booker
3+
grey07;2070;Laura;Grey
4+
johnson81;4081;Craig;Johnson
5+
jenkins46;9346;Mary;Jenkins
6+
smith79;5079;Jamie;Smith

geonode/documents/views.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
from geonode.base.models import Thesaurus, TopicCategory
5454
from geonode.base import enumerations
5555

56+
from pathlib import Path
57+
5658
from .utils import get_download_response
5759

5860
from .models import Document
@@ -162,7 +164,8 @@ def form_valid(self, form):
162164
if file:
163165
tempdir = mkdtemp()
164166
dirname = os.path.basename(tempdir)
165-
filepath = storage_manager.save(f"{dirname}/{file.name}", file)
167+
name = Path(file.name)
168+
filepath = storage_manager.save(f"{dirname}/{name.stem}{name.suffix.lower()}", file)
166169
storage_path = storage_manager.path(filepath)
167170
self.object = resource_manager.create(
168171
None,

0 commit comments

Comments
 (0)