udata 9.0.1.dev29687__py2.py3-none-any.whl → 9.0.1.dev29716__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/dataservices/factories.py +19 -0
- udata/core/dataservices/rdf.py +55 -4
- udata/core/dataset/rdf.py +14 -8
- udata/core/site/api.py +29 -1
- udata/core/site/rdf.py +6 -1
- udata/routing.py +1 -1
- udata/static/chunks/{11.ae54612e36c6d46f85db.js → 11.7266fef2dddc1db403d9.js} +3 -3
- udata/static/chunks/{11.ae54612e36c6d46f85db.js.map → 11.7266fef2dddc1db403d9.js.map} +1 -1
- udata/static/chunks/{13.d8ccb992a49875966313.js → 13.91b177d7d531fd55cf5d.js} +2 -2
- udata/static/chunks/{13.d8ccb992a49875966313.js.map → 13.91b177d7d531fd55cf5d.js.map} +1 -1
- udata/static/chunks/{16.4565605e68bab129a471.js → 16.e866757bab9f6b0a3f1b.js} +2 -2
- udata/static/chunks/{16.4565605e68bab129a471.js.map → 16.e866757bab9f6b0a3f1b.js.map} +1 -1
- udata/static/chunks/{19.f993a75d5bfe2382548d.js → 19.619b83ac597516dcd03e.js} +3 -3
- udata/static/chunks/{19.f993a75d5bfe2382548d.js.map → 19.619b83ac597516dcd03e.js.map} +1 -1
- udata/static/chunks/{5.cc2e7bf65ef32f9c8604.js → 5.48417db6b33328fa9d6a.js} +3 -3
- udata/static/chunks/{5.cc2e7bf65ef32f9c8604.js.map → 5.48417db6b33328fa9d6a.js.map} +1 -1
- udata/static/chunks/{6.cad898a38692eda28965.js → 6.f84539bd4c419b36cc19.js} +3 -3
- udata/static/chunks/{6.cad898a38692eda28965.js.map → 6.f84539bd4c419b36cc19.js.map} +1 -1
- udata/static/chunks/{9.d5b992e9ef51921aeb57.js → 9.07503e7f7ec02919f696.js} +2 -2
- udata/static/chunks/{9.d5b992e9ef51921aeb57.js.map → 9.07503e7f7ec02919f696.js.map} +1 -1
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- udata/tests/site/test_site_rdf.py +50 -0
- {udata-9.0.1.dev29687.dist-info → udata-9.0.1.dev29716.dist-info}/METADATA +3 -1
- {udata-9.0.1.dev29687.dist-info → udata-9.0.1.dev29716.dist-info}/RECORD +29 -28
- {udata-9.0.1.dev29687.dist-info → udata-9.0.1.dev29716.dist-info}/LICENSE +0 -0
- {udata-9.0.1.dev29687.dist-info → udata-9.0.1.dev29716.dist-info}/WHEEL +0 -0
- {udata-9.0.1.dev29687.dist-info → udata-9.0.1.dev29716.dist-info}/entry_points.txt +0 -0
- {udata-9.0.1.dev29687.dist-info → udata-9.0.1.dev29716.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import factory
|
|
2
|
+
|
|
3
|
+
from udata.core.dataservices.models import Dataservice
|
|
4
|
+
from udata.core.organization.factories import OrganizationFactory
|
|
5
|
+
from udata.factories import ModelFactory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DataserviceFactory(ModelFactory):
|
|
9
|
+
class Meta:
|
|
10
|
+
model = Dataservice
|
|
11
|
+
|
|
12
|
+
title = factory.Faker('sentence')
|
|
13
|
+
description = factory.Faker('text')
|
|
14
|
+
base_api_url = factory.Faker('url')
|
|
15
|
+
|
|
16
|
+
class Params:
|
|
17
|
+
org = factory.Trait(
|
|
18
|
+
organization=factory.SubFactory(OrganizationFactory),
|
|
19
|
+
)
|
udata/core/dataservices/rdf.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
from datetime import datetime
|
|
3
3
|
from typing import List, Optional
|
|
4
|
-
from rdflib import RDF, Graph, URIRef
|
|
4
|
+
from rdflib import RDF, BNode, Graph, Literal, URIRef
|
|
5
5
|
|
|
6
6
|
from udata.core.dataservices.models import Dataservice, HarvestMetadata as HarvestDataserviceMetadata
|
|
7
7
|
from udata.core.dataset.models import Dataset, License
|
|
8
|
-
from udata.core.dataset.rdf import sanitize_html
|
|
8
|
+
from udata.core.dataset.rdf import dataset_to_graph_id, sanitize_html
|
|
9
9
|
from udata.harvest.models import HarvestSource
|
|
10
|
-
from udata.rdf import DCAT, DCT, contact_point_from_rdf, rdf_value, remote_url_from_rdf,
|
|
10
|
+
from udata.rdf import DCATAP, TAG_TO_EU_HVD_CATEGORIES, namespace_manager, DCAT, DCT, contact_point_from_rdf, rdf_value, remote_url_from_rdf, themes_from_rdf, url_from_rdf
|
|
11
|
+
from udata.uris import endpoint_for
|
|
11
12
|
|
|
12
13
|
def dataservice_from_rdf(graph: Graph, dataservice: Dataservice, node, all_datasets: List[Dataset]) -> Dataservice :
|
|
13
14
|
'''
|
|
@@ -55,4 +56,54 @@ def dataservice_from_rdf(graph: Graph, dataservice: Dataservice, node, all_datas
|
|
|
55
56
|
|
|
56
57
|
dataservice.tags = themes_from_rdf(d)
|
|
57
58
|
|
|
58
|
-
return dataservice
|
|
59
|
+
return dataservice
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def dataservice_to_rdf(dataservice, graph=None):
|
|
63
|
+
'''
|
|
64
|
+
Map a dataservice domain model to a DCAT/RDF graph
|
|
65
|
+
'''
|
|
66
|
+
# Use the unlocalized permalink to the dataset as URI when available
|
|
67
|
+
# unless there is already an upstream URI
|
|
68
|
+
if dataservice.harvest and dataservice.harvest.rdf_node_id_as_url:
|
|
69
|
+
id = URIRef(dataservice.harvest.rdf_node_id_as_url)
|
|
70
|
+
elif dataservice.id:
|
|
71
|
+
id = URIRef(endpoint_for('dataservices.show_redirect', 'api.dataservice',
|
|
72
|
+
dataservice=dataservice.id, _external=True))
|
|
73
|
+
else:
|
|
74
|
+
# Should not happen in production. Some test only
|
|
75
|
+
# `build()` a dataset without saving it to the DB.
|
|
76
|
+
id = BNode()
|
|
77
|
+
|
|
78
|
+
# Expose upstream identifier if present
|
|
79
|
+
if dataservice.harvest and dataservice.harvest.dct_identifier:
|
|
80
|
+
identifier = dataservice.harvest.dct_identifier
|
|
81
|
+
else:
|
|
82
|
+
identifier = dataservice.id
|
|
83
|
+
graph = graph or Graph(namespace_manager=namespace_manager)
|
|
84
|
+
|
|
85
|
+
d = graph.resource(id)
|
|
86
|
+
d.set(RDF.type, DCAT.DataService)
|
|
87
|
+
d.set(DCT.identifier, Literal(identifier))
|
|
88
|
+
d.set(DCT.title, Literal(dataservice.title))
|
|
89
|
+
d.set(DCT.description, Literal(dataservice.description))
|
|
90
|
+
d.set(DCT.issued, Literal(dataservice.created_at))
|
|
91
|
+
|
|
92
|
+
if dataservice.base_api_url:
|
|
93
|
+
d.set(DCAT.endpointURL, Literal(dataservice.base_api_url))
|
|
94
|
+
|
|
95
|
+
if dataservice.endpoint_description_url:
|
|
96
|
+
d.set(DCAT.endpointDescription, Literal(dataservice.endpoint_description_url))
|
|
97
|
+
|
|
98
|
+
for tag in dataservice.tags:
|
|
99
|
+
d.add(DCAT.keyword, Literal(tag))
|
|
100
|
+
|
|
101
|
+
# `dataset_to_graph_id(dataset)` URIRef may not exist in the current page
|
|
102
|
+
# but should exists in the catalog somewhere. Maybe we should create a Node
|
|
103
|
+
# with some basic information about this dataset (but this will return a page
|
|
104
|
+
# with more datasets than the page size… and could be problematic when processing the
|
|
105
|
+
# correct Node with all the information in a future page)
|
|
106
|
+
for dataset in dataservice.datasets:
|
|
107
|
+
d.add(DCAT.servesDataset, dataset_to_graph_id(dataset))
|
|
108
|
+
|
|
109
|
+
return d
|
udata/core/dataset/rdf.py
CHANGED
|
@@ -6,7 +6,7 @@ import json
|
|
|
6
6
|
import logging
|
|
7
7
|
|
|
8
8
|
from datetime import date
|
|
9
|
-
from typing import Optional
|
|
9
|
+
from typing import Optional, Union
|
|
10
10
|
from dateutil.parser import parse as parse_dt
|
|
11
11
|
from flask import current_app
|
|
12
12
|
from geomet import wkt
|
|
@@ -149,19 +149,25 @@ def resource_to_rdf(resource, dataset=None, graph=None, is_hvd=False):
|
|
|
149
149
|
return r
|
|
150
150
|
|
|
151
151
|
|
|
152
|
+
def dataset_to_graph_id(dataset: Dataset) -> Union[URIRef, BNode]:
|
|
153
|
+
if dataset.harvest and dataset.harvest.uri:
|
|
154
|
+
return URIRef(dataset.harvest.uri)
|
|
155
|
+
elif dataset.id:
|
|
156
|
+
return URIRef(endpoint_for('datasets.show_redirect', 'api.dataset',
|
|
157
|
+
dataset=dataset.id, _external=True))
|
|
158
|
+
else:
|
|
159
|
+
# Should not happen in production. Some test only
|
|
160
|
+
# `build()` a dataset without saving it to the DB.
|
|
161
|
+
return BNode()
|
|
162
|
+
|
|
152
163
|
def dataset_to_rdf(dataset, graph=None):
|
|
153
164
|
'''
|
|
154
165
|
Map a dataset domain model to a DCAT/RDF graph
|
|
155
166
|
'''
|
|
156
167
|
# Use the unlocalized permalink to the dataset as URI when available
|
|
157
168
|
# unless there is already an upstream URI
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
elif dataset.id:
|
|
161
|
-
id = URIRef(endpoint_for('datasets.show_redirect', 'api.dataset',
|
|
162
|
-
dataset=dataset.id, _external=True))
|
|
163
|
-
else:
|
|
164
|
-
id = BNode()
|
|
169
|
+
id = dataset_to_graph_id(dataset)
|
|
170
|
+
|
|
165
171
|
# Expose upstream identifier if present
|
|
166
172
|
if dataset.harvest and dataset.harvest.dct_identifier:
|
|
167
173
|
identifier = dataset.harvest.dct_identifier
|
udata/core/site/api.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from bson import ObjectId
|
|
2
2
|
|
|
3
3
|
from flask import request, redirect, url_for, json, make_response
|
|
4
|
+
from mongoengine import Q
|
|
4
5
|
|
|
5
6
|
from udata.api import api, API, fields
|
|
6
7
|
from udata.auth import admin_permission
|
|
8
|
+
from udata.core.dataservices.models import Dataservice
|
|
7
9
|
from udata.models import Dataset, Reuse
|
|
8
10
|
from udata.utils import multi_to_dict
|
|
9
11
|
from udata.rdf import (
|
|
@@ -109,7 +111,33 @@ class SiteRdfCatalogFormat(API):
|
|
|
109
111
|
if 'tag' in params:
|
|
110
112
|
datasets = datasets.filter(tags=params.get('tag', ''))
|
|
111
113
|
datasets = datasets.paginate(page, page_size)
|
|
112
|
-
|
|
114
|
+
|
|
115
|
+
# We need to add Dataservice to the catalog.
|
|
116
|
+
# In the best world, we want:
|
|
117
|
+
# - Keep the correct number of datasets on the page (if the requested page size is 100, we should have 100 datasets)
|
|
118
|
+
# - Have simple MongoDB queries
|
|
119
|
+
# - Do not duplicate the datasets (each dataset is present once in the catalog)
|
|
120
|
+
# - Do not duplicate the dataservices (each dataservice is present once in the catalog)
|
|
121
|
+
# - Every referenced dataset for one dataservices present on the page (hard to do)
|
|
122
|
+
#
|
|
123
|
+
# Multiple solutions are possible but none check all the constraints.
|
|
124
|
+
# The selected one is to put all the dataservices referencing at least one of the dataset on
|
|
125
|
+
# the page at the end of it. It means dataservices could be duplicated (present on multiple pages)
|
|
126
|
+
# and these dataservices may referenced some datasets not present in the current page. It's working
|
|
127
|
+
# if somebody is doing the same thing as us (keeping the list of all the datasets IDs for the entire catalog then
|
|
128
|
+
# listing all dataservices in a second pass)
|
|
129
|
+
# Another option is to do some tricky Mongo requests to order/group datasets by their presence in some dataservices but
|
|
130
|
+
# it could be really hard to do with a n..n relation.
|
|
131
|
+
# Let's keep this solution simple right now and iterate on it in the future.
|
|
132
|
+
dataservices_filter = Q(datasets__in=[d.id for d in datasets])
|
|
133
|
+
|
|
134
|
+
# On the first page, add all dataservices without datasets
|
|
135
|
+
if page == 1:
|
|
136
|
+
dataservices_filter = dataservices_filter | Q(datasets__size=0)
|
|
137
|
+
|
|
138
|
+
dataservices = Dataservice.objects.visible().filter(dataservices_filter)
|
|
139
|
+
|
|
140
|
+
catalog = build_catalog(current_site, datasets, dataservices=dataservices, format=format)
|
|
113
141
|
# bypass flask-restplus make_response, since graph_response
|
|
114
142
|
# is handling the content negociation directly
|
|
115
143
|
return make_response(*graph_response(catalog, format))
|
udata/core/site/rdf.py
CHANGED
|
@@ -5,6 +5,7 @@ from flask import url_for, current_app
|
|
|
5
5
|
from rdflib import Graph, URIRef, Literal, BNode
|
|
6
6
|
from rdflib.namespace import RDF, FOAF
|
|
7
7
|
|
|
8
|
+
from udata.core.dataservices.rdf import dataservice_to_rdf
|
|
8
9
|
from udata.core.dataset.rdf import dataset_to_rdf
|
|
9
10
|
from udata.core.organization.rdf import organization_to_rdf
|
|
10
11
|
from udata.core.user.rdf import user_to_rdf
|
|
@@ -13,7 +14,7 @@ from udata.utils import Paginable
|
|
|
13
14
|
from udata.uris import endpoint_for
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
def build_catalog(site, datasets, format=None):
|
|
17
|
+
def build_catalog(site, datasets, dataservices = [], format=None):
|
|
17
18
|
'''Build the DCAT catalog for this site'''
|
|
18
19
|
site_url = endpoint_for('site.home_redirect', 'api.site', _external=True)
|
|
19
20
|
catalog_url = url_for('api.site_rdf_catalog', _external=True)
|
|
@@ -40,6 +41,10 @@ def build_catalog(site, datasets, format=None):
|
|
|
40
41
|
rdf_dataset.add(DCT.publisher, organization_to_rdf(dataset.organization, graph))
|
|
41
42
|
catalog.add(DCAT.dataset, rdf_dataset)
|
|
42
43
|
|
|
44
|
+
for dataservice in dataservices:
|
|
45
|
+
rdf_dataservice = dataservice_to_rdf(dataservice, graph)
|
|
46
|
+
catalog.add(DCAT.DataService, rdf_dataservice)
|
|
47
|
+
|
|
43
48
|
if isinstance(datasets, Paginable):
|
|
44
49
|
paginate_catalog(catalog, graph, datasets, format, 'api.site_rdf_catalog_format')
|
|
45
50
|
|
udata/routing.py
CHANGED
|
@@ -217,7 +217,7 @@ def lazy_raise_or_redirect():
|
|
|
217
217
|
new_args = request.view_args
|
|
218
218
|
new_args[name] = value.arg
|
|
219
219
|
new_url = url_for(request.endpoint, **new_args)
|
|
220
|
-
return redirect(new_url, code=308)
|
|
220
|
+
return redirect(new_url, code=204 if request.method == 'OPTIONS' else 308)
|
|
221
221
|
|
|
222
222
|
|
|
223
223
|
def init_app(app):
|