Skip to content

Commit

Permalink
EDSC-3773: Refactor buildAccessMethods.js (#1767)
Browse files Browse the repository at this point in the history
* EDSC-3773:
- Moved out all the logic bocks in buildAccessMethods into their one files (1 for each logic block).
- Created tests for each of those logic blocks and updated the buildAccessMethods to test that those methods get called the correct number of times and with the correct params.

* removed dangling cammas

* EDSC-3773: a bit of cleanup

* EDSC-3773: added some code coverage

* EDSC-3773: updated documentation and how we run buildAccessMethods.

* EDSC-3773: changed lodash to lodash-es

* EDSC-3773: fixed the indexing issue and cleaned up some stuff

* EDSC-3773: fixed harmony tests

* EDSC-3773: addressed matthew's comments

* EDSC-3773: added some comments and pushed a small lint fix

* EDSC-3773: fixed some eslint issues

* fixed some wording

* EDSC-3773: added a test that needs to be finished in buildAccessMethods

* EDSC-3773: fixed up the format and tests of Harmony, Opendap, and Swodlr results to match Esi and Echo Orders

* EDSC-3773: removed console.logs

* EDSC-3773: fixed up syntax/linting so it matches our standards

* EDSC-3773: forgot a couple of the lint changes

* adding test and seeing weirdness

* fixed up the test

* EDSC-3773: merged new test and removed console.logs and fixed the order of checking results so they are accurate to the indexing of echoIndex, esiIndex, & harmonyIndex
  • Loading branch information
bnp26 committed Aug 29, 2024
1 parent b0693f9 commit aa65615
Show file tree
Hide file tree
Showing 12 changed files with 5,502 additions and 1,718 deletions.
5,138 changes: 3,603 additions & 1,535 deletions static/src/js/util/accessMethods/__tests__/buildAccessMethods.test.js

Large diffs are not rendered by default.

230 changes: 47 additions & 183 deletions static/src/js/util/accessMethods/buildAccessMethods.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { camelCase, uniq } from 'lodash-es'

import { getApplicationConfig } from '../../../../../sharedUtils/config'

import { isDownloadable } from '../../../../../sharedUtils/isDownloadable'
import { generateFormDigest } from './generateFormDigest'
import { getVariables } from './getVariables'
import { supportsBoundingBoxSubsetting } from './supportsBoundingBoxSubsetting'
import { supportsConcatenation } from './supportsConcatenation'
import { defaultConcatenation } from './defaultConcatenation'
import { supportsShapefileSubsetting } from './supportsShapefileSubsetting'
import { supportsTemporalSubsetting } from './supportsTemporalSubsetting'
import { supportsVariableSubsetting } from './supportsVariableSubsetting'
import { buildEsiEcho } from './buildAccessMethods/buildEsiEcho'
import { buildOpendap } from './buildAccessMethods/buildOpendap'
import { buildHarmony } from './buildAccessMethods/buildHarmony'
import { buildSwodlr } from './buildAccessMethods/buildSwodlr'
import { buildDownload } from './buildAccessMethods/buildDownload'

/**
* Builds the different access methods available for the provided collection
Expand All @@ -25,25 +17,27 @@ export const buildAccessMethods = (collectionMetadata, isOpenSearch) => {
variables: collectionAssociatedVariables = {}
} = collectionMetadata

const accessMethods = {}
let harmonyIndex = 0
let echoIndex = 0
let esiIndex = 0

const { items: serviceItems = null } = services

const { disableOrdering, disableSwodlr } = getApplicationConfig()
const buildMethods = {
esi: (serviceItem, params) => buildEsiEcho(serviceItem, params),
'echo orders': (serviceItem, params) => buildEsiEcho(serviceItem, params),
opendap: (serviceItem, params) => buildOpendap(serviceItem, params),
harmony: (serviceItem, params) => buildHarmony(serviceItem, params),
swodlr: (serviceItem) => buildSwodlr(serviceItem),
downloads: () => buildDownload(granules, isOpenSearch)
}

if (serviceItems !== null) {
serviceItems.forEach((serviceItem) => {
const nonDownloadMethods = serviceItems === null
? {}
: serviceItems.reduce((methods, serviceItem) => {
let associatedVariables = collectionAssociatedVariables
const {
conceptId: serviceConceptId,
description,
orderOptions,
type: serviceType,
url,
longName,
maxItemsPerOrder,
name,
supportedReformattings,
variables: serviceAssociatedVariables = {}
} = serviceItem

Expand All @@ -52,175 +46,45 @@ export const buildAccessMethods = (collectionMetadata, isOpenSearch) => {
associatedVariables = serviceAssociatedVariables
}

const lowerServiceType = serviceType.toLowerCase()

// Only process service types that EDSC supports
const supportedServiceTypes = ['esi', 'echo orders', 'opendap', 'harmony', 'swodlr']
if (!supportedServiceTypes.includes(serviceType.toLowerCase())) return

const { urlValue } = url

const supportsOrderOptions = ['esi', 'echo orders']

// Only process orderOptions if the service type uses orderOptions
// Do not include access if orders are disabled
if (supportsOrderOptions.includes(serviceType.toLowerCase()) && (disableOrdering !== 'true')) {
const { items: orderOptionsItems } = orderOptions
if (orderOptionsItems === null) return

orderOptionsItems.forEach((orderOptionItem, orderOptionIndex) => {
const {
conceptId: orderOptionConceptId,
form,
name: orderOptionName
} = orderOptionItem

const method = {
type: serviceType,
maxItemsPerOrder,
url: urlValue,
optionDefinition: {
conceptId: orderOptionConceptId,
name: orderOptionName
},
form,
formDigest: generateFormDigest(form)
}

let methodKey = camelCase(serviceType)

// `echoOrders` needs to be singular to match existing savedAccessConfigurations
if (methodKey === 'echoOrders') {
methodKey = 'echoOrder'
}

accessMethods[`${methodKey}${orderOptionIndex}`] = method
})
}
if (!supportedServiceTypes.includes(lowerServiceType)) return {}

if (serviceType.toLowerCase() === 'opendap') {
const {
hierarchyMappings,
keywordMappings,
variables
} = getVariables(associatedVariables)

const outputFormats = []

if (supportedReformattings) {
supportedReformattings.forEach((reformatting) => {
const { supportedOutputFormats } = reformatting

// Collect all supported output formats from each mapping
outputFormats.push(...supportedOutputFormats)
})
}

accessMethods.opendap = {
hierarchyMappings,
id: serviceConceptId,
isValid: true,
keywordMappings,
longName,
name,
supportedOutputFormats: uniq(outputFormats),
supportsVariableSubsetting: supportsVariableSubsetting(serviceItem),
type: serviceType,
variables
}
const params = {
harmonyIndex,
echoIndex,
esiIndex,
associatedVariables
}

if (serviceType.toLowerCase() === 'harmony') {
const {
hierarchyMappings,
keywordMappings,
variables
} = getVariables(associatedVariables)
const {
supportedOutputProjections
} = serviceItem

const outputFormats = []

if (supportedReformattings) {
supportedReformattings.forEach((reformatting) => {
const { supportedOutputFormats } = reformatting

// Collect all supported output formats from each mapping
outputFormats.push(...supportedOutputFormats)
})
}

let outputProjections = []
if (supportedOutputProjections) {
outputProjections = supportedOutputProjections.filter((projection) => {
const { projectionAuthority } = projection

return projectionAuthority != null
}).map((projection) => {
const { projectionAuthority } = projection

return projectionAuthority
})
}

accessMethods[`harmony${harmonyIndex}`] = {
description,
enableTemporalSubsetting: true,
enableSpatialSubsetting: true,
hierarchyMappings,
id: serviceConceptId,
isValid: true,
keywordMappings,
longName,
name,
supportedOutputFormats: uniq(outputFormats),
supportedOutputProjections: outputProjections,
supportsBoundingBoxSubsetting: supportsBoundingBoxSubsetting(serviceItem),
supportsShapefileSubsetting: supportsShapefileSubsetting(serviceItem),
supportsTemporalSubsetting: supportsTemporalSubsetting(serviceItem),
supportsVariableSubsetting: supportsVariableSubsetting(serviceItem),
supportsConcatenation: supportsConcatenation(serviceItem),
defaultConcatenation: defaultConcatenation(serviceItem),
enableConcatenateDownload: defaultConcatenation(serviceItem),
type: serviceType,
url: urlValue,
variables
}
const builtMethod = buildMethods[lowerServiceType](serviceItem, params)

harmonyIndex += 1
}
const {
accessMethods: newAccessMethods,
esiIndex: newEsiIndex,
echoIndex: newEchoIndex
} = builtMethod

if (serviceType.toLowerCase() === 'swodlr' && (disableSwodlr !== 'true')) {
accessMethods.swodlr = {
id: serviceConceptId,
isValid: true,
longName,
name,
type: serviceType,
supportsSwodlr: true,
url: urlValue
}
}
})
}
esiIndex = newEsiIndex || esiIndex
echoIndex = newEchoIndex || echoIndex

// Determine if the collection should have the downloadable accessMethod
let onlineAccessFlag = false
const updatedMethods = {
...methods,
...newAccessMethods
}

if (granules) {
// If the collection has granules, check their online access flags to
// determine if this collection is downloadable
const { items: granuleItems } = granules
if (lowerServiceType === 'harmony') {
harmonyIndex += 1
}

if (granuleItems) {
onlineAccessFlag = isDownloadable(granuleItems)
}
return updatedMethods
}, {})

if (onlineAccessFlag || isOpenSearch) {
accessMethods.download = {
isValid: true,
type: 'download'
}
}
const accessMethods = {
...nonDownloadMethods,
...buildMethods.downloads()
}

return accessMethods
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { buildDownload } from '../buildDownload'

describe('buildDownload', () => {
test('returns a download access method', () => {
const collectionMetadata = {
granules: {
items: [{
online_access_flag: true
}]
}
}
const isOpenSearch = false

const {
granules
} = collectionMetadata

const method = buildDownload(granules, isOpenSearch)

expect(method).toEqual(
{
download: {
isValid: true,
type: 'download'
}
}
)
})

test('returns a download access method for open search', () => {
const collectionMetadata = {}
const isOpenSearch = true

const {
granules = {}
} = collectionMetadata

const method = buildDownload(granules, isOpenSearch)

expect(method).toEqual(
{
download: {
isValid: true,
type: 'download'
}
}
)
})
})
Loading

0 comments on commit aa65615

Please sign in to comment.