oceanprotocol/market

View on GitHub
src/@utils/ddo.ts

Summary

Maintainability
A
3 hrs
Test Coverage
F
0%
import { MetadataEditForm } from '@components/Asset/Edit/_types'
import {
  FormConsumerParameter,
  FormPublishData
} from '@components/Publish/_types'
import {
  Arweave,
  Asset,
  ConsumerParameter,
  DDO,
  FileInfo,
  GraphqlQuery,
  Ipfs,
  Service,
  Smartcontract,
  UrlFile
} from '@oceanprotocol/lib'
import { checkJson } from './codemirror'

export function isValidDid(did: string): boolean {
  const regex = /did:op:[A-Za-z0-9]{64}/
  return regex.test(did)
}

export function getServiceByName(ddo: Asset | DDO, name: 'access'): Service {
  if (!ddo) return

  const service = ddo.services.filter((service) => service.type === name)[0]
  return service
}

export function getServiceById(ddo: Asset | DDO, serviceId: string): Service {
  if (!ddo) return

  const service = ddo.services.find((s) => s.id === serviceId)
  return service
}

export function mapTimeoutStringToSeconds(timeout: string): number {
  switch (timeout) {
    case 'Forever':
      return 0
    case '1 day':
      return 86400
    case '1 week':
      return 604800
    case '1 month':
      return 2630000
    case '1 year':
      return 31556952
    default:
      return 0
  }
}

function numberEnding(number: number): string {
  return number > 1 ? 's' : ''
}

export function secondsToString(numberOfSeconds: number): string {
  if (numberOfSeconds === 0) return 'Forever'

  const years = Math.floor(numberOfSeconds / 31536000)
  const months = Math.floor((numberOfSeconds %= 31536000) / 2630000)
  const weeks = Math.floor((numberOfSeconds %= 31536000) / 604800)
  const days = Math.floor((numberOfSeconds %= 604800) / 86400)
  const hours = Math.floor((numberOfSeconds %= 86400) / 3600)
  const minutes = Math.floor((numberOfSeconds %= 3600) / 60)
  const seconds = numberOfSeconds % 60

  return years
    ? `${years} year${numberEnding(years)}`
    : months
    ? `${months} month${numberEnding(months)}`
    : weeks
    ? `${weeks} week${numberEnding(weeks)}`
    : days
    ? `${days} day${numberEnding(days)}`
    : hours
    ? `${hours} hour${numberEnding(hours)}`
    : minutes
    ? `${minutes} minute${numberEnding(minutes)}`
    : seconds
    ? `${seconds} second${numberEnding(seconds)}`
    : 'less than a second'
}

// this is required to make it work properly for preview/publish/edit/debug.
// TODO: find a way to only have FileInfo interface instead of FileExtended
interface FileExtended extends FileInfo {
  url?: string
  query?: string
  transactionId?: string
  address?: string
  abi?: string
  headers?: { key: string; value: string }[]
}

export function normalizeFile(
  storageType: string,
  file: FileExtended,
  chainId: number
) {
  let fileObj
  const headersProvider = {}
  const headers = file[0]?.headers || file?.headers
  if (headers && headers.length > 0) {
    headers.map((el) => {
      headersProvider[el.key] = el.value
      return el
    })
  }
  switch (storageType) {
    case 'ipfs': {
      fileObj = {
        type: storageType,
        hash: file[0]?.url || file?.url
      } as Ipfs
      break
    }
    case 'arweave': {
      fileObj = {
        type: storageType,
        transactionId:
          file[0]?.url ||
          file?.url ||
          file[0]?.transactionId ||
          file?.transactionId
      } as Arweave
      break
    }
    case 'graphql': {
      fileObj = {
        type: storageType,
        url: file[0]?.url || file?.url,
        query: file[0]?.query || file?.query,
        headers: headersProvider
      } as GraphqlQuery
      break
    }
    case 'smartcontract': {
      // clean obj
      fileObj = {
        chainId,
        type: storageType,
        address: file[0]?.address || file?.address || file[0]?.url || file?.url,
        abi: checkJson(file[0]?.abi || file?.abi)
          ? JSON.parse(file[0]?.abi || file?.abi)
          : file[0]?.abi || file?.abi
      } as Smartcontract
      break
    }
    default: {
      fileObj = {
        type: 'url',
        index: 0,
        url: file ? file[0]?.url || file?.url : null,
        headers: headersProvider,
        method: file.method
      } as UrlFile
      break
    }
  }
  return fileObj
}

export function previewDebugPatch(
  values: FormPublishData | Partial<MetadataEditForm>,
  chainId: number
) {
  // handle file's object property dynamically
  // without braking Yup and type validation
  const buildValuesPreview = JSON.parse(JSON.stringify(values))

  // fallback for edit mode under "edit compute settings"
  if (!buildValuesPreview.services) return buildValuesPreview

  const valuesService = buildValuesPreview.services
    ? buildValuesPreview.services[0]
    : buildValuesPreview
  valuesService.files[0] = normalizeFile(
    valuesService.files[0].type,
    valuesService.files[0],
    chainId
  )

  return buildValuesPreview
}

export function parseConsumerParameters(
  consumerParameters: ConsumerParameter[]
): FormConsumerParameter[] {
  if (!consumerParameters?.length) return []

  return consumerParameters.map((param) => ({
    ...param,
    required: param.required ? 'required' : 'optional',
    options:
      param.type === 'select'
        ? JSON.parse(param.options)?.map((option) => {
            const key = Object.keys(option)[0]
            return {
              key,
              value: option[key]
            }
          })
        : [],
    default:
      param.type === 'boolean'
        ? param.default === 'true'
        : param.type === 'number'
        ? Number(param.default)
        : param.default
  }))
}