@cumulus/cmrjs 9.9.0 → 10.0.0-beta.0

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.
package/src/cmr-utils.js CHANGED
@@ -65,12 +65,13 @@ function getFileDescription(file, urlType = 'distribution') {
65
65
  return filename ? `Download ${filename}` : 'File to download';
66
66
  }
67
67
 
68
- const isECHO10File = (filename) => filename.endsWith('cmr.xml');
69
- const isUMMGFile = (filename) => filename.endsWith('cmr.json');
70
- const isISOFile = (filename) => filename.endsWith('cmr_iso.xml');
71
- const isCMRFilename = (filename) => isECHO10File(filename)
72
- || isUMMGFile(filename)
73
- || isISOFile(filename);
68
+ const isECHO10Filename = (filename) => filename.endsWith('cmr.xml');
69
+ const isUMMGFilename = (filename) => filename.endsWith('cmr.json');
70
+ const isISOFilename = (filename) => filename.endsWith('.iso.xml');
71
+ const isCMRISOFilename = (filename) => filename.endsWith('cmr_iso.xml');
72
+ const isCMRFilename = (filename) => isECHO10Filename(filename)
73
+ || isUMMGFilename(filename)
74
+ || isCMRISOFilename(filename);
74
75
 
75
76
  const constructCmrConceptLink = (conceptId, extension) => `${getSearchUrl()}concepts/${conceptId}.${extension}`;
76
77
 
@@ -85,6 +86,17 @@ function isCMRFile(fileobject) {
85
86
  return isCMRFilename(cmrfilename);
86
87
  }
87
88
 
89
+ /**
90
+ * Returns True if this object can be determined to be an ISO file object.
91
+ *
92
+ * @param {Object} fileobject
93
+ * @returns {boolean} true if object references an ISO file metadata.
94
+ */
95
+ function isISOFile(fileobject) {
96
+ const filename = fileobject.key || fileobject.name || fileobject.filename || '';
97
+ return isISOFilename(filename) || isCMRISOFilename(filename);
98
+ }
99
+
88
100
  /**
89
101
  * Extracts CMR file objects from the specified granule object.
90
102
  *
@@ -92,30 +104,37 @@ function isCMRFile(fileobject) {
92
104
  * `files` property
93
105
  * @param {Array<Object>} granule.files - array of files for a granule
94
106
  * @param {string} granule.granuleId - granule ID
107
+ * @param {Function} filterFunc - function to determine if the given file object is a
108
+ CMR file; defaults to `isCMRFile`
95
109
  * @returns {Array<Object>} an array of CMR file objects, each with properties
96
- * `granuleId`, `filename`, and possibly `etag` (if present on input)
110
+ * `granuleId`, `bucket`, `key`, and possibly `etag` (if present on input)
97
111
  */
98
- function granuleToCmrFileObject({ granuleId, files = [] }) {
112
+ function granuleToCmrFileObject({ granuleId, files = [] }, filterFunc = isCMRFile) {
99
113
  return files
100
- .filter(isCMRFile)
101
- .map((file) => ({
102
- // Include etag only if file has one
103
- ...pick(file, 'etag'),
104
- // handle both new-style and old-style files model
105
- filename: file.key ? buildS3Uri(file.bucket, file.key) : file.filename,
106
- granuleId,
107
- }));
114
+ .filter(filterFunc)
115
+ .map((file) => {
116
+ const { Bucket, Key } = parseS3Uri(getS3UrlOfFile(file));
117
+ return {
118
+ // Include etag only if file has one
119
+ ...pick(file, 'etag'),
120
+ bucket: Bucket,
121
+ key: Key,
122
+ granuleId,
123
+ };
124
+ });
108
125
  }
109
126
 
110
127
  /**
111
128
  * Reduce granule object array to CMR files array
112
129
  *
113
130
  * @param {Array<Object>} granules - granule objects array
131
+ * @param {Function} filterFunc - function to determine if the given file object is a
132
+ CMR file; defaults to `isCMRFile`
114
133
  *
115
- * @returns {Array<Object>} - CMR file object array: { filename, granuleId }
134
+ * @returns {Array<Object>} - CMR file object array: { etag, bucket, key, granuleId }
116
135
  */
117
- function granulesToCmrFileObjects(granules) {
118
- return granules.flatMap(granuleToCmrFileObject);
136
+ function granulesToCmrFileObjects(granules, filterFunc = isCMRFile) {
137
+ return granules.flatMap((granule) => granuleToCmrFileObject(granule, filterFunc));
119
138
  }
120
139
 
121
140
  /**
@@ -200,12 +219,13 @@ async function publishUMMGJSON2CMR(cmrFile, cmrClient, revisionId) {
200
219
  */
201
220
  async function publish2CMR(cmrPublishObject, creds, cmrRevisionId) {
202
221
  const cmrClient = new CMR(creds);
222
+ const cmrFileName = getFilename(cmrPublishObject);
203
223
 
204
224
  // choose xml or json and do the things.
205
- if (isECHO10File(cmrPublishObject.filename)) {
225
+ if (isECHO10Filename(cmrFileName)) {
206
226
  return await publishECHO10XML2CMR(cmrPublishObject, cmrClient, cmrRevisionId);
207
227
  }
208
- if (isUMMGFile(cmrPublishObject.filename)) {
228
+ if (isUMMGFilename(cmrFileName)) {
209
229
  return await publishUMMGJSON2CMR(cmrPublishObject, cmrClient, cmrRevisionId);
210
230
  }
211
231
 
@@ -290,14 +310,14 @@ const metadataObjectFromCMRXMLFile = (cmrFilename, etag) =>
290
310
  * @returns {Promise<Object>} metadata object from the file
291
311
  * @throws {Error} if the specified filename does not represent an ECHO-10 XML
292
312
  * file or a UMMG file
293
- * @see isECHO10File
294
- * @see isUMMGFile
313
+ * @see isECHO10Filename
314
+ * @see isUMMGFilename
295
315
  */
296
316
  function metadataObjectFromCMRFile(cmrFilename, etag) {
297
- if (isECHO10File(cmrFilename)) {
317
+ if (isECHO10Filename(cmrFilename) || isISOFilename(cmrFilename)) {
298
318
  return metadataObjectFromCMRXMLFile(cmrFilename, etag);
299
319
  }
300
- if (isUMMGFile(cmrFilename)) {
320
+ if (isUMMGFilename(cmrFilename)) {
301
321
  return metadataObjectFromCMRJSONFile(cmrFilename, etag);
302
322
  }
303
323
  throw new Error(
@@ -347,6 +367,51 @@ function mapCNMTypeToCMRType(type, urlType = 'distribution', useDirectS3Type = f
347
367
  return mappedType;
348
368
  }
349
369
 
370
+ /**
371
+ * Add ETags to file objects as some downstream functions expect this structure.
372
+ *
373
+ * @param {Object} granule - input granule object
374
+ * @param {Object} etags - map of s3URIs and ETags
375
+ * @returns {Object} - updated granule object
376
+ */
377
+ function addEtagsToFileObjects(granule, etags) {
378
+ granule.files.forEach((incomingFile) => {
379
+ const file = incomingFile;
380
+ const fileURI = getS3UrlOfFile(file);
381
+ if (etags[fileURI]) file.etag = etags[fileURI];
382
+ });
383
+ return granule;
384
+ }
385
+
386
+ /**
387
+ * Remove ETags to match output schema
388
+ *
389
+ * @param {Object} granule - output granule object
390
+ * @returns {undefined}
391
+ */
392
+ function removeEtagsFromFileObjects(granule) {
393
+ granule.files.forEach((incomingFile) => {
394
+ const file = incomingFile;
395
+ delete file.etag;
396
+ });
397
+ }
398
+
399
+ /**
400
+ * Maps etag values from the specified granules' files.
401
+ *
402
+ * @param {Object[]} files - array of file objects with `bucket`, `key` and
403
+ * `etag` properties
404
+ * @returns {Object} mapping of file S3 URIs to etags
405
+ */
406
+ function mapFileEtags(files) {
407
+ return files.reduce((filesMap, file) => {
408
+ const { bucket, key, etag } = file;
409
+ const s3Uri = getS3UrlOfFile({ bucket, key });
410
+ filesMap[s3Uri] = etag; // eslint-disable-line no-param-reassign
411
+ return filesMap;
412
+ }, {});
413
+ }
414
+
350
415
  /**
351
416
  * generate a url for a given file and a url type.
352
417
  *
@@ -885,9 +950,9 @@ async function updateCMRMetadata({
885
950
  let metadataObject;
886
951
  let etag;
887
952
 
888
- if (isECHO10File(filename)) {
953
+ if (isECHO10Filename(filename)) {
889
954
  ({ metadataObject, etag } = await updateEcho10XMLMetadata(params));
890
- } else if (isUMMGFile(filename)) {
955
+ } else if (isUMMGFilename(filename)) {
891
956
  ({ metadataObject, etag } = await updateUMMGMetadata(params));
892
957
  } else {
893
958
  throw new errors.CMRMetaFileNotFound(`Invalid CMR filetype: ${filename}`);
@@ -1022,9 +1087,9 @@ async function getGranuleTemporalInfo(granule) {
1022
1087
  const cmrFile = granuleToCmrFileObject(granule);
1023
1088
  if (cmrFile.length === 0) return {};
1024
1089
 
1025
- const cmrFilename = cmrFile[0].filename;
1090
+ const cmrFilename = getS3UrlOfFile(cmrFile[0]);
1026
1091
 
1027
- if (isISOFile(cmrFilename)) {
1092
+ if (isCMRISOFilename(cmrFilename)) {
1028
1093
  const metadata = await metadataObjectFromCMRXMLFile(cmrFilename);
1029
1094
  const metadataMI = metadata['gmd:DS_Series']['gmd:composedOf']['gmd:DS_DataSet']['gmd:has']['gmi:MI_Metadata'];
1030
1095
 
@@ -1044,7 +1109,7 @@ async function getGranuleTemporalInfo(granule) {
1044
1109
 
1045
1110
  return { beginningDateTime, endingDateTime, productionDateTime, lastUpdateDateTime };
1046
1111
  }
1047
- if (isECHO10File(cmrFilename)) {
1112
+ if (isECHO10Filename(cmrFilename)) {
1048
1113
  const metadata = await metadataObjectFromCMRXMLFile(cmrFilename);
1049
1114
  const beginningDateTime = get(metadata.Granule, 'Temporal.RangeDateTime.BeginningDateTime');
1050
1115
  const endingDateTime = get(metadata.Granule, 'Temporal.RangeDateTime.EndingDateTime');
@@ -1054,16 +1119,15 @@ async function getGranuleTemporalInfo(granule) {
1054
1119
  beginningDateTime, endingDateTime, productionDateTime, lastUpdateDateTime,
1055
1120
  };
1056
1121
  }
1057
- if (isUMMGFile(cmrFilename)) {
1122
+ if (isUMMGFilename(cmrFilename)) {
1058
1123
  const metadata = await metadataObjectFromCMRJSONFile(cmrFilename);
1059
1124
  const beginningDateTime = get(metadata, 'TemporalExtent.RangeDateTime.BeginningDateTime');
1060
1125
  const endingDateTime = get(metadata, 'TemporalExtent.RangeDateTime.EndingDateTime');
1061
1126
  const productionDateTime = get(metadata, 'DataGranule.ProductionDateTime');
1062
- let updateDate = metadata.ProviderDates.filter((d) => d.Type === 'Update');
1063
- if (updateDate.length === 0) {
1064
- updateDate = metadata.ProviderDates.filter((d) => d.Type === 'Insert');
1065
- }
1066
- const lastUpdateDateTime = updateDate[0].Date;
1127
+ const lastUpdateDateTime = (metadata.ProviderDates.find((d) => d.Type === 'Update')
1128
+ || metadata.ProviderDates.find((d) => d.Type === 'Insert')
1129
+ || metadata.ProviderDates.find((d) => d.Type === 'Create') || {}).Date;
1130
+
1067
1131
  return {
1068
1132
  beginningDateTime, endingDateTime, productionDateTime, lastUpdateDateTime,
1069
1133
  };
@@ -1072,6 +1136,7 @@ async function getGranuleTemporalInfo(granule) {
1072
1136
  }
1073
1137
 
1074
1138
  module.exports = {
1139
+ addEtagsToFileObjects,
1075
1140
  constructCmrConceptLink,
1076
1141
  constructOnlineAccessUrl,
1077
1142
  constructOnlineAccessUrls,
@@ -1083,16 +1148,21 @@ module.exports = {
1083
1148
  getFilename,
1084
1149
  getGranuleTemporalInfo,
1085
1150
  getCollectionsByShortNameAndVersion,
1151
+ getS3UrlOfFile,
1086
1152
  getUserAccessibleBuckets,
1087
1153
  granulesToCmrFileObjects,
1088
1154
  isCMRFile,
1089
1155
  isCMRFilename,
1090
- isECHO10File,
1156
+ isCMRISOFilename,
1157
+ isECHO10Filename,
1091
1158
  isISOFile,
1092
- isUMMGFile,
1159
+ isISOFilename,
1160
+ isUMMGFilename,
1161
+ mapFileEtags,
1093
1162
  metadataObjectFromCMRFile,
1094
1163
  publish2CMR,
1095
1164
  reconcileCMRMetadata,
1165
+ removeEtagsFromFileObjects,
1096
1166
  updateCMRMetadata,
1097
1167
  uploadEcho10CMRFile,
1098
1168
  uploadUMMGJSONCMRFile,
package/src/index.js CHANGED
@@ -4,28 +4,36 @@ const {
4
4
  ValidationError,
5
5
  } = require('./utils');
6
6
  const {
7
+ addEtagsToFileObjects,
7
8
  constructOnlineAccessUrl,
8
9
  getGranuleTemporalInfo,
9
10
  getCollectionsByShortNameAndVersion,
10
11
  getUserAccessibleBuckets,
11
12
  isCMRFile,
13
+ isISOFile,
14
+ mapFileEtags,
12
15
  metadataObjectFromCMRFile,
13
16
  publish2CMR,
14
17
  granulesToCmrFileObjects,
15
18
  reconcileCMRMetadata,
19
+ removeEtagsFromFileObjects,
16
20
  updateCMRMetadata,
17
21
  } = require('./cmr-utils');
18
22
 
19
23
  module.exports = {
24
+ addEtagsToFileObjects,
20
25
  constructOnlineAccessUrl,
21
26
  ValidationError,
22
27
  getGranuleTemporalInfo,
23
28
  getCollectionsByShortNameAndVersion,
24
29
  getUserAccessibleBuckets,
25
30
  isCMRFile,
31
+ isISOFile,
32
+ mapFileEtags,
26
33
  metadataObjectFromCMRFile,
27
34
  publish2CMR,
28
35
  reconcileCMRMetadata,
36
+ removeEtagsFromFileObjects,
29
37
  granulesToCmrFileObjects,
30
38
  updateCMRMetadata,
31
39
  };