udata 10.0.1.dev32350__py2.py3-none-any.whl → 10.0.1.dev32396__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/api_fields.py +28 -1
- udata/core/badges/tests/test_model.py +22 -7
- udata/core/dataset/models.py +6 -1
- udata/core/dataset/rdf.py +20 -5
- udata/core/organization/models.py +6 -1
- udata/core/reuse/models.py +6 -1
- udata/rdf.py +1 -0
- udata/static/chunks/{10.dac55d18d0b4ef3cdacf.js → 10.a99bb538cfbadb38dbcb.js} +3 -3
- udata/static/chunks/{10.dac55d18d0b4ef3cdacf.js.map → 10.a99bb538cfbadb38dbcb.js.map} +1 -1
- udata/static/chunks/{11.4a20a75f827c5a1125c3.js → 11.bb1c1fb39f740fbbeec0.js} +3 -3
- udata/static/chunks/{11.4a20a75f827c5a1125c3.js.map → 11.bb1c1fb39f740fbbeec0.js.map} +1 -1
- udata/static/chunks/{13.645dd0b7c0b9210f1b56.js → 13.bef5fdb3e147e94fea99.js} +2 -2
- udata/static/chunks/{13.645dd0b7c0b9210f1b56.js.map → 13.bef5fdb3e147e94fea99.js.map} +1 -1
- udata/static/chunks/{17.8e19985c4d12a3b7b0c0.js → 17.b91d28f550dc44bc4979.js} +2 -2
- udata/static/chunks/{17.8e19985c4d12a3b7b0c0.js.map → 17.b91d28f550dc44bc4979.js.map} +1 -1
- udata/static/chunks/{19.825a43c330157e351fca.js → 19.2c615ffee1e807000770.js} +3 -3
- udata/static/chunks/{19.825a43c330157e351fca.js.map → 19.2c615ffee1e807000770.js.map} +1 -1
- udata/static/chunks/{8.5ee0cf635c848abbfc05.js → 8.291bde987ed97294e4de.js} +2 -2
- udata/static/chunks/{8.5ee0cf635c848abbfc05.js.map → 8.291bde987ed97294e4de.js.map} +1 -1
- udata/static/chunks/{9.df3c36f8d0d210621fbb.js → 9.985935421e62c97a9f86.js} +3 -3
- udata/static/chunks/{9.df3c36f8d0d210621fbb.js.map → 9.985935421e62c97a9f86.js.map} +1 -1
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- udata/tests/dataset/test_dataset_rdf.py +11 -3
- udata/tests/organization/test_organization_model.py +20 -2
- udata/tests/reuse/test_reuse_model.py +17 -1
- {udata-10.0.1.dev32350.dist-info → udata-10.0.1.dev32396.dist-info}/METADATA +3 -1
- {udata-10.0.1.dev32350.dist-info → udata-10.0.1.dev32396.dist-info}/RECORD +32 -32
- {udata-10.0.1.dev32350.dist-info → udata-10.0.1.dev32396.dist-info}/LICENSE +0 -0
- {udata-10.0.1.dev32350.dist-info → udata-10.0.1.dev32396.dist-info}/WHEEL +0 -0
- {udata-10.0.1.dev32350.dist-info → udata-10.0.1.dev32396.dist-info}/entry_points.txt +0 -0
- {udata-10.0.1.dev32350.dist-info → udata-10.0.1.dev32396.dist-info}/top_level.txt +0 -0
udata/api_fields.py
CHANGED
|
@@ -94,6 +94,8 @@ def convert_db_to_field(key, field, info) -> tuple[Callable | None, Callable | N
|
|
|
94
94
|
params["min_length"] = field.min_length
|
|
95
95
|
params["max_length"] = field.max_length
|
|
96
96
|
params["enum"] = field.choices
|
|
97
|
+
if field.validation:
|
|
98
|
+
params["validation"] = validation_to_type(field.validation)
|
|
97
99
|
elif isinstance(field, mongo_fields.ObjectIdField):
|
|
98
100
|
constructor = restx_fields.String
|
|
99
101
|
elif isinstance(field, mongo_fields.FloatField):
|
|
@@ -287,7 +289,7 @@ def generate_fields(**kwargs) -> Callable:
|
|
|
287
289
|
if not isinstance(
|
|
288
290
|
field, mongo_fields.ReferenceField | mongo_fields.LazyReferenceField
|
|
289
291
|
):
|
|
290
|
-
raise Exception("Cannot use additional_filters on not a ref.")
|
|
292
|
+
raise Exception("Cannot use additional_filters on a field that is not a ref.")
|
|
291
293
|
|
|
292
294
|
ref_model: db.Document = field.document_type
|
|
293
295
|
|
|
@@ -678,9 +680,34 @@ def compute_filter(column: str, field, info, filterable) -> dict:
|
|
|
678
680
|
filterable["type"] = boolean
|
|
679
681
|
else:
|
|
680
682
|
filterable["type"] = str
|
|
683
|
+
if field.validation:
|
|
684
|
+
filterable["type"] = validation_to_type(field.validation)
|
|
681
685
|
|
|
682
686
|
filterable["choices"] = info.get("choices", None)
|
|
683
687
|
if hasattr(field, "choices") and field.choices:
|
|
684
688
|
filterable["choices"] = field.choices
|
|
685
689
|
|
|
686
690
|
return filterable
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
def validation_to_type(validation: Callable) -> Callable:
|
|
694
|
+
"""Convert a mongo field's validation function to a ReqParser's type.
|
|
695
|
+
|
|
696
|
+
In flask_restx.ReqParser, validation is done by setting the param's type to
|
|
697
|
+
a callable that will either raise, or return the parsed value.
|
|
698
|
+
|
|
699
|
+
In mongo, a field's validation function cannot return anything, so this
|
|
700
|
+
helper wraps the mongo field's validation to return the value if it validated.
|
|
701
|
+
"""
|
|
702
|
+
from udata.models import db
|
|
703
|
+
|
|
704
|
+
def wrapper(value: str) -> str:
|
|
705
|
+
try:
|
|
706
|
+
validation(value)
|
|
707
|
+
except db.ValidationError:
|
|
708
|
+
raise
|
|
709
|
+
return value
|
|
710
|
+
|
|
711
|
+
wrapper.__schema__ = {"type": "string", "format": "my-custom-format"}
|
|
712
|
+
|
|
713
|
+
return wrapper
|
|
@@ -15,8 +15,13 @@ BADGES = {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def validate_badge(value):
|
|
19
|
+
if value not in Fake.__badges__.keys():
|
|
20
|
+
raise db.ValidationError("Unknown badge type")
|
|
21
|
+
|
|
22
|
+
|
|
18
23
|
class FakeBadge(Badge):
|
|
19
|
-
kind = db.StringField(required=True,
|
|
24
|
+
kind = db.StringField(required=True, validation=validate_badge)
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
class FakeBadgeMixin(BadgeMixin):
|
|
@@ -34,12 +39,6 @@ class BadgeMixinTest(DBTestMixin, TestCase):
|
|
|
34
39
|
fake = Fake.objects.create()
|
|
35
40
|
self.assertIsInstance(fake.badges, (list, tuple))
|
|
36
41
|
|
|
37
|
-
def test_choices(self):
|
|
38
|
-
"""It should have a choice list on the badge field."""
|
|
39
|
-
self.assertEqual(
|
|
40
|
-
Fake._fields["badges"].field.document_type.kind.choices, list(Fake.__badges__.keys())
|
|
41
|
-
)
|
|
42
|
-
|
|
43
42
|
def test_get_badge_found(self):
|
|
44
43
|
"""It allow to get a badge by kind if present"""
|
|
45
44
|
fake = Fake.objects.create()
|
|
@@ -155,3 +154,19 @@ class BadgeMixinTest(DBTestMixin, TestCase):
|
|
|
155
154
|
with self.assertRaises(db.ValidationError):
|
|
156
155
|
fake = Fake.objects.create()
|
|
157
156
|
fake.add_badge("unknown")
|
|
157
|
+
|
|
158
|
+
def test_validation(self):
|
|
159
|
+
"""It should validate default badges as well as extended ones"""
|
|
160
|
+
# Model badges can be extended in plugins, for example in udata-front
|
|
161
|
+
# for french only badges.
|
|
162
|
+
Fake.__badges__["new"] = "new"
|
|
163
|
+
|
|
164
|
+
fake = FakeBadge(kind="test")
|
|
165
|
+
fake.validate()
|
|
166
|
+
|
|
167
|
+
fake = FakeBadge(kind="new")
|
|
168
|
+
fake.validate()
|
|
169
|
+
|
|
170
|
+
with self.assertRaises(db.ValidationError):
|
|
171
|
+
fake = FakeBadge(kind="doesnotexist")
|
|
172
|
+
fake.validate()
|
udata/core/dataset/models.py
CHANGED
|
@@ -521,8 +521,13 @@ class Resource(ResourceMixin, WithMetrics, db.EmbeddedDocument):
|
|
|
521
521
|
self.dataset.save(*args, **kwargs)
|
|
522
522
|
|
|
523
523
|
|
|
524
|
+
def validate_badge(value):
|
|
525
|
+
if value not in Dataset.__badges__.keys():
|
|
526
|
+
raise db.ValidationError("Unknown badge type")
|
|
527
|
+
|
|
528
|
+
|
|
524
529
|
class DatasetBadge(Badge):
|
|
525
|
-
kind = db.StringField(required=True,
|
|
530
|
+
kind = db.StringField(required=True, validation=validate_badge)
|
|
526
531
|
|
|
527
532
|
|
|
528
533
|
class DatasetBadgeMixin(BadgeMixin):
|
udata/core/dataset/rdf.py
CHANGED
|
@@ -21,6 +21,7 @@ from udata.core.spatial.models import SpatialCoverage
|
|
|
21
21
|
from udata.harvest.exceptions import HarvestSkipException
|
|
22
22
|
from udata.models import db
|
|
23
23
|
from udata.rdf import (
|
|
24
|
+
ADMS,
|
|
24
25
|
DCAT,
|
|
25
26
|
DCATAP,
|
|
26
27
|
DCT,
|
|
@@ -200,16 +201,30 @@ def dataset_to_rdf(dataset, graph=None):
|
|
|
200
201
|
# unless there is already an upstream URI
|
|
201
202
|
id = dataset_to_graph_id(dataset)
|
|
202
203
|
|
|
204
|
+
graph = graph or Graph(namespace_manager=namespace_manager)
|
|
205
|
+
d = graph.resource(id)
|
|
206
|
+
|
|
203
207
|
# Expose upstream identifier if present
|
|
204
208
|
if dataset.harvest and dataset.harvest.dct_identifier:
|
|
205
|
-
identifier
|
|
209
|
+
d.set(DCT.identifier, Literal(dataset.harvest.dct_identifier))
|
|
210
|
+
|
|
211
|
+
alt = graph.resource(BNode())
|
|
212
|
+
alternate_identifier = Literal(
|
|
213
|
+
endpoint_for(
|
|
214
|
+
"datasets.show_redirect",
|
|
215
|
+
"api.dataset",
|
|
216
|
+
dataset=dataset.id,
|
|
217
|
+
_external=True,
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
alt.set(RDF.type, ADMS.Identifier)
|
|
221
|
+
alt.set(DCT.creator, Literal(current_app.config["SITE_TITLE"]))
|
|
222
|
+
alt.set(SKOS.notation, alternate_identifier)
|
|
223
|
+
d.set(ADMS.identifier, alt)
|
|
206
224
|
else:
|
|
207
|
-
identifier
|
|
208
|
-
graph = graph or Graph(namespace_manager=namespace_manager)
|
|
225
|
+
d.set(DCT.identifier, Literal(dataset.id))
|
|
209
226
|
|
|
210
|
-
d = graph.resource(id)
|
|
211
227
|
d.set(RDF.type, DCAT.Dataset)
|
|
212
|
-
d.set(DCT.identifier, Literal(identifier))
|
|
213
228
|
d.set(DCT.title, Literal(dataset.title))
|
|
214
229
|
d.set(DCT.description, Literal(dataset.description))
|
|
215
230
|
d.set(DCT.issued, Literal(dataset.created_at))
|
|
@@ -95,8 +95,13 @@ class OrganizationQuerySet(db.BaseQuerySet):
|
|
|
95
95
|
return self(badges__kind=kind)
|
|
96
96
|
|
|
97
97
|
|
|
98
|
+
def validate_badge(value):
|
|
99
|
+
if value not in Organization.__badges__.keys():
|
|
100
|
+
raise db.ValidationError("Unknown badge type")
|
|
101
|
+
|
|
102
|
+
|
|
98
103
|
class OrganizationBadge(Badge):
|
|
99
|
-
kind = db.StringField(required=True,
|
|
104
|
+
kind = db.StringField(required=True, validation=validate_badge)
|
|
100
105
|
|
|
101
106
|
|
|
102
107
|
class OrganizationBadgeMixin(BadgeMixin):
|
udata/core/reuse/models.py
CHANGED
|
@@ -35,8 +35,13 @@ def check_url_does_not_exists(url):
|
|
|
35
35
|
raise FieldValidationError(_("This URL is already registered"), field="url")
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
def validate_badge(value):
|
|
39
|
+
if value not in Reuse.__badges__.keys():
|
|
40
|
+
raise db.ValidationError("Unknown badge type")
|
|
41
|
+
|
|
42
|
+
|
|
38
43
|
class ReuseBadge(Badge):
|
|
39
|
-
kind = db.StringField(required=True,
|
|
44
|
+
kind = db.StringField(required=True, validation=validate_badge)
|
|
40
45
|
|
|
41
46
|
|
|
42
47
|
class ReuseBadgeMixin(BadgeMixin):
|
udata/rdf.py
CHANGED
|
@@ -49,6 +49,7 @@ DCT = DCTERMS # More common usage
|
|
|
49
49
|
VCARD = Namespace("http://www.w3.org/2006/vcard/ns#")
|
|
50
50
|
|
|
51
51
|
namespace_manager = NamespaceManager(Graph())
|
|
52
|
+
namespace_manager.bind("adms", ADMS)
|
|
52
53
|
namespace_manager.bind("dcat", DCAT)
|
|
53
54
|
namespace_manager.bind("dcatap", DCATAP)
|
|
54
55
|
namespace_manager.bind("dct", DCT)
|