From c1736a45cfec85bb3a968356145a8b4228ecc8c3 Mon Sep 17 00:00:00 2001
From: Alice Fage <afage@linz.govt.nz>
Date: Thu, 9 Dec 2021 15:35:57 +1300
Subject: [PATCH 1/4] feat: require additional fields for historical imagery

---
 extensions/aerial-photo/schema.json           |  2 +-
 .../tests/aerial_photo_collection.test.js     | 12 +++++++
 .../camera/tests/camera_collection.test.js    | 14 ++++++++
 extensions/film/schema.json                   |  2 +-
 extensions/film/tests/film_collection.test.js | 12 +++++++
 .../examples/collection.json                  | 34 +++++++++++++++++++
 .../historical-imagery/examples/item.json     | 15 ++++++--
 extensions/historical-imagery/schema.json     |  9 +++--
 .../historical-imagery_collection.test.js     | 34 +++++++++++++++++++
 .../tests/historical-imagery_item.test.js     | 16 +++++++++
 .../tests/scanning_collection.test.js         | 14 ++++++++
 11 files changed, 157 insertions(+), 7 deletions(-)

diff --git a/extensions/aerial-photo/schema.json b/extensions/aerial-photo/schema.json
index fedf2041..4aa48fb2 100644
--- a/extensions/aerial-photo/schema.json
+++ b/extensions/aerial-photo/schema.json
@@ -58,7 +58,7 @@
           "type": "object",
           "allOf": [
             {
-              "required": ["type", "summaries"]
+              "required": ["type"]
             },
             {
               "$ref": "#/definitions/fields"
diff --git a/extensions/aerial-photo/tests/aerial_photo_collection.test.js b/extensions/aerial-photo/tests/aerial_photo_collection.test.js
index 8fead2b5..9934338e 100644
--- a/extensions/aerial-photo/tests/aerial_photo_collection.test.js
+++ b/extensions/aerial-photo/tests/aerial_photo_collection.test.js
@@ -30,6 +30,18 @@ o.spec('Aerial Photo Extension Collection', () => {
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
 
+  o("Missing summaries section should pass validation", async () => {
+    // given
+    const example = JSON.parse(await fs.readFile(examplePath));
+    delete example.summaries;
+
+    // when
+    let valid = validate(example);
+
+    // then
+    o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
+  });
+
   o("Summaries with no 'aerial-photo:run' property should fail validation", async () => {
     // given
     const example = JSON.parse(await fs.readFile(examplePath));
diff --git a/extensions/camera/tests/camera_collection.test.js b/extensions/camera/tests/camera_collection.test.js
index 967f8dc4..1b317279 100644
--- a/extensions/camera/tests/camera_collection.test.js
+++ b/extensions/camera/tests/camera_collection.test.js
@@ -29,4 +29,18 @@ o.spec('Camera Extension Collection', () => {
     // then
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
+
+  o("Missing summaries section should pass validation", async () => {
+    // given
+    const example = JSON.parse(await fs.readFile(examplePath));
+    delete example.summaries;
+
+    // when
+    let valid = validate(example);
+
+    // then
+    o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
+  });
+
+
 });
diff --git a/extensions/film/schema.json b/extensions/film/schema.json
index 8312b1d6..5ae73a27 100644
--- a/extensions/film/schema.json
+++ b/extensions/film/schema.json
@@ -58,7 +58,7 @@
           "type": "object",
           "allOf": [
             {
-              "required": ["type", "summaries"]
+              "required": ["type"]
             },
             {
               "$ref": "#/definitions/fields"
diff --git a/extensions/film/tests/film_collection.test.js b/extensions/film/tests/film_collection.test.js
index 3496f60f..f18016a2 100644
--- a/extensions/film/tests/film_collection.test.js
+++ b/extensions/film/tests/film_collection.test.js
@@ -30,6 +30,18 @@ o.spec('Film Extension Collection', () => {
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
 
+  o("Missing summaries section should pass validation", async () => {
+    // given
+    const example = JSON.parse(await fs.readFile(examplePath));
+    delete example.summaries;
+
+    // when
+    let valid = validate(example);
+
+    // then
+    o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
+  });
+
   o("Summaries with no 'film:id' property should fail validation", async () => {
     // given
     const example = JSON.parse(await fs.readFile(examplePath));
diff --git a/extensions/historical-imagery/examples/collection.json b/extensions/historical-imagery/examples/collection.json
index 2be2229b..8c0208d9 100644
--- a/extensions/historical-imagery/examples/collection.json
+++ b/extensions/historical-imagery/examples/collection.json
@@ -3,9 +3,13 @@
   "stac_version": "1.0.0",
   "stac_extensions": [
     "https://stac.linz.govt.nz/_STAC_VERSION_/historical-imagery/schema.json",
+    "https://stac.linz.govt.nz/_STAC_VERSION_/linz/schema.json",
+    "https://stac.linz.govt.nz/_STAC_VERSION_/quality/schema.json",
     "https://stac-extensions.github.io/eo/v1.0.0/schema.json",
+    "https://stac-extensions.github.io/processing/v1.0.0/schema.json",
     "https://stac-extensions.github.io/projection/v1.0.0/schema.json",
     "https://stac-extensions.github.io/file/v2.0.0/schema.json",
+    "https://stac-extensions.github.io/version/v1.0.0/schema.json",
     "https://stac.linz.govt.nz/_STAC_VERSION_/aerial-photo/schema.json",
     "https://stac.linz.govt.nz/_STAC_VERSION_/camera/schema.json",
     "https://stac.linz.govt.nz/_STAC_VERSION_/film/schema.json",
@@ -23,6 +27,32 @@
       "interval": [["1947-03-28T12:00:00Z", "1952-04-22T12:00:00Z"]]
     }
   },
+  "linz:security_classification": "unclassified",
+  "linz:lifecycle": "completed",
+  "linz:history": "LINZ and its predecessors, Lands & Survey and Department of Survey and Land Information (DOSLI), commissioned aerial photography for the Crown between 1936 and 2008.\nOne of the predominant uses of the aerial photography at the time was the photogrammetric mapping of New Zealand, initially at 1inch to 1mile followed by the NZMS 260 and Topo50 map series at 1:50,000.\nThese photographs were scanned through the Crown Aerial Film Archive scanning project.",
+  "linz:providers": [
+    {
+      "name": "Toitū Te Whenua LINZ",
+      "description": "The New Zealand Government's lead agency for location and property information, Crown land and managing overseas investment.",
+      "roles": ["custodian"],
+      "url": "https://www.linz.govt.nz/about-linz/what-were-doing/projects/crown-aerial-film-archive-historical-imagery-scanning-project"
+    },
+    {
+      "name": "Manager Partnership Programmes",
+      "roles": ["manager"]
+    }
+  ],
+  "linz:geospatial_type": "black and white image",
+  "linz:asset_summaries": {
+    "created": {
+      "minimum": "1999-01-01T00:00:00Z",
+      "maximum": "2021-12-09T00:04:09Z"
+    },
+    "updated": {
+      "minimum": "1999-01-02T00:00:00Z",
+      "maximum": "2021-12-09T00:04:09Z"
+    }
+  },
   "providers": [
     {
       "name": "NZ Aerial Mapping",
@@ -36,6 +66,10 @@
       "url": "https://www.linz.govt.nz/about-linz/what-were-doing/projects/crown-aerial-film-archive-historical-imagery-scanning-project"
     }
   ],
+  "processing:software": {
+    "Topo Processor": "0.1.0"
+  },
+  "version": "1",
   "summaries": {
     "platform": ["Fixed-wing Aircraft"],
     "instruments": ["EAGLE IV"],
diff --git a/extensions/historical-imagery/examples/item.json b/extensions/historical-imagery/examples/item.json
index ca9bea6e..a4dea4db 100644
--- a/extensions/historical-imagery/examples/item.json
+++ b/extensions/historical-imagery/examples/item.json
@@ -1,16 +1,19 @@
 {
+  "type": "Feature",
   "stac_version": "1.0.0",
   "stac_extensions": [
     "https://stac.linz.govt.nz/_STAC_VERSION_/historical-imagery/schema.json",
+    "https://stac.linz.govt.nz/_STAC_VERSION_/linz/schema.json",
     "https://stac-extensions.github.io/eo/v1.0.0/schema.json",
+    "https://stac-extensions.github.io/processing/v1.0.0/schema.json",
     "https://stac-extensions.github.io/projection/v1.0.0/schema.json",
     "https://stac-extensions.github.io/file/v2.0.0/schema.json",
+    "https://stac-extensions.github.io/version/v1.0.0/schema.json",
     "https://stac.linz.govt.nz/_STAC_VERSION_/aerial-photo/schema.json",
     "https://stac.linz.govt.nz/_STAC_VERSION_/camera/schema.json",
     "https://stac.linz.govt.nz/_STAC_VERSION_/film/schema.json",
     "https://stac.linz.govt.nz/_STAC_VERSION_/scanning/schema.json"
   ],
-  "type": "Feature",
   "id": "215354",
   "bbox": [170.54524, -45.80237, 170.56431, -45.81345],
   "geometry": {
@@ -44,7 +47,11 @@
     "film:physical_condition": "Film scratched",
     "film:physical_size": "18cm x 23cm",
     "scan:is_original": true,
-    "scan:scanned": "2018-09-30T11:00:00Z"
+    "scan:scanned": "2018-09-30T11:00:00Z",
+    "processing:software": {
+      "Topo Processor": "0.1.0"
+    },
+    "version": "1"
   },
   "links": [
     {
@@ -68,7 +75,9 @@
           "name": "gray",
           "common_name": "pan"
         }
-      ]
+      ],
+      "created": "2021-12-09T00:04:09Z",
+      "updated": "2021-12-09T00:04:09Z"
     }
   },
   "collection": "01FJ0SE46TT5TGBHBVX64TMEPA"
diff --git a/extensions/historical-imagery/schema.json b/extensions/historical-imagery/schema.json
index 1f2e41bd..7fda438a 100644
--- a/extensions/historical-imagery/schema.json
+++ b/extensions/historical-imagery/schema.json
@@ -29,7 +29,7 @@
               "properties": {
                 "type": "object",
                 "$comment": "Require fields here for Item Properties.",
-                "required": ["platform", "mission"]
+                "required": ["platform", "mission", "processing:software"]
               },
               "assets": {
                 "type": "object",
@@ -57,7 +57,7 @@
           "allOf": [
             {
               "type": "object",
-              "required": ["type", "title", "providers", "summaries"]
+              "required": ["type", "title", "providers", "summaries", "processing:software"]
             }
           ]
         },
@@ -78,6 +78,11 @@
                 "const": "https://stac.linz.govt.nz/_STAC_VERSION_/historical-imagery/schema.json"
               }
             },
+            {
+              "contains": {
+                "const": "https://stac.linz.govt.nz/_STAC_VERSION_/linz/schema.json"
+              }
+            },
             {
               "contains": {
                 "const": "https://stac-extensions.github.io/eo/v1.0.0/schema.json"
diff --git a/extensions/historical-imagery/tests/historical-imagery_collection.test.js b/extensions/historical-imagery/tests/historical-imagery_collection.test.js
index e421160b..f74ebd56 100644
--- a/extensions/historical-imagery/tests/historical-imagery_collection.test.js
+++ b/extensions/historical-imagery/tests/historical-imagery_collection.test.js
@@ -79,6 +79,23 @@ o.spec('Historical Imagery Extension Collection', () => {
     );
   });
 
+  o("Example with missing 'processing:software' property should fail validation", async () => {
+    // given
+    const example = JSON.parse(await fs.readFile(examplePath));
+    delete example['processing:software'];
+
+    // when
+    let valid = validate(example);
+
+    // then
+    o(valid).equals(false);
+    o(
+      validate.errors.some(
+        (error) => error.instancePath === '' && error.message === "must have required property 'processing:software'",
+      ),
+    ).equals(true)(JSON.stringify(validate.errors));
+  });
+
   o("Example without 'providers' should fail validation", async () => {
     // given
     const example = JSON.parse(await fs.readFile(examplePath));
@@ -227,4 +244,21 @@ o.spec('Historical Imagery Extension Collection', () => {
     // then
     o(valid).equals(true);
   });
+
+  o("Summaries with no 'summaries' should fail validation", async () => {
+    // given
+    const example = JSON.parse(await fs.readFile(examplePath));
+    delete example.summaries;
+
+    // when
+    let valid = validate(example);
+
+    // then
+    o(valid).equals(false);
+    o(
+      validate.errors.some(
+        (error) => error.instancePath === '' && error.message === "must have required property 'summaries'",
+      ),
+    ).equals(true)(JSON.stringify(validate.errors));
+  });
 });
diff --git a/extensions/historical-imagery/tests/historical-imagery_item.test.js b/extensions/historical-imagery/tests/historical-imagery_item.test.js
index d6c421f8..3f49bb58 100644
--- a/extensions/historical-imagery/tests/historical-imagery_item.test.js
+++ b/extensions/historical-imagery/tests/historical-imagery_item.test.js
@@ -122,4 +122,20 @@ o.spec('Historical Imagery Extension Item', () => {
       ),
     ).equals(true)(JSON.stringify(validate.errors));
   });
+
+  o("Example without mandatory 'processing:software' property should fail validation", async () => {
+    // given
+    const example = JSON.parse(await fs.readFile(examplePath));
+    delete example.properties['processing:software'];
+    // when
+    let valid = validate(example);
+
+    // then
+    o(valid).equals(false);
+    o(
+      validate.errors.some(
+        (error) => error.instancePath === '/properties' && error.message === "must have required property 'processing:software'",
+      ),
+    ).equals(true)(JSON.stringify(validate.errors));
+  });
 });
diff --git a/extensions/scanning/tests/scanning_collection.test.js b/extensions/scanning/tests/scanning_collection.test.js
index 7db6152d..54ded5d5 100644
--- a/extensions/scanning/tests/scanning_collection.test.js
+++ b/extensions/scanning/tests/scanning_collection.test.js
@@ -29,4 +29,18 @@ o.spec('Scanning Extension Collection', () => {
     // then
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
+
+  o("Missing summaries section should pass validation", async () => {
+    // given
+    const example = JSON.parse(await fs.readFile(examplePath));
+    delete example.summaries;
+
+    // when
+    let valid = validate(example);
+
+    // then
+    o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
+  });
+
+
 });

From 3fa81f9d12a9d18ff600daf8ec29299968880a9b Mon Sep 17 00:00:00 2001
From: Alice Fage <afage@linz.govt.nz>
Date: Thu, 9 Dec 2021 15:40:52 +1300
Subject: [PATCH 2/4] fix: linting

---
 extensions/aerial-photo/tests/aerial_photo_collection.test.js | 2 +-
 extensions/camera/tests/camera_collection.test.js             | 4 +---
 extensions/film/tests/film_collection.test.js                 | 2 +-
 .../historical-imagery/tests/historical-imagery_item.test.js  | 3 ++-
 extensions/scanning/tests/scanning_collection.test.js         | 4 +---
 5 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/extensions/aerial-photo/tests/aerial_photo_collection.test.js b/extensions/aerial-photo/tests/aerial_photo_collection.test.js
index 9934338e..b1f124bc 100644
--- a/extensions/aerial-photo/tests/aerial_photo_collection.test.js
+++ b/extensions/aerial-photo/tests/aerial_photo_collection.test.js
@@ -30,7 +30,7 @@ o.spec('Aerial Photo Extension Collection', () => {
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
 
-  o("Missing summaries section should pass validation", async () => {
+  o('Missing summaries section should pass validation', async () => {
     // given
     const example = JSON.parse(await fs.readFile(examplePath));
     delete example.summaries;
diff --git a/extensions/camera/tests/camera_collection.test.js b/extensions/camera/tests/camera_collection.test.js
index 1b317279..971e3cc1 100644
--- a/extensions/camera/tests/camera_collection.test.js
+++ b/extensions/camera/tests/camera_collection.test.js
@@ -30,7 +30,7 @@ o.spec('Camera Extension Collection', () => {
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
 
-  o("Missing summaries section should pass validation", async () => {
+  o('Missing summaries section should pass validation', async () => {
     // given
     const example = JSON.parse(await fs.readFile(examplePath));
     delete example.summaries;
@@ -41,6 +41,4 @@ o.spec('Camera Extension Collection', () => {
     // then
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
-
-
 });
diff --git a/extensions/film/tests/film_collection.test.js b/extensions/film/tests/film_collection.test.js
index f18016a2..c60a8638 100644
--- a/extensions/film/tests/film_collection.test.js
+++ b/extensions/film/tests/film_collection.test.js
@@ -30,7 +30,7 @@ o.spec('Film Extension Collection', () => {
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
 
-  o("Missing summaries section should pass validation", async () => {
+  o('Missing summaries section should pass validation', async () => {
     // given
     const example = JSON.parse(await fs.readFile(examplePath));
     delete example.summaries;
diff --git a/extensions/historical-imagery/tests/historical-imagery_item.test.js b/extensions/historical-imagery/tests/historical-imagery_item.test.js
index 3f49bb58..5f6e6d2e 100644
--- a/extensions/historical-imagery/tests/historical-imagery_item.test.js
+++ b/extensions/historical-imagery/tests/historical-imagery_item.test.js
@@ -134,7 +134,8 @@ o.spec('Historical Imagery Extension Item', () => {
     o(valid).equals(false);
     o(
       validate.errors.some(
-        (error) => error.instancePath === '/properties' && error.message === "must have required property 'processing:software'",
+        (error) =>
+          error.instancePath === '/properties' && error.message === "must have required property 'processing:software'",
       ),
     ).equals(true)(JSON.stringify(validate.errors));
   });
diff --git a/extensions/scanning/tests/scanning_collection.test.js b/extensions/scanning/tests/scanning_collection.test.js
index 54ded5d5..5e0efd10 100644
--- a/extensions/scanning/tests/scanning_collection.test.js
+++ b/extensions/scanning/tests/scanning_collection.test.js
@@ -30,7 +30,7 @@ o.spec('Scanning Extension Collection', () => {
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
 
-  o("Missing summaries section should pass validation", async () => {
+  o('Missing summaries section should pass validation', async () => {
     // given
     const example = JSON.parse(await fs.readFile(examplePath));
     delete example.summaries;
@@ -41,6 +41,4 @@ o.spec('Scanning Extension Collection', () => {
     // then
     o(valid).equals(true)(JSON.stringify(validate.errors, null, 2));
   });
-
-
 });

From b3a0eab7db4545f9b7c4ed759153b6d61735a14c Mon Sep 17 00:00:00 2001
From: Alice Fage <afage@linz.govt.nz>
Date: Thu, 9 Dec 2021 15:51:11 +1300
Subject: [PATCH 3/4] fix: added git tag example to readme

---
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 09ec90dc..e3922781 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,8 @@ Verify changes by running `yarn lint && yarn test` before committing.
 To create a release:
 
 1. Run `yarn version --new-version <patch|minor|major>` which will create a change log commit and version tag.
-2. Run `git push --atomic origin master TAG` which will trigger a GitHub release job. This will publish the new version to the "gh-pages" branch.
+2. Run `git push --atomic origin master TAG` (e.g. `git push --atomic origin master v0.0.14`) which will trigger a GitHub release job.
+   This will publish the new version to the "gh-pages" branch.
 
 ## Adding a new extension
 

From 98a13f3b1a84c20c6bd8e56101d03ba9df140a2e Mon Sep 17 00:00:00 2001
From: Alice Fage <afage@linz.govt.nz>
Date: Thu, 9 Dec 2021 16:09:44 +1300
Subject: [PATCH 4/4] fix: fixed typo

---
 .../tests/historical-imagery_collection.test.js                 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/extensions/historical-imagery/tests/historical-imagery_collection.test.js b/extensions/historical-imagery/tests/historical-imagery_collection.test.js
index f74ebd56..f54ee749 100644
--- a/extensions/historical-imagery/tests/historical-imagery_collection.test.js
+++ b/extensions/historical-imagery/tests/historical-imagery_collection.test.js
@@ -245,7 +245,7 @@ o.spec('Historical Imagery Extension Collection', () => {
     o(valid).equals(true);
   });
 
-  o("Summaries with no 'summaries' should fail validation", async () => {
+  o("Example with no 'summaries' should fail validation", async () => {
     // given
     const example = JSON.parse(await fs.readFile(examplePath));
     delete example.summaries;