From ddcba716f913d8165410ea46c08c7b8ac3198fda Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:01:37 +1300 Subject: [PATCH 01/16] feat: Require 'linz:asset_summaries' root property --- extensions/linz/examples/collection.json | 1 + extensions/linz/schema.json | 2 ++ extensions/linz/tests/linz_collection.test.js | 17 +++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index 71e8fd94..039480b8 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -12,6 +12,7 @@ "title": "A title", "description": "A description", "license": "Apache-2.0", + "linz:asset_summaries": {}, "linz:lifecycle": "under development", "linz:providers": [ { diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 7130e3dc..8214bef4 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -34,6 +34,7 @@ { "type": "object", "required": [ + "linz:asset_summaries", "linz:geospatial_type", "linz:history", "linz:lifecycle", @@ -940,6 +941,7 @@ } } }, + "linz:asset_summaries": {}, "linz:geospatial_type": {}, "linz:history": { "title": "History", diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 9dea747c..6b6a1742 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -205,6 +205,23 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); + o("Example without the mandatory 'linz:asset_summaries' property should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries']; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => error.instancePath === '' && error.message === "must have required property 'linz:asset_summaries'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Example without the mandatory 'linz:history' field should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); From 9931751a7e33f7fb7748a5b030aa60c46ed1fc04 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:05:58 +1300 Subject: [PATCH 02/16] feat: Require asset summary 'created' propert --- extensions/linz/examples/collection.json | 4 +++- extensions/linz/schema.json | 4 +++- extensions/linz/tests/linz_collection.test.js | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index 039480b8..4b1b2a11 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -12,7 +12,9 @@ "title": "A title", "description": "A description", "license": "Apache-2.0", - "linz:asset_summaries": {}, + "linz:asset_summaries": { + "created": {} + }, "linz:lifecycle": "under development", "linz:providers": [ { diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 8214bef4..23fc118f 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -941,7 +941,9 @@ } } }, - "linz:asset_summaries": {}, + "linz:asset_summaries": { + "required": ["created"] + }, "linz:geospatial_type": {}, "linz:history": { "title": "History", diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 6b6a1742..a71f27ee 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -222,6 +222,24 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); + o("Asset summary without the mandatory 'created' property should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries']['created']; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === '/linz:asset_summaries' && error.message === "must have required property 'created'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Example without the mandatory 'linz:history' field should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); From ed32691c10dd0ed6fdbcae133a6700571fc39373 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:09:55 +1300 Subject: [PATCH 03/16] feat: require asset summary created 'minimum' property --- extensions/linz/examples/collection.json | 4 +++- extensions/linz/schema.json | 7 ++++++- extensions/linz/tests/linz_collection.test.js | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index 4b1b2a11..2c1c9c2d 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -13,7 +13,9 @@ "description": "A description", "license": "Apache-2.0", "linz:asset_summaries": { - "created": {} + "created": { + "minimum": "" + } }, "linz:lifecycle": "under development", "linz:providers": [ diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 23fc118f..76368cf4 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -942,7 +942,12 @@ } }, "linz:asset_summaries": { - "required": ["created"] + "required": ["created"], + "properties": { + "created": { + "required": ["minimum"] + } + } }, "linz:geospatial_type": {}, "linz:history": { diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index a71f27ee..bb3a4517 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -240,6 +240,25 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); + o("Asset summary created without the mandatory 'minimum' property should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries']['created']['minimum']; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === '/linz:asset_summaries/created' && + error.message === "must have required property 'minimum'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Example without the mandatory 'linz:history' field should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); From ab4bf4874f73d2aa2ef386f5b28f3e0a62ff6402 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:42:32 +1300 Subject: [PATCH 04/16] feat: require asset summary created minimum property be a string --- extensions/linz/examples/collection.json | 2 +- extensions/linz/schema.json | 7 ++++++- extensions/linz/tests/linz_collection.test.js | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index 2c1c9c2d..f3afb753 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -14,7 +14,7 @@ "license": "Apache-2.0", "linz:asset_summaries": { "created": { - "minimum": "" + "minimum": "1999-01-01T00:00:00Z" } }, "linz:lifecycle": "under development", diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 76368cf4..194088ed 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -945,7 +945,12 @@ "required": ["created"], "properties": { "created": { - "required": ["minimum"] + "required": ["minimum"], + "properties": { + "minimum": { + "type": "string" + } + } } } }, diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index bb3a4517..aa86cdda 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -259,6 +259,24 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); + o("Asset summary created with invalid 'minimum' value should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + example['linz:asset_summaries']['created']['minimum'] = 1; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === '/linz:asset_summaries/created/minimum' && error.message === 'must be string', + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Example without the mandatory 'linz:history' field should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); From 208c890648ffe30389fbd34e77955108306786d0 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:43:36 +1300 Subject: [PATCH 05/16] feat: require asset summary created minimum property be a datetime --- extensions/linz/schema.json | 3 ++- extensions/linz/tests/linz_collection.test.js | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 194088ed..791cc950 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -948,7 +948,8 @@ "required": ["minimum"], "properties": { "minimum": { - "type": "string" + "type": "string", + "format": "date-time" } } } diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index aa86cdda..8a951147 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -262,7 +262,7 @@ o.spec('LINZ collection', () => { o("Asset summary created with invalid 'minimum' value should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); - example['linz:asset_summaries']['created']['minimum'] = 1; + example['linz:asset_summaries']['created']['minimum'] = 'yesterday'; // when let valid = validate(example); @@ -272,7 +272,8 @@ o.spec('LINZ collection', () => { o( validate.errors.some( (error) => - error.instancePath === '/linz:asset_summaries/created/minimum' && error.message === 'must be string', + error.instancePath === '/linz:asset_summaries/created/minimum' && + error.message === 'must match format "date-time"', ), ).equals(true)(JSON.stringify(validate.errors)); }); From 96f29c05ebb97fd84f739d677c4cd0111ab80489 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:46:05 +1300 Subject: [PATCH 06/16] feat: require asset summary created minimum property be a UTC datetime --- extensions/linz/schema.json | 3 ++- extensions/linz/tests/linz_collection.test.js | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 791cc950..84b54c7f 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -949,7 +949,8 @@ "properties": { "minimum": { "type": "string", - "format": "date-time" + "format": "date-time", + "pattern": "(\\+00:00|Z)$" } } } diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 8a951147..566774e2 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -262,7 +262,7 @@ o.spec('LINZ collection', () => { o("Asset summary created with invalid 'minimum' value should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); - example['linz:asset_summaries']['created']['minimum'] = 'yesterday'; + example['linz:asset_summaries']['created']['minimum'] = '1999-01-01T00:00:00'; // when let valid = validate(example); @@ -273,7 +273,7 @@ o.spec('LINZ collection', () => { validate.errors.some( (error) => error.instancePath === '/linz:asset_summaries/created/minimum' && - error.message === 'must match format "date-time"', + error.message === 'must match pattern "(\\+00:00|Z)$"', ), ).equals(true)(JSON.stringify(validate.errors)); }); From 9a5669d3f450e1305ebe985f7b55b07391ebdcf9 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:48:51 +1300 Subject: [PATCH 07/16] refactor: Pull out UTC datetime definition --- extensions/linz/schema.json | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 84b54c7f..df1ecfd5 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -132,15 +132,11 @@ "properties": { "created": { "title": "Creation time", - "type": "string", - "format": "date-time", - "pattern": "(\\+00:00|Z)$" + "$ref": "#/definitions/utc_datetime" }, "updated": { "title": "Last update time", - "type": "string", - "format": "date-time", - "pattern": "(\\+00:00|Z)$" + "$ref": "#/definitions/utc_datetime" }, "linz:language": { "title": "IETF RFC 5646 language tag", @@ -948,9 +944,7 @@ "required": ["minimum"], "properties": { "minimum": { - "type": "string", - "format": "date-time", - "pattern": "(\\+00:00|Z)$" + "$ref": "#/definitions/utc_datetime" } } } @@ -1064,15 +1058,11 @@ "properties": { "minimum": { "title": "Earliest asset creation time", - "type": "string", - "format": "date-time", - "pattern": "(\\+00:00|Z)$" + "$ref": "#/definitions/utc_datetime" }, "maximum": { "title": "Latest asset creation time", - "type": "string", - "format": "date-time", - "pattern": "(\\+00:00|Z)$" + "$ref": "#/definitions/utc_datetime" } } }, @@ -1082,15 +1072,11 @@ "properties": { "minimum": { "title": "Earliest asset updated time", - "type": "string", - "format": "date-time", - "pattern": "(\\+00:00|Z)$" + "$ref": "#/definitions/utc_datetime" }, "maximum": { "title": "Latest asset updated time", - "type": "string", - "format": "date-time", - "pattern": "(\\+00:00|Z)$" + "$ref": "#/definitions/utc_datetime" } } } @@ -1105,6 +1091,11 @@ "^(?!linz:)": {} }, "additionalProperties": false + }, + "utc_datetime": { + "type": "string", + "format": "date-time", + "pattern": "(\\+00:00|Z)$" } } } From 084f8dd2d276d2884946e0a5edd506bc32a52e82 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:50:01 +1300 Subject: [PATCH 08/16] docs: Set asset/metadata summary created/updated titles --- extensions/linz/schema.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index df1ecfd5..a6ef6b2e 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -944,6 +944,7 @@ "required": ["minimum"], "properties": { "minimum": { + "title": "Earliest asset creation time", "$ref": "#/definitions/utc_datetime" } } @@ -1057,11 +1058,11 @@ "required": ["minimum", "maximum"], "properties": { "minimum": { - "title": "Earliest asset creation time", + "title": "Earliest metadata creation time", "$ref": "#/definitions/utc_datetime" }, "maximum": { - "title": "Latest asset creation time", + "title": "Latest metadata creation time", "$ref": "#/definitions/utc_datetime" } } @@ -1071,11 +1072,11 @@ "required": ["minimum", "maximum"], "properties": { "minimum": { - "title": "Earliest asset updated time", + "title": "Earliest metadata updated time", "$ref": "#/definitions/utc_datetime" }, "maximum": { - "title": "Latest asset updated time", + "title": "Latest metadata updated time", "$ref": "#/definitions/utc_datetime" } } From 7d81ff5fa2246b20c2c05f8ca250738c2995312f Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:53:23 +1300 Subject: [PATCH 09/16] feat: require asset summary created 'maximum' property --- extensions/linz/examples/collection.json | 3 ++- extensions/linz/schema.json | 2 +- extensions/linz/tests/linz_collection.test.js | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index f3afb753..f193b3fc 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -14,7 +14,8 @@ "license": "Apache-2.0", "linz:asset_summaries": { "created": { - "minimum": "1999-01-01T00:00:00Z" + "minimum": "1999-01-01T00:00:00Z", + "maximum": "" } }, "linz:lifecycle": "under development", diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index a6ef6b2e..bdb91404 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -941,7 +941,7 @@ "required": ["created"], "properties": { "created": { - "required": ["minimum"], + "required": ["minimum", "maximum"], "properties": { "minimum": { "title": "Earliest asset creation time", diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 566774e2..07578500 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -259,6 +259,25 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); + o("Asset summary created without the mandatory 'maximum' property should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries']['created']['maximum']; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.dataPath === "['linz:asset_summaries'].created" && + error.message === "should have required property '.maximum'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Asset summary created with invalid 'minimum' value should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); From f401faddcffc04c5fd0aa3fd095a5a783a79a746 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:55:18 +1300 Subject: [PATCH 10/16] feat: require asset summary created maximum property be a UTC datetime --- extensions/linz/examples/collection.json | 2 +- extensions/linz/schema.json | 4 ++++ extensions/linz/tests/linz_collection.test.js | 21 ++++++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index f193b3fc..8d0170fa 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -15,7 +15,7 @@ "linz:asset_summaries": { "created": { "minimum": "1999-01-01T00:00:00Z", - "maximum": "" + "maximum": "2010-01-01T00:00:00Z" } }, "linz:lifecycle": "under development", diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index bdb91404..8707b4a5 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -946,6 +946,10 @@ "minimum": { "title": "Earliest asset creation time", "$ref": "#/definitions/utc_datetime" + }, + "maximum": { + "title": "Latest asset creation time", + "$ref": "#/definitions/utc_datetime" } } } diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 07578500..6aa5e386 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -273,7 +273,7 @@ o.spec('LINZ collection', () => { validate.errors.some( (error) => error.dataPath === "['linz:asset_summaries'].created" && - error.message === "should have required property '.maximum'", + error.message === "should have required property 'maximum'", ), ).equals(true)(JSON.stringify(validate.errors)); }); @@ -297,6 +297,25 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); + o("Asset summary created with invalid 'maximum' value should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + example['linz:asset_summaries']['created']['maximum'] = '1999-01-01T00:00:00'; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.dataPath === "['linz:asset_summaries'].created.maximum" && + error.message === 'should match pattern "(\\+00:00|Z)$"', + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Example without the mandatory 'linz:history' field should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); From abc190f187a542ae8f715287e1bb5fa58478c191 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 11:57:11 +1300 Subject: [PATCH 11/16] feat: require asset summary 'updated' property --- extensions/linz/examples/collection.json | 3 ++- extensions/linz/schema.json | 2 +- extensions/linz/tests/linz_collection.test.js | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index 8d0170fa..ff3a5260 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -16,7 +16,8 @@ "created": { "minimum": "1999-01-01T00:00:00Z", "maximum": "2010-01-01T00:00:00Z" - } + }, + "updated": {} }, "linz:lifecycle": "under development", "linz:providers": [ diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 8707b4a5..b5b5b74f 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -938,7 +938,7 @@ } }, "linz:asset_summaries": { - "required": ["created"], + "required": ["created", "updated"], "properties": { "created": { "required": ["minimum", "maximum"], diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 6aa5e386..b9f45e7d 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -240,6 +240,24 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); + o("Asset summary without the mandatory 'updated' property should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries']['updated']; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.dataPath === "['linz:asset_summaries']" && error.message === "should have required property '.updated'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Asset summary created without the mandatory 'minimum' property should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); From 29d00d21421472a96db1f586e02117d39697911c Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 12:01:46 +1300 Subject: [PATCH 12/16] feat: require asset summary updated 'minimum' property --- extensions/linz/examples/collection.json | 4 +- extensions/linz/schema.json | 3 ++ extensions/linz/tests/linz_collection.test.js | 52 ++++++++++--------- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index ff3a5260..c37718e8 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -17,7 +17,9 @@ "minimum": "1999-01-01T00:00:00Z", "maximum": "2010-01-01T00:00:00Z" }, - "updated": {} + "updated": { + "minimum": "" + } }, "linz:lifecycle": "under development", "linz:providers": [ diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index b5b5b74f..3b006112 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -952,6 +952,9 @@ "$ref": "#/definitions/utc_datetime" } } + }, + "updated": { + "required": ["minimum"] } } }, diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index b9f45e7d..3f9d3046 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -222,28 +222,31 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); - o("Asset summary without the mandatory 'created' property should fail validation", async () => { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - delete example['linz:asset_summaries']['created']; + o("Asset summary without the mandatory 'created'/'updated' properties should fail validation", async () => { + for (const property of ['created', 'updated']) { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries'][property]; - // when - let valid = validate(example); + // when + let valid = validate(example); - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.instancePath === '/linz:asset_summaries' && error.message === "must have required property 'created'", - ), - ).equals(true)(JSON.stringify(validate.errors)); + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === '/linz:asset_summaries' && + error.message === `must have required property '${property}'`, + ), + ).equals(true)(JSON.stringify(validate.errors)); + } }); - o("Asset summary without the mandatory 'updated' property should fail validation", async () => { + o("Asset summary created without the mandatory 'minimum' property should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); - delete example['linz:asset_summaries']['updated']; + delete example['linz:asset_summaries']['created']['minimum']; // when let valid = validate(example); @@ -253,15 +256,16 @@ o.spec('LINZ collection', () => { o( validate.errors.some( (error) => - error.dataPath === "['linz:asset_summaries']" && error.message === "should have required property '.updated'", + error.instancePath === '/linz:asset_summaries/created' && + error.message === "must have required property 'minimum'", ), ).equals(true)(JSON.stringify(validate.errors)); }); - o("Asset summary created without the mandatory 'minimum' property should fail validation", async () => { + o("Asset summary updated without the mandatory 'minimum' property should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); - delete example['linz:asset_summaries']['created']['minimum']; + delete example['linz:asset_summaries']['updated']['minimum']; // when let valid = validate(example); @@ -271,7 +275,7 @@ o.spec('LINZ collection', () => { o( validate.errors.some( (error) => - error.instancePath === '/linz:asset_summaries/created' && + error.instancePath === '/linz:asset_summaries/updated' && error.message === "must have required property 'minimum'", ), ).equals(true)(JSON.stringify(validate.errors)); @@ -290,8 +294,8 @@ o.spec('LINZ collection', () => { o( validate.errors.some( (error) => - error.dataPath === "['linz:asset_summaries'].created" && - error.message === "should have required property 'maximum'", + error.instancePath === '/linz:asset_summaries/created' && + error.message === "must have required property 'maximum'", ), ).equals(true)(JSON.stringify(validate.errors)); }); @@ -328,8 +332,8 @@ o.spec('LINZ collection', () => { o( validate.errors.some( (error) => - error.dataPath === "['linz:asset_summaries'].created.maximum" && - error.message === 'should match pattern "(\\+00:00|Z)$"', + error.instancePath === '/linz:asset_summaries/created/maximum' && + error.message === 'must match pattern "(\\+00:00|Z)$"', ), ).equals(true)(JSON.stringify(validate.errors)); }); From 2662008f4b247068e596b91b21d2dc8167ae9826 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 12:05:52 +1300 Subject: [PATCH 13/16] feat: require asset summary updated minimum property be a UTC datetime --- extensions/linz/examples/collection.json | 2 +- extensions/linz/schema.json | 8 +- extensions/linz/tests/linz_collection.test.js | 83 ++++++++----------- 3 files changed, 42 insertions(+), 51 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index c37718e8..0e1a11c1 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -18,7 +18,7 @@ "maximum": "2010-01-01T00:00:00Z" }, "updated": { - "minimum": "" + "minimum": "1999-01-01T00:00:00Z" } }, "linz:lifecycle": "under development", diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 3b006112..ef03eed3 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -954,7 +954,13 @@ } }, "updated": { - "required": ["minimum"] + "required": ["minimum"], + "properties": { + "minimum": { + "title": "Earliest asset creation time", + "$ref": "#/definitions/utc_datetime" + } + } } } }, diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 3f9d3046..746feff4 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -243,42 +243,25 @@ o.spec('LINZ collection', () => { } }); - o("Asset summary created without the mandatory 'minimum' property should fail validation", async () => { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - delete example['linz:asset_summaries']['created']['minimum']; - - // when - let valid = validate(example); - - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.instancePath === '/linz:asset_summaries/created' && - error.message === "must have required property 'minimum'", - ), - ).equals(true)(JSON.stringify(validate.errors)); - }); - - o("Asset summary updated without the mandatory 'minimum' property should fail validation", async () => { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - delete example['linz:asset_summaries']['updated']['minimum']; + o("Asset summary created/updated without the mandatory 'minimum' property should fail validation", async () => { + for (const property of ['created', 'updated']) { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries'][property]['minimum']; - // when - let valid = validate(example); + // when + let valid = validate(example); - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.instancePath === '/linz:asset_summaries/updated' && - error.message === "must have required property 'minimum'", - ), - ).equals(true)(JSON.stringify(validate.errors)); + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === `/linz:asset_summaries/${property}` && + error.message === "must have required property 'minimum'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + } }); o("Asset summary created without the mandatory 'maximum' property should fail validation", async () => { @@ -300,23 +283,25 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); - o("Asset summary created with invalid 'minimum' value should fail validation", async () => { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - example['linz:asset_summaries']['created']['minimum'] = '1999-01-01T00:00:00'; + o("Asset summary created/updated with invalid 'minimum' value should fail validation", async () => { + for (const property of ['created', 'updated']) { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + example['linz:asset_summaries'][property]['minimum'] = '1999-01-01T00:00:00'; - // when - let valid = validate(example); + // when + let valid = validate(example); - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.instancePath === '/linz:asset_summaries/created/minimum' && - error.message === 'must match pattern "(\\+00:00|Z)$"', - ), - ).equals(true)(JSON.stringify(validate.errors)); + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === `/linz:asset_summaries/${property}/minimum` && + error.message === 'must match pattern "(\\+00:00|Z)$"', + ), + ).equals(true)(JSON.stringify(validate.errors)); + } }); o("Asset summary created with invalid 'maximum' value should fail validation", async () => { From 16b24877f10b5e58a2b1529880a98c9e578f5d0c Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 12:10:17 +1300 Subject: [PATCH 14/16] feat: require asset summary updated 'maximum' property --- extensions/linz/examples/collection.json | 3 ++- extensions/linz/schema.json | 4 ++-- extensions/linz/tests/linz_collection.test.js | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index 0e1a11c1..928bc120 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -18,7 +18,8 @@ "maximum": "2010-01-01T00:00:00Z" }, "updated": { - "minimum": "1999-01-01T00:00:00Z" + "minimum": "1999-01-01T00:00:00Z", + "maximum": "" } }, "linz:lifecycle": "under development", diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index ef03eed3..71554f3a 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -954,10 +954,10 @@ } }, "updated": { - "required": ["minimum"], + "required": ["minimum", "maximum"], "properties": { "minimum": { - "title": "Earliest asset creation time", + "title": "Earliest asset updated time", "$ref": "#/definitions/utc_datetime" } } diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 746feff4..386d2fb2 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -283,6 +283,25 @@ o.spec('LINZ collection', () => { ).equals(true)(JSON.stringify(validate.errors)); }); + o("Asset summary updated without the mandatory 'maximum' property should fail validation", async () => { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries']['updated']['maximum']; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.dataPath === "['linz:asset_summaries'].updated" && + error.message === "should have required property '.maximum'", + ), + ).equals(true)(JSON.stringify(validate.errors)); + }); + o("Asset summary created/updated with invalid 'minimum' value should fail validation", async () => { for (const property of ['created', 'updated']) { // given From 97325bcd57039e20889dec9a08d10d361fae87f4 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Mon, 15 Nov 2021 12:17:28 +1300 Subject: [PATCH 15/16] feat: require asset summary updated maximum property be a UTC datetime --- extensions/linz/examples/collection.json | 2 +- extensions/linz/schema.json | 4 + extensions/linz/tests/linz_collection.test.js | 142 ++++++------------ 3 files changed, 51 insertions(+), 97 deletions(-) diff --git a/extensions/linz/examples/collection.json b/extensions/linz/examples/collection.json index 928bc120..9611b8df 100644 --- a/extensions/linz/examples/collection.json +++ b/extensions/linz/examples/collection.json @@ -19,7 +19,7 @@ }, "updated": { "minimum": "1999-01-01T00:00:00Z", - "maximum": "" + "maximum": "2010-01-01T00:00:00Z" } }, "linz:lifecycle": "under development", diff --git a/extensions/linz/schema.json b/extensions/linz/schema.json index 71554f3a..42e9e230 100644 --- a/extensions/linz/schema.json +++ b/extensions/linz/schema.json @@ -959,6 +959,10 @@ "minimum": { "title": "Earliest asset updated time", "$ref": "#/definitions/utc_datetime" + }, + "maximum": { + "title": "Latest asset updated time", + "$ref": "#/definitions/utc_datetime" } } } diff --git a/extensions/linz/tests/linz_collection.test.js b/extensions/linz/tests/linz_collection.test.js index 386d2fb2..50a64c3e 100644 --- a/extensions/linz/tests/linz_collection.test.js +++ b/extensions/linz/tests/linz_collection.test.js @@ -243,105 +243,55 @@ o.spec('LINZ collection', () => { } }); - o("Asset summary created/updated without the mandatory 'minimum' property should fail validation", async () => { - for (const property of ['created', 'updated']) { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - delete example['linz:asset_summaries'][property]['minimum']; - - // when - let valid = validate(example); - - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.instancePath === `/linz:asset_summaries/${property}` && - error.message === "must have required property 'minimum'", - ), - ).equals(true)(JSON.stringify(validate.errors)); - } - }); - - o("Asset summary created without the mandatory 'maximum' property should fail validation", async () => { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - delete example['linz:asset_summaries']['created']['maximum']; - - // when - let valid = validate(example); - - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.instancePath === '/linz:asset_summaries/created' && - error.message === "must have required property 'maximum'", - ), - ).equals(true)(JSON.stringify(validate.errors)); - }); - - o("Asset summary updated without the mandatory 'maximum' property should fail validation", async () => { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - delete example['linz:asset_summaries']['updated']['maximum']; - - // when - let valid = validate(example); - - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.dataPath === "['linz:asset_summaries'].updated" && - error.message === "should have required property '.maximum'", - ), - ).equals(true)(JSON.stringify(validate.errors)); - }); - - o("Asset summary created/updated with invalid 'minimum' value should fail validation", async () => { - for (const property of ['created', 'updated']) { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - example['linz:asset_summaries'][property]['minimum'] = '1999-01-01T00:00:00'; - - // when - let valid = validate(example); - - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.instancePath === `/linz:asset_summaries/${property}/minimum` && - error.message === 'must match pattern "(\\+00:00|Z)$"', - ), - ).equals(true)(JSON.stringify(validate.errors)); + o( + "Asset summary created/updated without the mandatory 'minimum'/'maximum' properties should fail validation", + async () => { + for (const outerProperty of ['created', 'updated']) { + for (const innerProperty of ['minimum', 'maximum']) { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + delete example['linz:asset_summaries'][outerProperty][innerProperty]; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === `/linz:asset_summaries/${outerProperty}` && + error.message === `must have required property '${innerProperty}'`, + ), + ).equals(true)(JSON.stringify(validate.errors)); + } + } + }, + ); + + o("Asset summary created/updated with invalid 'minimum'/'maximum' value should fail validation", async () => { + for (const outerProperty of ['created', 'updated']) { + for (const innerProperty of ['minimum', 'maximum']) { + // given + const example = JSON.parse(await fs.readFile(examplePath)); + example['linz:asset_summaries'][outerProperty][innerProperty] = '1999-01-01T00:00:00'; + + // when + let valid = validate(example); + + // then + o(valid).equals(false); + o( + validate.errors.some( + (error) => + error.instancePath === `/linz:asset_summaries/${outerProperty}/${innerProperty}` && + error.message === 'must match pattern "(\\+00:00|Z)$"', + ), + ).equals(true)(JSON.stringify(validate.errors)); + } } }); - o("Asset summary created with invalid 'maximum' value should fail validation", async () => { - // given - const example = JSON.parse(await fs.readFile(examplePath)); - example['linz:asset_summaries']['created']['maximum'] = '1999-01-01T00:00:00'; - - // when - let valid = validate(example); - - // then - o(valid).equals(false); - o( - validate.errors.some( - (error) => - error.instancePath === '/linz:asset_summaries/created/maximum' && - error.message === 'must match pattern "(\\+00:00|Z)$"', - ), - ).equals(true)(JSON.stringify(validate.errors)); - }); - o("Example without the mandatory 'linz:history' field should fail validation", async () => { // given const example = JSON.parse(await fs.readFile(examplePath)); From 1aedd9b830364dafa492f37f72f7926c72b2b7d1 Mon Sep 17 00:00:00 2001 From: Victor Engmark Date: Wed, 24 Nov 2021 11:48:22 +1300 Subject: [PATCH 16/16] docs: Move asset summary documentation to right property --- extensions/linz/README.md | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/extensions/linz/README.md b/extensions/linz/README.md index 91b1528e..1dbd21a7 100644 --- a/extensions/linz/README.md +++ b/extensions/linz/README.md @@ -63,28 +63,34 @@ See [ISO/IEC 13249-3:2016(en)](https://www.iso.org/obp/ui/#!iso:std:60343:en) fo ## Collection Fields -| Field Name | Type | Description | -| ---------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| title | string | **REQUIRED**. Collection title. | -| linz:geospatial_type | string | **REQUIRED**. A general description of the type of content that can be found in the dataset. See the [list of accepted geospatial types](#geospatial-types). | -| linz:history | string | **REQUIRED**. A descriptive statement about the lineage/history of a dataset | -| linz:lifecycle | string | **REQUIRED**. Lifecycle Status of Collection. Must be one of `under development`, `preview`, `ongoing`, `completed`, `deprecated`. | -| linz:providers | LINZ Provider Object | **REQUIRED**. The object provides information about a provider with additional roles defined by Toitū Te Whenua LINZ. A provider is any of the organizations that captures or processes the content of the assets and therefore influences the data offered by the STAC implementation. See [LINZ Provider Object](#linz-provider-object). | -| providers | Provider Object | **REQUIRED**. The object provides information about a provider. A provider is any of the organizations that captures or processes the content of the assets and therefore influences the data offered by the STAC implementation. See [Provider Object](#provider-object). | -| linz:security_classification | string | **REQUIRED**. New Zealand Government [Security Classification](https://www.digital.govt.nz/standards-and-guidance/governance/managing-online-channels/security-and-privacy-for-websites/foundations/classify-information/). Must be one of `unclassified`, `in-confidence`, `sensitive`, `restricted`, `confidential`, `secret` or `top-secret`. | -| linz:update_frequency | string | Recommended. Indicates how frequently an updated dataset may be distributed to the publication platform. Must follow the format for durations as defined in [RFC3339](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A). For example, `P3D` expresses a duration of 3 days. | -| processing:software | Map | Recommended. The software and versions which were used to generate the dataset. See [reference](https://github.com/stac-extensions/processing). | - -### Collection Summaries Object Fields +| Field Name | Type | Description | +| ---------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| title | string | **REQUIRED**. Collection title. | +| linz:asset_summaries | Map> | **REQUIRED**. See [Custom Collection Summaries Object Fields](#custom-collection-summaries-object-fields). | +| linz:geospatial_type | string | **REQUIRED**. A general description of the type of content that can be found in the dataset. See the [list of accepted geospatial types](#geospatial-types). | +| linz:history | string | **REQUIRED**. A descriptive statement about the lineage/history of a dataset | +| linz:lifecycle | string | **REQUIRED**. Lifecycle Status of Collection. Must be one of `under development`, `preview`, `ongoing`, `completed`, `deprecated`. | +| linz:providers | LINZ Provider Object | **REQUIRED**. The object provides information about a provider with additional roles defined by Toitū Te Whenua LINZ. A provider is any of the organizations that captures or processes the content of the assets and therefore influences the data offered by the STAC implementation. See [LINZ Provider Object](#linz-provider-object). | +| providers | Provider Object | **REQUIRED**. The object provides information about a provider. A provider is any of the organizations that captures or processes the content of the assets and therefore influences the data offered by the STAC implementation. See [Provider Object](#provider-object). | +| linz:security_classification | string | **REQUIRED**. New Zealand Government [Security Classification](https://www.digital.govt.nz/standards-and-guidance/governance/managing-online-channels/security-and-privacy-for-websites/foundations/classify-information/). Must be one of `unclassified`, `in-confidence`, `sensitive`, `restricted`, `confidential`, `secret` or `top-secret`. | +| linz:update_frequency | string | Recommended. Indicates how frequently an updated dataset may be distributed to the publication platform. Must follow the format for durations as defined in [RFC3339](https://datatracker.ietf.org/doc/html/rfc3339#appendix-A). For example, `P3D` expresses a duration of 3 days. | +| processing:software | Map | Recommended. The software and versions which were used to generate the dataset. See [reference](https://github.com/stac-extensions/processing). | + +### Custom Collection Summaries Object Fields | Field Name | Type | Description | | --------------- | --------- | -------------------------------------------------------------------- | -| title | string | **REQUIRED**. Collection title. | | created/minimum | date-time | **REQUIRED**. Earliest [asset created value](#asset-fields), in UTC. | | created/maximum | date-time | **REQUIRED**. Latest [asset created value](#asset-fields), in UTC. | | updated/minimum | date-time | **REQUIRED**. Earliest [asset updated value](#asset-fields), in UTC. | | updated/maximum | date-time | **REQUIRED**. Latest [asset updated value](#asset-fields), in UTC. | +### Collection Summaries Object Fields + +| Field Name | Type | Description | +| ---------- | ------ | ------------------------------- | +| title | string | **REQUIRED**. Collection title. | + ### LINZ Provider Object Fields This expands on the [provider object in the STAC spec](https://github.com/radiantearth/stac-spec/blob/v1.0.0/item-spec/common-metadata.md#provider-object). Only differences from that definition are mentioned here.