mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
more publish flow preparation
* consolidate scattered methods into publish utils * new encrypt method * remove DDO File typings
This commit is contained in:
parent
8ce573b2a0
commit
704b52a3c4
18
src/@types/DDO/File.d.ts
vendored
18
src/@types/DDO/File.d.ts
vendored
@ -1,18 +0,0 @@
|
|||||||
// This is all super questionable,
|
|
||||||
// but we most likely need something to represent what we get
|
|
||||||
// back from fileinfo endpoint in Provider. But then should be moved out of DDO typings.
|
|
||||||
|
|
||||||
interface FileMetadata {
|
|
||||||
url: string
|
|
||||||
contentType: string
|
|
||||||
name?: string
|
|
||||||
checksum?: string
|
|
||||||
checksumType?: string
|
|
||||||
contentLength?: string
|
|
||||||
encoding?: string
|
|
||||||
compression?: string
|
|
||||||
encrypted?: boolean
|
|
||||||
encryptionMode?: string
|
|
||||||
resourceId?: string
|
|
||||||
attributes?: { [key: string]: any }
|
|
||||||
}
|
|
@ -1,5 +1,3 @@
|
|||||||
import slugify from 'slugify'
|
|
||||||
|
|
||||||
export function getServiceByName(
|
export function getServiceByName(
|
||||||
ddo: Asset | DDO,
|
ddo: Asset | DDO,
|
||||||
name: 'access' | 'compute'
|
name: 'access' | 'compute'
|
||||||
@ -10,16 +8,6 @@ export function getServiceByName(
|
|||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
|
|
||||||
export function dateToStringNoMS(date: Date): string {
|
|
||||||
return date.toISOString().replace(/\.[0-9]{3}Z/, 'Z')
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformTags(value: string): string[] {
|
|
||||||
const originalTags = value?.split(',')
|
|
||||||
const transformedTags = originalTags?.map((tag) => slugify(tag).toLowerCase())
|
|
||||||
return transformedTags
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mapTimeoutStringToSeconds(timeout: string): number {
|
export function mapTimeoutStringToSeconds(timeout: string): number {
|
||||||
switch (timeout) {
|
switch (timeout) {
|
||||||
case 'Forever':
|
case 'Forever':
|
||||||
@ -68,18 +56,3 @@ export function secondsToString(numberOfSeconds: number): string {
|
|||||||
? `${seconds} second${numberEnding(seconds)}`
|
? `${seconds} second${numberEnding(seconds)}`
|
||||||
: 'less than a second'
|
: 'less than a second'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkIfTimeoutInPredefinedValues(
|
|
||||||
timeout: string,
|
|
||||||
timeoutOptions: string[]
|
|
||||||
): boolean {
|
|
||||||
if (timeoutOptions.indexOf(timeout) > -1) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getUrlFileExtension(fileUrl: string): string {
|
|
||||||
const splitedFileUrl = fileUrl.split('.')
|
|
||||||
return splitedFileUrl[splitedFileUrl.length - 1]
|
|
||||||
}
|
|
||||||
|
@ -1,70 +1,16 @@
|
|||||||
import axios, { CancelToken, AxiosResponse } from 'axios'
|
import axios, { CancelToken, AxiosResponse } from 'axios'
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import { DID, Logger } from '@oceanprotocol/lib'
|
import { DID, Logger } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
export async function fileinfo(
|
export interface FileMetadata {
|
||||||
url: string,
|
contentType: string
|
||||||
providerUri: string,
|
contentLength: string
|
||||||
cancelToken: CancelToken
|
|
||||||
): Promise<FileMetadata> {
|
|
||||||
try {
|
|
||||||
const response = (await axios.post(
|
|
||||||
`${providerUri}/api/v1/services/fileinfo`,
|
|
||||||
{
|
|
||||||
url,
|
|
||||||
cancelToken
|
|
||||||
}
|
|
||||||
)) as AxiosResponse<
|
|
||||||
{ valid: boolean; contentLength: string; contentType: string }[]
|
|
||||||
>
|
|
||||||
|
|
||||||
if (!response || response.status !== 200 || !response.data) {
|
|
||||||
toast.error('Could not connect to File API')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!response.data[0] || !response.data[0].valid) {
|
|
||||||
toast.error(
|
|
||||||
'The data file URL you entered apears to be invalid. Please check URL and try again',
|
|
||||||
{
|
|
||||||
autoClose: false,
|
|
||||||
hideProgressBar: false,
|
|
||||||
closeOnClick: true,
|
|
||||||
pauseOnHover: true,
|
|
||||||
draggable: true,
|
|
||||||
progress: undefined
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
toast.dismiss() // Remove any existing error message
|
|
||||||
toast.success('Great! That file looks good. 🐳', {
|
|
||||||
position: 'bottom-right',
|
|
||||||
autoClose: 5000,
|
|
||||||
hideProgressBar: false,
|
|
||||||
closeOnClick: true,
|
|
||||||
pauseOnHover: true,
|
|
||||||
draggable: true,
|
|
||||||
progress: undefined
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const { contentLength, contentType } = response.data[0]
|
|
||||||
|
|
||||||
return {
|
|
||||||
contentLength: contentLength || '',
|
|
||||||
contentType: contentType || '', // need to do that cause lib-js File interface requires contentType
|
|
||||||
url
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
Logger.error(error.message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getFileInfo(
|
export async function getFileInfo(
|
||||||
url: string | DID,
|
url: string | DID,
|
||||||
providerUri: string,
|
providerUri: string,
|
||||||
cancelToken: CancelToken
|
cancelToken: CancelToken
|
||||||
): Promise<any> {
|
): Promise<FileMetadata[]> {
|
||||||
let postBody
|
let postBody
|
||||||
try {
|
try {
|
||||||
if (url instanceof DID)
|
if (url instanceof DID)
|
||||||
@ -75,10 +21,12 @@ export async function getFileInfo(
|
|||||||
postBody = {
|
postBody = {
|
||||||
url
|
url
|
||||||
}
|
}
|
||||||
const response = await axios.post(
|
const response: AxiosResponse<FileMetadata[]> = await axios.post(
|
||||||
`${providerUri}/api/v1/services/fileinfo`,
|
`${providerUri}/api/v1/services/fileinfo`,
|
||||||
postBody,
|
postBody,
|
||||||
{ cancelToken }
|
{
|
||||||
|
cancelToken
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!response || response.status !== 200 || !response.data) return
|
if (!response || response.status !== 200 || !response.data) return
|
||||||
|
@ -4,6 +4,7 @@ import classNames from 'classnames/bind'
|
|||||||
import cleanupContentType from '@utils/cleanupContentType'
|
import cleanupContentType from '@utils/cleanupContentType'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import Loader from '@shared/atoms/Loader'
|
import Loader from '@shared/atoms/Loader'
|
||||||
|
import { FileMetadata } from '@utils/provider'
|
||||||
|
|
||||||
const cx = classNames.bind(styles)
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { prettySize } from './utils'
|
|||||||
import cleanupContentType from '@utils/cleanupContentType'
|
import cleanupContentType from '@utils/cleanupContentType'
|
||||||
import styles from './Info.module.css'
|
import styles from './Info.module.css'
|
||||||
import { useField, useFormikContext } from 'formik'
|
import { useField, useFormikContext } from 'formik'
|
||||||
|
import { FileMetadata } from '@utils/provider'
|
||||||
|
|
||||||
export default function FileInfo({
|
export default function FileInfo({
|
||||||
name,
|
name,
|
||||||
@ -21,7 +22,7 @@ export default function FileInfo({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
<h3 className={styles.url}>{file.url}</h3>
|
{/* <h3 className={styles.url}>{file}</h3> */}
|
||||||
<ul>
|
<ul>
|
||||||
<li>URL confirmed</li>
|
<li>URL confirmed</li>
|
||||||
{file.contentLength && <li>{prettySize(+file.contentLength)}</li>}
|
{file.contentLength && <li>{prettySize(+file.contentLength)}</li>}
|
||||||
|
@ -4,7 +4,7 @@ import { toast } from 'react-toastify'
|
|||||||
import FileInfo from './Info'
|
import FileInfo from './Info'
|
||||||
import CustomInput from '../URLInput/Input'
|
import CustomInput from '../URLInput/Input'
|
||||||
import { InputProps } from '@shared/Form/Input'
|
import { InputProps } from '@shared/Form/Input'
|
||||||
import { fileinfo } from '@utils/provider'
|
import { getFileInfo } from '@utils/provider'
|
||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
import { getOceanConfig } from '@utils/ocean'
|
import { getOceanConfig } from '@utils/ocean'
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
@ -22,7 +22,7 @@ export default function FilesInput(props: InputProps): ReactElement {
|
|||||||
async function validateUrl() {
|
async function validateUrl() {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
const checkedFile = await fileinfo(
|
const checkedFile = await getFileInfo(
|
||||||
fileUrl,
|
fileUrl,
|
||||||
config?.providerUri,
|
config?.providerUri,
|
||||||
newCancelToken()
|
newCancelToken()
|
||||||
|
@ -34,6 +34,7 @@ import ComputeJobs from '../../../Profile/History/ComputeJobs'
|
|||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
import { SortTermOptions } from '../../../../@types/aquarius/SearchQuery'
|
import { SortTermOptions } from '../../../../@types/aquarius/SearchQuery'
|
||||||
|
import { FileMetadata } from '@utils/provider'
|
||||||
|
|
||||||
export default function Compute({
|
export default function Compute({
|
||||||
dtBalance,
|
dtBalance,
|
||||||
|
@ -17,6 +17,7 @@ import { secondsToString } from '@utils/ddo'
|
|||||||
import AlgorithmDatasetsListForCompute from './Compute/AlgorithmDatasetsListForCompute'
|
import AlgorithmDatasetsListForCompute from './Compute/AlgorithmDatasetsListForCompute'
|
||||||
import styles from './Consume.module.css'
|
import styles from './Consume.module.css'
|
||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
|
import { FileMetadata } from '@utils/provider'
|
||||||
|
|
||||||
const previousOrderQuery = gql`
|
const previousOrderQuery = gql`
|
||||||
query PreviousOrder($id: String!, $account: String!) {
|
query PreviousOrder($id: String!, $account: String!) {
|
||||||
|
@ -2,7 +2,6 @@ import React, { ChangeEvent, ReactElement } from 'react'
|
|||||||
import { Field, Form, FormikContextType, useFormikContext } from 'formik'
|
import { Field, Form, FormikContextType, useFormikContext } from 'formik'
|
||||||
import { useOcean } from '@context/Ocean'
|
import { useOcean } from '@context/Ocean'
|
||||||
import Input, { InputProps } from '@shared/Form/Input'
|
import Input, { InputProps } from '@shared/Form/Input'
|
||||||
import { checkIfTimeoutInPredefinedValues } from '@utils/ddo'
|
|
||||||
import FormActions from './FormActions'
|
import FormActions from './FormActions'
|
||||||
import styles from './FormEditMetadata.module.css'
|
import styles from './FormEditMetadata.module.css'
|
||||||
import { FormPublishData } from '../../../Publish/_types'
|
import { FormPublishData } from '../../../Publish/_types'
|
||||||
|
@ -10,7 +10,7 @@ import { useAsset } from '@context/Asset'
|
|||||||
import { useOcean } from '@context/Ocean'
|
import { useOcean } from '@context/Ocean'
|
||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
import Web3Feedback from '@shared/Web3Feedback'
|
import Web3Feedback from '@shared/Web3Feedback'
|
||||||
import { getFileInfo } from '@utils/provider'
|
import { FileMetadata, getFileInfo } from '@utils/provider'
|
||||||
import { getOceanConfig } from '@utils/ocean'
|
import { getOceanConfig } from '@utils/ocean'
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
@ -23,7 +23,7 @@ export default function AssetActions(): ReactElement {
|
|||||||
|
|
||||||
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
||||||
const [dtBalance, setDtBalance] = useState<string>()
|
const [dtBalance, setDtBalance] = useState<string>()
|
||||||
const [fileMetadata, setFileMetadata] = useState<FileMetadata>(Object)
|
const [fileMetadata, setFileMetadata] = useState<FileMetadata>()
|
||||||
const [fileIsLoading, setFileIsLoading] = useState<boolean>(false)
|
const [fileIsLoading, setFileIsLoading] = useState<boolean>(false)
|
||||||
const isCompute = Boolean(
|
const isCompute = Boolean(
|
||||||
ddo?.services.filter((service) => service.type === 'compute')[0]
|
ddo?.services.filter((service) => service.type === 'compute')[0]
|
||||||
|
@ -21,21 +21,21 @@ export default function Actions({
|
|||||||
|
|
||||||
function handleNext(e: FormEvent) {
|
function handleNext(e: FormEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setFieldValue('step', values.step + 1)
|
setFieldValue('stepCurrent', values.stepCurrent + 1)
|
||||||
scrollToRef.current.scrollIntoView()
|
scrollToRef.current.scrollIntoView()
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePrevious(e: FormEvent) {
|
function handlePrevious(e: FormEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setFieldValue('step', values.step - 1)
|
setFieldValue('stepCurrent', values.stepCurrent - 1)
|
||||||
scrollToRef.current.scrollIntoView()
|
scrollToRef.current.scrollIntoView()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className={styles.actions}>
|
<footer className={styles.actions}>
|
||||||
{values.step > 1 && <Button onClick={handlePrevious}>Back</Button>}
|
{values.stepCurrent > 1 && <Button onClick={handlePrevious}>Back</Button>}
|
||||||
|
|
||||||
{values.step < wizardSteps.length ? (
|
{values.stepCurrent < wizardSteps.length ? (
|
||||||
<Button style="primary" onClick={handleNext}>
|
<Button style="primary" onClick={handleNext}>
|
||||||
Continue
|
Continue
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -3,12 +3,10 @@ import DebugOutput from '@shared/DebugOutput'
|
|||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
// import { transformPublishFormToMetadata } from '@utils/metadata'
|
// import { transformPublishFormToMetadata } from '@utils/metadata'
|
||||||
import { FormPublishData } from './_types'
|
import { FormPublishData } from './_types'
|
||||||
|
import { useFormikContext } from 'formik'
|
||||||
|
|
||||||
export default function Debug({
|
export default function Debug(): ReactElement {
|
||||||
values
|
const { values } = useFormikContext<FormPublishData>()
|
||||||
}: {
|
|
||||||
values: Partial<FormPublishData>
|
|
||||||
}): ReactElement {
|
|
||||||
const ddo = {
|
const ddo = {
|
||||||
'@context': 'https://w3id.org/did/v1'
|
'@context': 'https://w3id.org/did/v1'
|
||||||
// dataTokenInfo: {
|
// dataTokenInfo: {
|
||||||
|
@ -5,15 +5,11 @@ import { wizardSteps } from '../_constants'
|
|||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
|
|
||||||
export default function Navigation(): ReactElement {
|
export default function Navigation(): ReactElement {
|
||||||
const {
|
const { values, setFieldValue }: FormikContextType<FormPublishData> =
|
||||||
values,
|
useFormikContext()
|
||||||
errors,
|
|
||||||
touched,
|
|
||||||
setFieldValue
|
|
||||||
}: FormikContextType<FormPublishData> = useFormikContext()
|
|
||||||
|
|
||||||
function handleStepClick(step: number) {
|
function handleStepClick(step: number) {
|
||||||
setFieldValue('step', step)
|
setFieldValue('stepCurrent', step)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -24,7 +20,7 @@ export default function Navigation(): ReactElement {
|
|||||||
key={step.title}
|
key={step.title}
|
||||||
onClick={() => handleStepClick(step.step)}
|
onClick={() => handleStepClick(step.step)}
|
||||||
// TODO: add success class
|
// TODO: add success class
|
||||||
className={values.step === step.step ? styles.current : null}
|
className={values.stepCurrent === step.step ? styles.current : null}
|
||||||
>
|
>
|
||||||
{step.title}
|
{step.title}
|
||||||
</li>
|
</li>
|
||||||
|
@ -4,7 +4,6 @@ import Tags from '@shared/atoms/Tags'
|
|||||||
import MetaItem from '../../Asset/AssetContent/MetaItem'
|
import MetaItem from '../../Asset/AssetContent/MetaItem'
|
||||||
import FileIcon from '@shared/FileIcon'
|
import FileIcon from '@shared/FileIcon'
|
||||||
import Button from '@shared/atoms/Button'
|
import Button from '@shared/atoms/Button'
|
||||||
import { transformTags } from '@utils/ddo'
|
|
||||||
import NetworkName from '@shared/NetworkName'
|
import NetworkName from '@shared/NetworkName'
|
||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
|
@ -4,18 +4,19 @@ import { wizardSteps } from './_constants'
|
|||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
import { FormPublishData } from './_types'
|
import { FormPublishData } from './_types'
|
||||||
|
|
||||||
export function Steps({ step }: { step: number }): ReactElement {
|
export function Steps(): ReactElement {
|
||||||
const { chainId } = useWeb3()
|
const { chainId, accountId } = useWeb3()
|
||||||
const { setFieldValue } = useFormikContext<FormPublishData>()
|
const { values, setFieldValue } = useFormikContext<FormPublishData>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!chainId) return
|
if (!chainId || !accountId) return
|
||||||
|
|
||||||
setFieldValue('chainId', chainId)
|
setFieldValue('chainId', chainId)
|
||||||
}, [chainId, setFieldValue])
|
setFieldValue('accountId', accountId)
|
||||||
|
}, [chainId, accountId, setFieldValue])
|
||||||
|
|
||||||
const { component } = wizardSteps.filter(
|
const { component } = wizardSteps.filter(
|
||||||
(stepContent) => stepContent.step === step
|
(stepContent) => stepContent.step === values.stepCurrent
|
||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
return component
|
return component
|
||||||
|
@ -32,8 +32,9 @@ export const wizardSteps: StepContent[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const initialValues: FormPublishData = {
|
export const initialValues: FormPublishData = {
|
||||||
step: 1,
|
stepCurrent: 1,
|
||||||
chainId: 1,
|
chainId: 1,
|
||||||
|
accountId: '',
|
||||||
metadata: {
|
metadata: {
|
||||||
type: 'dataset',
|
type: 'dataset',
|
||||||
name: '',
|
name: '',
|
||||||
@ -47,9 +48,9 @@ export const initialValues: FormPublishData = {
|
|||||||
files: [],
|
files: [],
|
||||||
links: [],
|
links: [],
|
||||||
dataTokenOptions: { name: '', symbol: '' },
|
dataTokenOptions: { name: '', symbol: '' },
|
||||||
timeout: 'Forever',
|
timeout: '',
|
||||||
access: '',
|
access: '',
|
||||||
providerUrl: ''
|
providerUrl: 'https://provider.oceanprotocol.com'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
pricing: {
|
pricing: {
|
||||||
@ -84,17 +85,17 @@ const validationMetadata = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const validationService = {
|
const validationService = {
|
||||||
files: Yup.array<FileMetadata>()
|
files: Yup.array<string[]>()
|
||||||
.required('Enter a valid URL and click "ADD FILE"')
|
.required('Enter a valid URL and click "ADD FILE"')
|
||||||
.nullable(),
|
.nullable(),
|
||||||
links: Yup.array<FileMetadata[]>().nullable(),
|
links: Yup.array<string[]>().nullable(),
|
||||||
dataTokenOptions: Yup.object().shape({
|
dataTokenOptions: Yup.object().shape({
|
||||||
name: Yup.string(),
|
name: Yup.string(),
|
||||||
symbol: Yup.string()
|
symbol: Yup.string()
|
||||||
}),
|
}),
|
||||||
timeout: Yup.string().required('Required'),
|
timeout: Yup.string().required('Required'),
|
||||||
access: Yup.string()
|
access: Yup.string()
|
||||||
.matches(/Compute|Download/g, { excludeEmptyString: true })
|
.matches(/compute|download/g, { excludeEmptyString: true })
|
||||||
.required('Required'),
|
.required('Required'),
|
||||||
providerUrl: Yup.string().url().nullable()
|
providerUrl: Yup.string().url().nullable()
|
||||||
}
|
}
|
||||||
@ -123,8 +124,9 @@ const validationPricing = {
|
|||||||
|
|
||||||
// export const validationSchema: Yup.SchemaOf<FormPublishData> =
|
// export const validationSchema: Yup.SchemaOf<FormPublishData> =
|
||||||
export const validationSchema: Yup.SchemaOf<any> = Yup.object().shape({
|
export const validationSchema: Yup.SchemaOf<any> = Yup.object().shape({
|
||||||
step: Yup.number(),
|
stepCurrent: Yup.number(),
|
||||||
chainId: Yup.number(),
|
chainId: Yup.number(),
|
||||||
|
accountId: Yup.string(),
|
||||||
metadata: Yup.object().shape(validationMetadata),
|
metadata: Yup.object().shape(validationMetadata),
|
||||||
services: Yup.array().of(Yup.object().shape(validationService)),
|
services: Yup.array().of(Yup.object().shape(validationService)),
|
||||||
pricing: Yup.object().shape(validationPricing)
|
pricing: Yup.object().shape(validationPricing)
|
||||||
|
@ -2,7 +2,7 @@ import { DataTokenOptions } from '@hooks/usePublish'
|
|||||||
import { ReactElement } from 'react'
|
import { ReactElement } from 'react'
|
||||||
|
|
||||||
export interface FormPublishService {
|
export interface FormPublishService {
|
||||||
files: string | FileMetadata[]
|
files: string | string[]
|
||||||
links?: string[]
|
links?: string[]
|
||||||
timeout: string
|
timeout: string
|
||||||
dataTokenOptions: DataTokenOptions
|
dataTokenOptions: DataTokenOptions
|
||||||
@ -14,7 +14,9 @@ export interface FormPublishService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FormPublishData {
|
export interface FormPublishData {
|
||||||
step: number
|
stepCurrent: number
|
||||||
|
accountId: string
|
||||||
|
chainId: number
|
||||||
metadata: {
|
metadata: {
|
||||||
type: 'dataset' | 'algorithm'
|
type: 'dataset' | 'algorithm'
|
||||||
name: string
|
name: string
|
||||||
@ -25,7 +27,6 @@ export interface FormPublishData {
|
|||||||
}
|
}
|
||||||
services: FormPublishService[]
|
services: FormPublishService[]
|
||||||
pricing: PriceOptions
|
pricing: PriceOptions
|
||||||
chainId: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StepContent {
|
export interface StepContent {
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
|
import axios, { AxiosResponse } from 'axios'
|
||||||
import { sha256 } from 'js-sha256'
|
import { sha256 } from 'js-sha256'
|
||||||
import {
|
import slugify from 'slugify'
|
||||||
dateToStringNoMS,
|
|
||||||
transformTags,
|
|
||||||
getUrlFileExtension
|
|
||||||
} from '@utils/ddo'
|
|
||||||
import { FormPublishData } from './_types'
|
import { FormPublishData } from './_types'
|
||||||
|
|
||||||
function encryptMe(files: string | FileMetadata[]): string {
|
|
||||||
throw new Error('Function not implemented.')
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getFieldContent(
|
export function getFieldContent(
|
||||||
fieldName: string,
|
fieldName: string,
|
||||||
fields: FormFieldContent[]
|
fields: FormFieldContent[]
|
||||||
@ -17,15 +10,52 @@ export function getFieldContent(
|
|||||||
return fields.filter((field: FormFieldContent) => field.name === fieldName)[0]
|
return fields.filter((field: FormFieldContent) => field.name === fieldName)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformPublishFormToDdo(
|
async function getEncryptedFileUrls(
|
||||||
|
files: string[],
|
||||||
|
providerUrl: string,
|
||||||
|
did: string,
|
||||||
|
accountId: string
|
||||||
|
): Promise<string> {
|
||||||
|
try {
|
||||||
|
// https://github.com/oceanprotocol/provider/blob/v4main/API.md#encrypt-endpoint
|
||||||
|
const url = `${providerUrl}/api/v1/services/encrypt`
|
||||||
|
const response: AxiosResponse<{ encryptedDocument: string }> =
|
||||||
|
await axios.post(url, {
|
||||||
|
documentId: did,
|
||||||
|
signature: '', // TODO: add signature
|
||||||
|
publisherAddress: accountId,
|
||||||
|
document: files
|
||||||
|
})
|
||||||
|
return response?.data?.encryptedDocument
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error parsing json: ' + error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUrlFileExtension(fileUrl: string): string {
|
||||||
|
const splittedFileUrl = fileUrl.split('.')
|
||||||
|
return splittedFileUrl[splittedFileUrl.length - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
function dateToStringNoMS(date: Date): string {
|
||||||
|
return date.toISOString().replace(/\.[0-9]{3}Z/, 'Z')
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformTags(value: string): string[] {
|
||||||
|
const originalTags = value?.split(',')
|
||||||
|
const transformedTags = originalTags?.map((tag) => slugify(tag).toLowerCase())
|
||||||
|
return transformedTags
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function transformPublishFormToDdo(
|
||||||
values: FormPublishData,
|
values: FormPublishData,
|
||||||
datatokenAddress: string,
|
datatokenAddress: string,
|
||||||
nftAddress: string
|
nftAddress: string
|
||||||
): DDO {
|
): Promise<DDO> {
|
||||||
const did = sha256(`${nftAddress}${values.chainId}`)
|
const { chainId, accountId, metadata, services } = values
|
||||||
|
const did = sha256(`${nftAddress}${chainId}`)
|
||||||
const currentTime = dateToStringNoMS(new Date())
|
const currentTime = dateToStringNoMS(new Date())
|
||||||
const { type, name, description, tags, author, termsAndConditions } =
|
const { type, name, description, tags, author, termsAndConditions } = metadata
|
||||||
values.metadata
|
|
||||||
const {
|
const {
|
||||||
access,
|
access,
|
||||||
files,
|
files,
|
||||||
@ -35,11 +65,16 @@ export function transformPublishFormToDdo(
|
|||||||
entrypoint,
|
entrypoint,
|
||||||
providerUrl,
|
providerUrl,
|
||||||
timeout
|
timeout
|
||||||
} = values.services[0]
|
} = services[0]
|
||||||
|
|
||||||
const fileUrl = typeof files !== 'string' && files[0].url
|
const filesEncrypted = await getEncryptedFileUrls(
|
||||||
|
files as string[],
|
||||||
|
providerUrl,
|
||||||
|
did,
|
||||||
|
accountId
|
||||||
|
)
|
||||||
|
|
||||||
const metadata: Metadata = {
|
const newMetadata: Metadata = {
|
||||||
created: currentTime,
|
created: currentTime,
|
||||||
updated: currentTime,
|
updated: currentTime,
|
||||||
type,
|
type,
|
||||||
@ -54,7 +89,7 @@ export function transformPublishFormToDdo(
|
|||||||
},
|
},
|
||||||
...(type === 'algorithm' && {
|
...(type === 'algorithm' && {
|
||||||
algorithm: {
|
algorithm: {
|
||||||
language: getUrlFileExtension(fileUrl),
|
language: getUrlFileExtension(files[0]),
|
||||||
version: '0.1',
|
version: '0.1',
|
||||||
container: {
|
container: {
|
||||||
entrypoint,
|
entrypoint,
|
||||||
@ -66,9 +101,9 @@ export function transformPublishFormToDdo(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const service: Service = {
|
const newService: Service = {
|
||||||
type: access,
|
type: access,
|
||||||
files: encryptMe(files),
|
files: filesEncrypted,
|
||||||
datatokenAddress,
|
datatokenAddress,
|
||||||
serviceEndpoint: providerUrl,
|
serviceEndpoint: providerUrl,
|
||||||
timeout,
|
timeout,
|
||||||
@ -92,9 +127,9 @@ export function transformPublishFormToDdo(
|
|||||||
'@context': ['https://w3id.org/did/v1'],
|
'@context': ['https://w3id.org/did/v1'],
|
||||||
id: did,
|
id: did,
|
||||||
version: '4.0.0',
|
version: '4.0.0',
|
||||||
chainId: values.chainId,
|
chainId,
|
||||||
metadata,
|
metadata: newMetadata,
|
||||||
services: [service]
|
services: [newService]
|
||||||
}
|
}
|
||||||
|
|
||||||
return newDdo
|
return newDdo
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { ReactElement, useState, useRef } from 'react'
|
import React, { ReactElement, useState, useRef } from 'react'
|
||||||
import { Form, Formik, FormikState } from 'formik'
|
import { Form, Formik, FormikState } from 'formik'
|
||||||
import { usePublish } from '@hooks/usePublish'
|
|
||||||
import { initialValues, validationSchema } from './_constants'
|
import { initialValues, validationSchema } from './_constants'
|
||||||
import { validateDockerImage } from '@utils/docker'
|
import { validateDockerImage } from '@utils/docker'
|
||||||
import { Logger, Metadata } from '@oceanprotocol/lib'
|
import { Logger, Metadata } from '@oceanprotocol/lib'
|
||||||
@ -15,6 +14,7 @@ import Debug from './Debug'
|
|||||||
import Navigation from './Navigation'
|
import Navigation from './Navigation'
|
||||||
import { Steps } from './Steps'
|
import { Steps } from './Steps'
|
||||||
import { FormPublishData } from './_types'
|
import { FormPublishData } from './_types'
|
||||||
|
import { sha256 } from 'js-sha256'
|
||||||
|
|
||||||
const formName = 'ocean-publish-form'
|
const formName = 'ocean-publish-form'
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ export default function PublishPage({
|
|||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { accountId, chainId } = useWeb3()
|
const { accountId, chainId } = useWeb3()
|
||||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||||
const { publish, publishError, isLoading, publishStepText } = usePublish()
|
// const { publish, publishError, isLoading, publishStepText } = usePublish()
|
||||||
const [success, setSuccess] = useState<string>()
|
const [success, setSuccess] = useState<string>()
|
||||||
const [error, setError] = useState<string>()
|
const [error, setError] = useState<string>()
|
||||||
const scrollToRef = useRef()
|
const scrollToRef = useRef()
|
||||||
@ -35,10 +35,22 @@ export default function PublishPage({
|
|||||||
// 1. Mint NFT & datatokens & put in pool
|
// 1. Mint NFT & datatokens & put in pool
|
||||||
// const txMint = await createNftWithErc()
|
// const txMint = await createNftWithErc()
|
||||||
// const { nftAddress, datatokenAddress } = txMint.logs[0].args
|
// const { nftAddress, datatokenAddress } = txMint.logs[0].args
|
||||||
|
//
|
||||||
// 2. Construct and publish DDO
|
// 2. Construct and publish DDO
|
||||||
// const did = sha256(`${nftAddress}${chainId}`)
|
// const did = sha256(`${nftAddress}${chainId}`)
|
||||||
// const ddo = transformPublishFormToDdo(values, datatokenAddress, nftAddress)
|
// const ddo = transformPublishFormToDdo(values, datatokenAddress, nftAddress)
|
||||||
// const txPublish = await publish(ddo)
|
// const txPublish = await publish(ddo)
|
||||||
|
//
|
||||||
|
// 3. Integrity check of DDO before & after publishing
|
||||||
|
// const checksumBefore = sha256(ddo)
|
||||||
|
// const ddoFromChain = await getDdoFromChain(ddo.id)
|
||||||
|
// const ddoFromChainDecrypted = await decryptDdo(ddoFromChain)
|
||||||
|
// const checksumAfter = sha256(ddoFromChainDecrypted)
|
||||||
|
|
||||||
|
// if (checksumBefore !== checksumAfter) {
|
||||||
|
// throw new Error('DDO integrity check failed!')
|
||||||
|
// }
|
||||||
|
|
||||||
setSuccess('Your DDO was published successfully!')
|
setSuccess('Your DDO was published successfully!')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setError(error.message)
|
setError(error.message)
|
||||||
@ -109,16 +121,12 @@ export default function PublishPage({
|
|||||||
await handleSubmit(values)
|
await handleSubmit(values)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ values }) => (
|
<Form className={styles.form} ref={scrollToRef}>
|
||||||
<>
|
<Navigation />
|
||||||
<Form className={styles.form} ref={scrollToRef}>
|
<Steps />
|
||||||
<Navigation />
|
<Actions scrollToRef={scrollToRef} />
|
||||||
<Steps step={values.step} />
|
</Form>
|
||||||
<Actions scrollToRef={scrollToRef} />
|
<Debug />
|
||||||
</Form>
|
|
||||||
<Debug values={values} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Formik>
|
</Formik>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user