udata 10.3.3.dev35091__py2.py3-none-any.whl → 10.3.3.dev35125__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of udata might be problematic. Click here for more details.
- udata/core/dataset/api.py +5 -2
- udata/core/dataset/apiv2.py +42 -12
- udata/core/dataset/constants.py +2 -0
- udata/core/spatial/api_fields.py +16 -3
- udata/tests/api/test_datasets_api.py +37 -1
- {udata-10.3.3.dev35091.dist-info → udata-10.3.3.dev35125.dist-info}/METADATA +3 -2
- {udata-10.3.3.dev35091.dist-info → udata-10.3.3.dev35125.dist-info}/RECORD +11 -11
- {udata-10.3.3.dev35091.dist-info → udata-10.3.3.dev35125.dist-info}/LICENSE +0 -0
- {udata-10.3.3.dev35091.dist-info → udata-10.3.3.dev35125.dist-info}/WHEEL +0 -0
- {udata-10.3.3.dev35091.dist-info → udata-10.3.3.dev35125.dist-info}/entry_points.txt +0 -0
- {udata-10.3.3.dev35091.dist-info → udata-10.3.3.dev35125.dist-info}/top_level.txt +0 -0
udata/core/dataset/api.py
CHANGED
|
@@ -604,8 +604,11 @@ class ResourceAPI(ResourceMixin, API):
|
|
|
604
604
|
@api.marshal_with(resource_fields)
|
|
605
605
|
def get(self, dataset, rid):
|
|
606
606
|
"""Get a resource given its identifier"""
|
|
607
|
-
if
|
|
608
|
-
|
|
607
|
+
if not DatasetEditPermission(dataset).can():
|
|
608
|
+
if dataset.private:
|
|
609
|
+
api.abort(404)
|
|
610
|
+
elif dataset.deleted:
|
|
611
|
+
api.abort(410, "Dataset has been deleted")
|
|
609
612
|
resource = self.get_resource_or_404(dataset, rid)
|
|
610
613
|
return resource
|
|
611
614
|
|
udata/core/dataset/apiv2.py
CHANGED
|
@@ -8,6 +8,7 @@ from flask_restx import marshal
|
|
|
8
8
|
from udata import search
|
|
9
9
|
from udata.api import API, apiv2, fields
|
|
10
10
|
from udata.core.contact_point.api_fields import contact_point_fields
|
|
11
|
+
from udata.core.dataset.api_fields import license_fields
|
|
11
12
|
from udata.core.organization.api_fields import member_user_with_email_fields
|
|
12
13
|
from udata.core.spatial.api_fields import geojson
|
|
13
14
|
from udata.utils import get_by
|
|
@@ -28,7 +29,7 @@ from .api_fields import (
|
|
|
28
29
|
temporal_coverage_fields,
|
|
29
30
|
user_ref_fields,
|
|
30
31
|
)
|
|
31
|
-
from .constants import DEFAULT_FREQUENCY, DEFAULT_LICENSE, UPDATE_FREQUENCIES
|
|
32
|
+
from .constants import DEFAULT_FREQUENCY, DEFAULT_LICENSE, FULL_OBJECTS_HEADER, UPDATE_FREQUENCIES
|
|
32
33
|
from .models import CommunityResource, Dataset
|
|
33
34
|
from .permissions import DatasetEditPermission, ResourceEditPermission
|
|
34
35
|
from .search import DatasetSearch
|
|
@@ -149,11 +150,17 @@ dataset_fields = apiv2.model(
|
|
|
149
150
|
},
|
|
150
151
|
description="Link to the dataset community resources",
|
|
151
152
|
),
|
|
152
|
-
"frequency": fields.
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
"frequency": fields.Raw(
|
|
154
|
+
attribute=lambda d: {
|
|
155
|
+
"id": d.frequency or DEFAULT_FREQUENCY,
|
|
156
|
+
"label": UPDATE_FREQUENCIES.get(d.frequency or DEFAULT_FREQUENCY),
|
|
157
|
+
}
|
|
158
|
+
if request.headers.get(FULL_OBJECTS_HEADER, False, bool)
|
|
159
|
+
else d.frequency,
|
|
155
160
|
enum=list(UPDATE_FREQUENCIES),
|
|
156
161
|
default=DEFAULT_FREQUENCY,
|
|
162
|
+
required=True,
|
|
163
|
+
description="The update frequency (full Frequency object if `X-Get-Datasets-Full-Objects` is set, ID of the frequency otherwise)",
|
|
157
164
|
),
|
|
158
165
|
"frequency_date": fields.ISODateTime(
|
|
159
166
|
description=(
|
|
@@ -183,8 +190,12 @@ dataset_fields = apiv2.model(
|
|
|
183
190
|
"spatial": fields.Nested(
|
|
184
191
|
spatial_coverage_fields, allow_null=True, description="The spatial coverage"
|
|
185
192
|
),
|
|
186
|
-
"license": fields.
|
|
187
|
-
attribute=
|
|
193
|
+
"license": fields.Raw(
|
|
194
|
+
attribute=lambda d: marshal(d.license, license_fields)
|
|
195
|
+
if request.headers.get(FULL_OBJECTS_HEADER, False, bool)
|
|
196
|
+
else (d.license.id if d.license is not None else None),
|
|
197
|
+
default=DEFAULT_LICENSE["id"],
|
|
198
|
+
description="The dataset license (full License object if `X-Get-Datasets-Full-Objects` is set, ID of the license otherwise)",
|
|
188
199
|
),
|
|
189
200
|
"uri": fields.UrlFor(
|
|
190
201
|
"api.dataset",
|
|
@@ -307,8 +318,11 @@ class DatasetAPI(API):
|
|
|
307
318
|
@apiv2.marshal_with(dataset_fields)
|
|
308
319
|
def get(self, dataset):
|
|
309
320
|
"""Get a dataset given its identifier"""
|
|
310
|
-
if
|
|
311
|
-
|
|
321
|
+
if not DatasetEditPermission(dataset).can():
|
|
322
|
+
if dataset.private:
|
|
323
|
+
apiv2.abort(404)
|
|
324
|
+
elif dataset.deleted:
|
|
325
|
+
apiv2.abort(410, "Dataset has been deleted")
|
|
312
326
|
return dataset
|
|
313
327
|
|
|
314
328
|
|
|
@@ -321,8 +335,11 @@ class DatasetExtrasAPI(API):
|
|
|
321
335
|
@apiv2.doc("get_dataset_extras")
|
|
322
336
|
def get(self, dataset):
|
|
323
337
|
"""Get a dataset extras given its identifier"""
|
|
324
|
-
if
|
|
325
|
-
|
|
338
|
+
if not DatasetEditPermission(dataset).can():
|
|
339
|
+
if dataset.private:
|
|
340
|
+
apiv2.abort(404)
|
|
341
|
+
elif dataset.deleted:
|
|
342
|
+
apiv2.abort(410, "Dataset has been deleted")
|
|
326
343
|
return dataset.extras
|
|
327
344
|
|
|
328
345
|
@apiv2.secure
|
|
@@ -370,6 +387,11 @@ class ResourcesAPI(API):
|
|
|
370
387
|
@apiv2.marshal_with(resource_page_fields)
|
|
371
388
|
def get(self, dataset):
|
|
372
389
|
"""Get the given dataset resources, paginated."""
|
|
390
|
+
if not DatasetEditPermission(dataset).can():
|
|
391
|
+
if dataset.private:
|
|
392
|
+
apiv2.abort(404)
|
|
393
|
+
elif dataset.deleted:
|
|
394
|
+
apiv2.abort(410, "Dataset has been deleted")
|
|
373
395
|
args = resources_parser.parse_args()
|
|
374
396
|
page = args["page"]
|
|
375
397
|
page_size = args["page_size"]
|
|
@@ -410,6 +432,11 @@ class ResourceAPI(API):
|
|
|
410
432
|
def get(self, rid):
|
|
411
433
|
dataset = Dataset.objects(resources__id=rid).first()
|
|
412
434
|
if dataset:
|
|
435
|
+
if not DatasetEditPermission(dataset).can():
|
|
436
|
+
if dataset.private:
|
|
437
|
+
apiv2.abort(404)
|
|
438
|
+
elif dataset.deleted:
|
|
439
|
+
apiv2.abort(410, "Dataset has been deleted")
|
|
413
440
|
resource = get_by(dataset.resources, "id", rid)
|
|
414
441
|
else:
|
|
415
442
|
resource = CommunityResource.objects(id=rid).first()
|
|
@@ -436,8 +463,11 @@ class ResourceExtrasAPI(ResourceMixin, API):
|
|
|
436
463
|
@apiv2.doc("get_resource_extras")
|
|
437
464
|
def get(self, dataset, rid):
|
|
438
465
|
"""Get a resource extras given its identifier"""
|
|
439
|
-
if
|
|
440
|
-
|
|
466
|
+
if not DatasetEditPermission(dataset).can():
|
|
467
|
+
if dataset.private:
|
|
468
|
+
apiv2.abort(404)
|
|
469
|
+
elif dataset.deleted:
|
|
470
|
+
apiv2.abort(410, "Dataset has been deleted")
|
|
441
471
|
resource = self.get_resource_or_404(dataset, rid)
|
|
442
472
|
return resource.extras
|
|
443
473
|
|
udata/core/dataset/constants.py
CHANGED
udata/core/spatial/api_fields.py
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
from flask import request
|
|
2
|
+
from flask_restx import marshal
|
|
3
|
+
|
|
1
4
|
from udata.api import api, fields
|
|
5
|
+
from udata.core.dataset.constants import FULL_OBJECTS_HEADER
|
|
2
6
|
|
|
3
7
|
GEOM_TYPES = ("Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon")
|
|
4
8
|
|
|
@@ -66,9 +70,18 @@ spatial_coverage_fields = api.model(
|
|
|
66
70
|
"geom": fields.Nested(
|
|
67
71
|
geojson, allow_null=True, description="A multipolygon for the whole coverage"
|
|
68
72
|
),
|
|
69
|
-
"zones": fields.
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
"zones": fields.Raw(
|
|
74
|
+
attribute=lambda s: marshal(s.zones, zone_fields)
|
|
75
|
+
if request.headers.get(FULL_OBJECTS_HEADER, False, bool)
|
|
76
|
+
else [str(z) for z in s.zones],
|
|
77
|
+
description="The covered zones identifiers (full GeoZone objects if `X-Get-Datasets-Full-Objects` is set, IDs of the zones otherwise)",
|
|
78
|
+
),
|
|
79
|
+
"granularity": fields.Raw(
|
|
80
|
+
attribute=lambda s: {"id": s.granularity or "other", "name": s.granularity_label}
|
|
81
|
+
if request.headers.get(FULL_OBJECTS_HEADER, False, bool)
|
|
82
|
+
else s.granularity,
|
|
83
|
+
default="other",
|
|
84
|
+
description="The spatial/territorial granularity (full Granularity object if `X-Get-Datasets-Full-Objects` is set, ID of the granularity otherwise)",
|
|
72
85
|
),
|
|
73
86
|
},
|
|
74
87
|
)
|
|
@@ -19,6 +19,7 @@ from udata.core.dataset.api_fields import (
|
|
|
19
19
|
resource_harvest_fields,
|
|
20
20
|
)
|
|
21
21
|
from udata.core.dataset.constants import (
|
|
22
|
+
FULL_OBJECTS_HEADER,
|
|
22
23
|
LEGACY_FREQUENCIES,
|
|
23
24
|
RESOURCE_TYPES,
|
|
24
25
|
UPDATE_FREQUENCIES,
|
|
@@ -37,7 +38,7 @@ from udata.core.dataset.models import (
|
|
|
37
38
|
ResourceMixin,
|
|
38
39
|
)
|
|
39
40
|
from udata.core.organization.factories import OrganizationFactory
|
|
40
|
-
from udata.core.spatial.factories import SpatialCoverageFactory
|
|
41
|
+
from udata.core.spatial.factories import GeoLevelFactory, SpatialCoverageFactory
|
|
41
42
|
from udata.core.topic.factories import TopicFactory
|
|
42
43
|
from udata.core.user.factories import AdminFactory, UserFactory
|
|
43
44
|
from udata.i18n import gettext as _
|
|
@@ -506,6 +507,41 @@ class DatasetAPITest(APITestCase):
|
|
|
506
507
|
response = self.get(url_for("api.dataset", dataset=dataset))
|
|
507
508
|
self.assert200(response)
|
|
508
509
|
|
|
510
|
+
def test_dataset_api_get_with_full_objects(self):
|
|
511
|
+
"""It should fetch a private dataset from the API if user is authorized"""
|
|
512
|
+
license = LicenseFactory(id="lov2", title="Licence Ouverte Version 2.0")
|
|
513
|
+
paca, bdr, arles = create_geozones_fixtures()
|
|
514
|
+
country = GeoLevelFactory(id="country", name="Pays", admin_level=10)
|
|
515
|
+
|
|
516
|
+
dataset = DatasetFactory(
|
|
517
|
+
frequency="monthly",
|
|
518
|
+
license=license,
|
|
519
|
+
spatial=SpatialCoverageFactory(zones=[paca.id], granularity=country.id),
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
response = self.get(url_for("apiv2.dataset", dataset=dataset))
|
|
523
|
+
self.assert200(response)
|
|
524
|
+
assert response.json["frequency"] == "monthly"
|
|
525
|
+
assert response.json["license"] == "lov2"
|
|
526
|
+
assert response.json["spatial"]["zones"][0] == paca.id
|
|
527
|
+
assert response.json["spatial"]["granularity"] == "country"
|
|
528
|
+
|
|
529
|
+
response = self.get(
|
|
530
|
+
url_for("apiv2.dataset", dataset=dataset),
|
|
531
|
+
headers={
|
|
532
|
+
FULL_OBJECTS_HEADER: "True",
|
|
533
|
+
},
|
|
534
|
+
)
|
|
535
|
+
self.assert200(response)
|
|
536
|
+
assert response.json["frequency"]["id"] == "monthly"
|
|
537
|
+
assert response.json["frequency"]["label"] == "Mensuelle"
|
|
538
|
+
assert response.json["license"]["id"] == "lov2"
|
|
539
|
+
assert response.json["license"]["title"] == license.title
|
|
540
|
+
assert response.json["spatial"]["zones"][0]["id"] == paca.id
|
|
541
|
+
assert response.json["spatial"]["zones"][0]["name"] == paca.name
|
|
542
|
+
assert response.json["spatial"]["granularity"]["id"] == "country"
|
|
543
|
+
assert response.json["spatial"]["granularity"]["name"] == country.name
|
|
544
|
+
|
|
509
545
|
def test_dataset_api_create(self):
|
|
510
546
|
"""It should create a dataset from the API"""
|
|
511
547
|
data = DatasetFactory.as_dict()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: udata
|
|
3
|
-
Version: 10.3.3.
|
|
3
|
+
Version: 10.3.3.dev35125
|
|
4
4
|
Summary: Open data portal
|
|
5
5
|
Home-page: https://github.com/opendatateam/udata
|
|
6
6
|
Author: Opendata Team
|
|
@@ -142,7 +142,8 @@ It is collectively taken care of by members of the
|
|
|
142
142
|
## Current (in progress)
|
|
143
143
|
|
|
144
144
|
- Improve reuse api perfs by adding a mask on datasets [#3309](https://github.com/opendatateam/udata/pull/3309)
|
|
145
|
-
- Private objects should return 404 by api [#3311](https://github.com/opendatateam/udata/pull/3311)
|
|
145
|
+
- Private objects should return 404 by api [#3311](https://github.com/opendatateam/udata/pull/3311) [#3316](https://github.com/opendatateam/udata/pull/3316)
|
|
146
|
+
- Allow returning full sub-objects (license, frequency, zones and granularity) for datasets APIv2 [#3310](https://github.com/opendatateam/udata/pull/3310)
|
|
146
147
|
- Add `featured` to dataset default mask [#3313](https://github.com/opendatateam/udata/pull/3313)
|
|
147
148
|
|
|
148
149
|
## 10.3.2 (2025-05-06)
|
|
@@ -94,11 +94,11 @@ udata/core/dataservices/tasks.py,sha256=d2tG1l6u8-eUKUYBOgnCsQLbLmLgJXU-DOzZWhhL
|
|
|
94
94
|
udata/core/dataset/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
95
95
|
udata/core/dataset/actions.py,sha256=mX6xox0PiMrbcAPZ3VZsI26rfM-ciYfEXxN6sqqImKA,1222
|
|
96
96
|
udata/core/dataset/activities.py,sha256=v8k1jwhdx62Z2ARZq8Q-x86OWSsBK99hRloPl74OCgA,1502
|
|
97
|
-
udata/core/dataset/api.py,sha256=
|
|
97
|
+
udata/core/dataset/api.py,sha256=jElQZuguc514Eb0cWdquEfosP1yB79hEQ52SV_SvLx8,33282
|
|
98
98
|
udata/core/dataset/api_fields.py,sha256=SLuzWoPdMLPX28WQ9DRGUPKS27vlltiFeiTo6jXa55Q,17549
|
|
99
|
-
udata/core/dataset/apiv2.py,sha256=
|
|
99
|
+
udata/core/dataset/apiv2.py,sha256=tpnIIk4UIQPOWUSjvxfBonTO8cbBEZSHKFItg0SnUws,19235
|
|
100
100
|
udata/core/dataset/commands.py,sha256=__hPAk_6iHtgMnEG51ux0vbNWJHxUjXhi1ukH4hF5jY,3714
|
|
101
|
-
udata/core/dataset/constants.py,sha256=
|
|
101
|
+
udata/core/dataset/constants.py,sha256=fKn21GzRShZv6pzKy3TvEK1cevQ9H3dOFE-xTRuE0lA,2971
|
|
102
102
|
udata/core/dataset/csv.py,sha256=aNJOytbFbH8OCYr6hyaSaqFSa94Xb3dvBd3QGZHJRsA,3633
|
|
103
103
|
udata/core/dataset/events.py,sha256=bSM0nFEX14r4JHc-bAM-7OOuD3JAxUIpw9GgXbOsUyw,4078
|
|
104
104
|
udata/core/dataset/exceptions.py,sha256=uKiayLSpSzsnLvClObS6hOO0qXEqvURKN7_w8eimQNU,498
|
|
@@ -202,7 +202,7 @@ udata/core/spam/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
|
202
202
|
udata/core/spam/tests/test_spam.py,sha256=Yu06Z3hU-XPX51mvdgH_nHQFeug_PXWy6P7QxNDaKEI,677
|
|
203
203
|
udata/core/spatial/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
204
204
|
udata/core/spatial/api.py,sha256=xuff3vcZjKm6z6FyFLFsuuVUDlCC8o0-JhUXkc-4pmc,5658
|
|
205
|
-
udata/core/spatial/api_fields.py,sha256=
|
|
205
|
+
udata/core/spatial/api_fields.py,sha256=6YVv7w6UyX_m7uGKNtexw8EOQk_I39GWlwCb3Qj_IiQ,3513
|
|
206
206
|
udata/core/spatial/commands.py,sha256=BMYAZqueaU6QlfN4ny4fsMF9l7rcjPp73mj8CIilyZ0,6931
|
|
207
207
|
udata/core/spatial/constants.py,sha256=T024yKsXuBkaZ1MAFZPfLh2X_EFFVQ7Sfg4VHCmZQM4,147
|
|
208
208
|
udata/core/spatial/factories.py,sha256=-eQupRrIOQLouw9Bvv4UBqizFKQ4l4CHZBht2cv7irE,3096
|
|
@@ -626,7 +626,7 @@ udata/tests/api/test_auth_api.py,sha256=OMRlY0OQt60j5N4A-N3HdWTuffOjRlFHkz5a3jJF
|
|
|
626
626
|
udata/tests/api/test_base_api.py,sha256=2w_vz0eEuq3P3aN-ByvxGc3VZAo7XtgatFfcrzf2uEU,2244
|
|
627
627
|
udata/tests/api/test_contact_points.py,sha256=X_RWD_xCfR8WchhHfKEt5mxMHY77OmTyguNKCsZftdE,5337
|
|
628
628
|
udata/tests/api/test_dataservices_api.py,sha256=fNpeHl4SMvci3QrC414X6KGorv7NS1y8LsGxcSMjjZY,25729
|
|
629
|
-
udata/tests/api/test_datasets_api.py,sha256=
|
|
629
|
+
udata/tests/api/test_datasets_api.py,sha256=dZXx9uz6Ni1qj2SxCgcmsvfzX8eCobqCVDaYHG4VZEY,96551
|
|
630
630
|
udata/tests/api/test_fields.py,sha256=OW85Z5MES5HeWOpapeem8OvR1cIcrqW-xMWpdZO4LZ8,1033
|
|
631
631
|
udata/tests/api/test_follow_api.py,sha256=XP6I96JUNT6xjGcQOF7pug_T_i67HzCiOGLaPdpfpEQ,4912
|
|
632
632
|
udata/tests/api/test_me_api.py,sha256=YPd8zmR3zwJKtpSqz8nY1nOOMyXs66INeBwyhg5D0Us,13846
|
|
@@ -726,9 +726,9 @@ udata/translations/pt/LC_MESSAGES/udata.mo,sha256=ViV14tUmjSydHS0TWG_mFikKQfyUaT
|
|
|
726
726
|
udata/translations/pt/LC_MESSAGES/udata.po,sha256=rzAD_MVoV54TmN3w1ECz3H2Ru5pM7hWMVH03SkY28Q8,47250
|
|
727
727
|
udata/translations/sr/LC_MESSAGES/udata.mo,sha256=EHX1_D-Uglj38832G7BrA0QC5IuY3p8dKqi9T0DgPmE,29169
|
|
728
728
|
udata/translations/sr/LC_MESSAGES/udata.po,sha256=3PMnbVhKVJh6Q8ABi1ZTZ8Dcf-sMjngLJZqLbonJoec,54225
|
|
729
|
-
udata-10.3.3.
|
|
730
|
-
udata-10.3.3.
|
|
731
|
-
udata-10.3.3.
|
|
732
|
-
udata-10.3.3.
|
|
733
|
-
udata-10.3.3.
|
|
734
|
-
udata-10.3.3.
|
|
729
|
+
udata-10.3.3.dev35125.dist-info/LICENSE,sha256=V8j_M8nAz8PvAOZQocyRDX7keai8UJ9skgmnwqETmdY,34520
|
|
730
|
+
udata-10.3.3.dev35125.dist-info/METADATA,sha256=3zpBEJCmrAbYIycc2NazRDRY0YMNr8KeofQ4L9bEL5M,145895
|
|
731
|
+
udata-10.3.3.dev35125.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
|
|
732
|
+
udata-10.3.3.dev35125.dist-info/entry_points.txt,sha256=ETvkR4r6G1duBsh_V_fGWENQy17GTFuobi95MYBAl1A,498
|
|
733
|
+
udata-10.3.3.dev35125.dist-info/top_level.txt,sha256=39OCg-VWFWOq4gCKnjKNu-s3OwFlZIu_dVH8Gl6ndHw,12
|
|
734
|
+
udata-10.3.3.dev35125.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|