Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Temporal coverage with only start date #3192

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Use correct DCAT.service predicate in RDF output [#3199](https://github.com/opendatateam/udata/pull/3199)
- Fix the Badge.badge_label method [#3198](https://github.com/opendatateam/udata/pull/3198)
- Allow temporal coverage with only a start date [#3192](https://github.com/opendatateam/udata/pull/3192)

## 10.0.1 (2024-11-15)

Expand Down
5 changes: 2 additions & 3 deletions js/components/form/daterange-picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
<input type="text" class="form-control daterange-picker-end"
v-el:end-input :placeholder="_('End')"
@focus="onFocus" @input="onChange | debounce 500"
:required="required"
:value="endValue|dt dateFormat ''"
:readonly="readonly">
<span class="input-group-btn">
Expand Down Expand Up @@ -131,11 +130,11 @@ export default {
$(this.$els.endHidden).rules('add', {
dateGreaterThan: this.$els.startHidden.id,
required: (el) => {
return (this.startValue && !this.endValue) || (this.endValue && !this.startValue);
return (this.endValue && !this.startValue);
},
maudetes marked this conversation as resolved.
Show resolved Hide resolved
messages: {
dateGreaterThan: this._('End date should be after start date'),
required: this._('Both dates are required')
required: this._('At least a start date is required')
}
});
},
Expand Down
2 changes: 1 addition & 1 deletion js/locales/udata.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"Are you sure you want to delete this comment?": "Are you sure you want to delete this comment?",
"Are you sure?": "Are you sure?",
"As administrator you can choose any organization to publish": "As administrator you can choose any organization to publish",
"At least a start date is required": "At least a start date is required",
"Attention": "Attention",
"Automatic archiving": "Automatic archiving",
"Availability": "Availability",
Expand All @@ -47,7 +48,6 @@
"Between": "Between",
"Body Type": "Body Type",
"Bold": "Bold",
"Both dates are required": "Both dates are required",
"Business id": "Business id",
"Cancel": "Cancel",
"Center the full picture": "Center the full picture",
Expand Down
2 changes: 1 addition & 1 deletion udata/core/dataset/api_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@
"TemporalCoverage",
{
"start": fields.ISODateTime(description="The temporal coverage start date", required=True),
"end": fields.ISODateTime(description="The temporal coverage end date", required=True),
"end": fields.ISODateTime(description="The temporal coverage end date"),
},
)

Expand Down
15 changes: 10 additions & 5 deletions udata/core/dataset/rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ def temporal_to_rdf(daterange, graph=None):
pot = graph.resource(BNode())
pot.set(RDF.type, DCT.PeriodOfTime)
pot.set(DCAT.startDate, Literal(daterange.start))
pot.set(DCAT.endDate, Literal(daterange.end))
if daterange.end:
pot.set(DCAT.endDate, Literal(daterange.end))
return pot


Expand Down Expand Up @@ -327,18 +328,22 @@ def temporal_from_resource(resource):
g = Graph().parse(str(resource.identifier))
resource = g.resource(resource.identifier)
if resource.value(SCHEMA.startDate):
end = resource.value(SCHEMA.endDate)
return db.DateRange(
start=resource.value(SCHEMA.startDate).toPython(),
end=resource.value(SCHEMA.endDate).toPython(),
end=end.toPython() if end else None,
)
elif resource.value(DCAT.startDate):
end = resource.value(DCAT.endDate)
return db.DateRange(
start=resource.value(DCAT.startDate).toPython(),
end=resource.value(DCAT.endDate).toPython(),
end=end.toPython() if end else None,
)
elif resource.value(SCV.min):
end = resource.value(SCV.max)
return db.DateRange(
start=resource.value(SCV.min).toPython(), end=resource.value(SCV.max).toPython()
start=resource.value(SCV.min).toPython(),
end=end.toPython() if end else None,
)


Expand Down Expand Up @@ -674,7 +679,7 @@ def dataset_from_rdf(graph: Graph, dataset=None, node=None, remote_url_prefix: s

temporal_coverage = temporal_from_rdf(d.value(DCT.temporal))
if temporal_coverage:
dataset.temporal_coverage = temporal_from_rdf(d.value(DCT.temporal))
dataset.temporal_coverage = temporal_coverage

provenances = provenances_from_rdf(d)
if provenances:
Expand Down
12 changes: 9 additions & 3 deletions udata/forms/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,14 +694,20 @@ def process_formdata(self, valuelist):
value = valuelist[0]
if isinstance(value, str):
start, end = value.split(" - ")
if end is not None:
end = parse(end, yearfirst=True).date()
self.data = db.DateRange(
start=parse(start, yearfirst=True).date(),
end=parse(end, yearfirst=True).date(),
end=end,
)
elif "start" in value and "end" in value:
elif "start" in value:
if value.get("end", None):
end = parse(value["end"], yearfirst=True).date()
else:
end = None
self.data = db.DateRange(
start=parse(value["start"], yearfirst=True).date(),
end=parse(value["end"], yearfirst=True).date(),
end=end,
)
else:
raise validators.ValidationError(_("Unable to parse date range"))
Expand Down
21 changes: 21 additions & 0 deletions udata/tests/api/test_datasets_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,27 @@ def test_dataset_api_update_deleted(self):
self.assertEqual(Dataset.objects.count(), 1)
self.assertEqual(Dataset.objects.first().description, dataset.description)

def test_update_temporal_coverage(self):
user = self.login()
dataset = DatasetFactory(owner=user)
data = dataset.to_dict()
data["temporal_coverage"] = {
"start": "2024-01-01",
"end": "2024-01-31",
}
response = self.put(url_for("api.dataset", dataset=dataset), data)
self.assert200(response)
dataset.reload()
self.assertEqual("2024-01-01", str(dataset.temporal_coverage.start))
self.assertEqual("2024-01-31", str(dataset.temporal_coverage.end))
data = dataset.to_dict()
data["temporal_coverage"] = {"start": "2024-01-01", "end": None}
response = self.put(url_for("api.dataset", dataset=dataset), data)
self.assert200(response)
dataset.reload()
self.assertEqual("2024-01-01", str(dataset.temporal_coverage.start))
self.assertIsNone(dataset.temporal_coverage.end)

def test_dataset_api_update_contact_point(self):
"""It should update a dataset from the API"""
self.login()
Expand Down
27 changes: 27 additions & 0 deletions udata/tests/dataset/test_dataset_rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,19 @@ def test_temporal_coverage(self):
assert pot.value(DCAT.startDate).toPython() == start
assert pot.value(DCAT.endDate).toPython() == end

def test_temporal_coverage_only_start(self):
start = faker.past_date(start_date="-30d")
temporal_coverage = db.DateRange(start=start)
dataset = DatasetFactory(temporal_coverage=temporal_coverage)

d = dataset_to_rdf(dataset)

pot = d.value(DCT.temporal)

assert pot.value(RDF.type).identifier == DCT.PeriodOfTime
assert pot.value(DCAT.startDate).toPython() == start
assert pot.value(DCAT.endDate) is None

def test_from_external_repository(self):
dataset = DatasetFactory(
harvest=HarvestDatasetMetadata(
Expand Down Expand Up @@ -748,6 +761,20 @@ def test_parse_temporal_as_schema_format(self):
assert daterange.start == start
assert daterange.end == end

def test_parse_temporal_as_schema_format_only_start_date(self):
node = BNode()
g = Graph()
start = faker.past_date(start_date="-30d")

g.set((node, RDF.type, DCT.PeriodOfTime))
g.set((node, SCHEMA.startDate, Literal(start)))

daterange = temporal_from_rdf(g.resource(node))

assert isinstance(daterange, db.DateRange)
assert daterange.start == start
assert daterange.end is None

def test_parse_temporal_as_iso_interval(self):
start = faker.past_date(start_date="-30d")
end = faker.future_date(end_date="+30d")
Expand Down
36 changes: 18 additions & 18 deletions udata/translations/udata.pot
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: udata 10.0.1.dev0\n"
"Project-Id-Version: udata 10.0.2.dev0\n"
"Report-Msgid-Bugs-To: [email protected]\n"
"POT-Creation-Date: 2024-11-15 10:00+0100\n"
"PO-Revision-Date: 2024-11-15 10:00+0100\n"
"POT-Creation-Date: 2024-11-19 11:00+0100\n"
"PO-Revision-Date: 2024-11-19 11:00+0100\n"
"Last-Translator: Open Data Team <[email protected]>\n"
"Language: en\n"
"Language-Team: Open Data Team <[email protected]>\n"
Expand Down Expand Up @@ -51,7 +51,7 @@ msgstr ""
msgid "Invalid URL \"{url}\": {reason}"
msgstr ""

#: udata/tests/api/test_datasets_api.py:810 udata/tests/test_model.py:367
#: udata/tests/api/test_datasets_api.py:831 udata/tests/test_model.py:367
#: udata/uris.py:55
msgid "Invalid URL \"{url}\""
msgstr ""
Expand Down Expand Up @@ -205,7 +205,7 @@ msgstr ""
msgid "Your udata instance is ready!"
msgstr ""

#: udata/core/owned.py:53 udata/forms/fields.py:735
#: udata/core/owned.py:53 udata/forms/fields.py:741
#: udata/tests/api/test_dataservices_api.py:407
msgid "You can only set yourself as owner"
msgstr ""
Expand All @@ -214,7 +214,7 @@ msgstr ""
msgid "Unknown organization"
msgstr ""

#: udata/core/owned.py:66 udata/forms/fields.py:756
#: udata/core/owned.py:66 udata/forms/fields.py:762
#: udata/tests/api/test_dataservices_api.py:421
msgid "Permission denied for this organization"
msgstr ""
Expand Down Expand Up @@ -256,12 +256,12 @@ msgstr ""
msgid "At least an email or a contact form is required for a contact point"
msgstr ""

#: udata/core/dataservices/models.py:163 udata/core/dataset/models.py:568
#: udata/core/dataservices/models.py:164 udata/core/dataset/models.py:568
#: udata/mongo/datetime_fields.py:60
msgid "Creation date"
msgstr ""

#: udata/core/dataservices/models.py:168 udata/core/dataset/models.py:571
#: udata/core/dataservices/models.py:169 udata/core/dataset/models.py:571
#: udata/mongo/datetime_fields.py:66
msgid "Last modification date"
msgstr ""
Expand Down Expand Up @@ -484,7 +484,7 @@ msgstr ""
msgid "Related dataset"
msgstr ""

#: udata/core/dataset/forms.py:134 udata/tests/api/test_datasets_api.py:725
#: udata/core/dataset/forms.py:134 udata/tests/api/test_datasets_api.py:746
msgid "Wrong contact point id or contact point ownership mismatch"
msgstr ""

Expand Down Expand Up @@ -558,20 +558,20 @@ msgstr ""
msgid "A schema must contains a name or an URL when a version is provided."
msgstr ""

#: udata/core/dataset/models.py:166 udata/tests/api/test_datasets_api.py:818
#: udata/tests/api/test_datasets_api.py:829
#: udata/core/dataset/models.py:166 udata/tests/api/test_datasets_api.py:839
#: udata/tests/api/test_datasets_api.py:850
msgid "Schema name \"{schema}\" is not an allowed value. Allowed values: {values}"
msgstr ""

#: udata/core/dataset/models.py:185 udata/tests/api/test_datasets_api.py:840
#: udata/core/dataset/models.py:185 udata/tests/api/test_datasets_api.py:861
msgid ""
"Version \"{version}\" is not an allowed value for the schema \"{name}\". "
"Allowed versions: {values}"
msgstr ""

#: udata/core/dataset/models.py:462 udata/core/dataset/rdf.py:503
#: udata/tests/dataset/test_dataset_rdf.py:556
#: udata/core/dataset/models.py:462 udata/core/dataset/rdf.py:508
#: udata/tests/dataset/test_dataset_rdf.py:569
#: udata/tests/dataset/test_dataset_rdf.py:582
msgid "Nameless resource"
msgstr ""

Expand All @@ -583,7 +583,7 @@ msgstr ""
msgid "dataset"
msgstr ""

#: udata/core/dataset/rdf.py:501 udata/tests/dataset/test_dataset_rdf.py:543
#: udata/core/dataset/rdf.py:506 udata/tests/dataset/test_dataset_rdf.py:556
msgid "{format} resource"
msgstr ""

Expand Down Expand Up @@ -943,7 +943,7 @@ msgstr ""
msgid "reuse"
msgstr ""

#: udata/core/reuse/tasks.py:45
#: udata/core/reuse/tasks.py:46
msgid "New reuse"
msgstr ""

Expand Down Expand Up @@ -1154,11 +1154,11 @@ msgstr ""
msgid "Unknown identifiers: {identifiers}"
msgstr ""

#: udata/forms/fields.py:707
#: udata/forms/fields.py:713
msgid "Unable to parse date range"
msgstr ""

#: udata/forms/fields.py:733 udata/forms/fields.py:754
#: udata/forms/fields.py:739 udata/forms/fields.py:760
msgid "You must be authenticated"
msgstr ""

Expand Down