From 45eea31d66d339b39f92bb9aff930dbe8f6f4078 Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Mon, 19 Sep 2022 15:54:07 +0300 Subject: [PATCH] WIP enforce docker container --- content/publish/form.json | 13 +-- .../FormFields/ContainerInput/index.tsx | 98 +++++++++++++++++++ .../@shared/FormFields/URLInput/index.tsx | 4 +- .../@shared/FormInput/InputElement.tsx | 3 + src/components/Publish/Metadata/index.tsx | 5 +- 5 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 src/components/@shared/FormFields/ContainerInput/index.tsx diff --git a/content/publish/form.json b/content/publish/form.json index fef5b8d7b..c2deac798 100644 --- a/content/publish/form.json +++ b/content/publish/form.json @@ -55,15 +55,16 @@ { "name": "dockerImageCustom", "label": "Docker Image URL", - "placeholder": "e.g. oceanprotocol/algo_dockers or https://example.com/image_path", - "help": "Provide the name of a public Docker image or the full url if you have it hosted in a 3rd party repo", + "placeholder": "e.g. oceanprotocol/algo_dockers:latest or https://example.com/image_path:image_tag", + "help": "Provide the name and the tag of a public Docker hub image or the full url if you have it hosted in a 3rd party repo", + "type": "container", "required": true }, { - "name": "dockerImageCustomTag", - "label": "Docker Image Tag", - "placeholder": "e.g. latest", - "help": "Provide the tag for your Docker image.", + "name": "dockerImageChecksum", + "label": "Docker container checksum", + "placeholder": "e.g. sha256:xiXqb7Vet0FbN9q0GFMgUdi5C22wjJT0i2G6lYKC2jl6QxkKzVz7KaPDgqfTMjNF", + "help": "Provide the checksum of your docker container image.", "required": true }, { diff --git a/src/components/@shared/FormFields/ContainerInput/index.tsx b/src/components/@shared/FormFields/ContainerInput/index.tsx new file mode 100644 index 000000000..705426bc8 --- /dev/null +++ b/src/components/@shared/FormFields/ContainerInput/index.tsx @@ -0,0 +1,98 @@ +import React, { ReactElement, useState } from 'react' +import { useField, useFormikContext } from 'formik' +import UrlInput from '../URLInput' +import { InputProps } from '@shared/FormInput' +import { FormPublishData } from 'src/components/Publish/_types' +import { LoggerInstance } from '@oceanprotocol/lib' +import { toast } from 'react-toastify' +import axios from 'axios' +import isUrl from 'is-url-superb' + +export default function FilesInput(props: InputProps): ReactElement { + const [field, meta, helpers] = useField(props.name) + const [isLoading, setIsLoading] = useState(false) + const { values, setFieldError } = useFormikContext() + + async function getContainerChecksum( + image: string, + tag: string + ): Promise { + try { + const response = await axios.post( + `https://dockerhub-proxy.oceanprotocol.com`, + { + image, + tag + } + ) + if ( + !response || + response.status !== 200 || + response.data.status !== 'success' + ) { + toast.error( + 'Could not fetch docker hub image info. Please input the container checksum manually' + ) + return null + } + return response.data.result.checksum + } catch (error) { + LoggerInstance.error(error.message) + toast.error( + 'Could not fetch docker hub image info. Please input the container checksum manually' + ) + return null + } + } + + async function handleValidation(e: React.SyntheticEvent, container: string) { + e.preventDefault() + try { + console.log('isUrl(container)', isUrl(container)) + setIsLoading(true) + if (!isUrl(container, { lenient: false })) { + const parsedContainerValue = container.split(':') + const checksum = await getContainerChecksum( + parsedContainerValue[0], + parsedContainerValue[1] + ) + values.metadata.dockerImageCustom = parsedContainerValue[0] + values.metadata.dockerImageCustomTag = parsedContainerValue[1] + if (checksum) { + values.metadata.dockerImageCustomChecksum = checksum + } + } else { + console.log('open input modal') + } + } catch (error) { + setFieldError(`${field.name}[0].url`, error.message) + LoggerInstance.error(error.message) + } finally { + setIsLoading(false) + } + } + + function handleClose() { + helpers.setValue(meta.initialValue) + helpers.setTouched(false) + } + + return ( + <> + + + {/* {field?.value?.[0]?.valid === true ? ( + + ) : ( + + )} */} + + ) +} diff --git a/src/components/@shared/FormFields/URLInput/index.tsx b/src/components/@shared/FormFields/URLInput/index.tsx index 3890032c9..af7d0fdf3 100644 --- a/src/components/@shared/FormFields/URLInput/index.tsx +++ b/src/components/@shared/FormFields/URLInput/index.tsx @@ -12,12 +12,14 @@ export default function URLInput({ handleButtonClick, isLoading, name, + checkUrl, ...props }: { submitText: string handleButtonClick(e: React.SyntheticEvent, data: string): void isLoading: boolean name: string + checkUrl?: boolean }): ReactElement { const [field, meta] = useField(name) const [isButtonDisabled, setIsButtonDisabled] = useState(true) @@ -28,7 +30,7 @@ export default function URLInput({ setIsButtonDisabled( !field?.value || field.value === '' || - !isUrl(field.value) || + (checkUrl && !isUrl(field.value)) || field.value.includes('javascript:') || meta?.error ) diff --git a/src/components/@shared/FormInput/InputElement.tsx b/src/components/@shared/FormInput/InputElement.tsx index 343889238..791e5ba73 100644 --- a/src/components/@shared/FormInput/InputElement.tsx +++ b/src/components/@shared/FormInput/InputElement.tsx @@ -11,6 +11,7 @@ import AssetSelection, { } from '../FormFields/AssetSelection' import Nft from '../FormFields/Nft' import InputRadio from './InputRadio' +import ContainerInput from '@shared/FormFields/ContainerInput' const cx = classNames.bind(styles) @@ -107,6 +108,8 @@ export default function InputElement({ ) case 'files': return + case 'container': + return case 'providerUrl': return case 'nft': diff --git a/src/components/Publish/Metadata/index.tsx b/src/components/Publish/Metadata/index.tsx index 2be4852bd..1954acbb6 100644 --- a/src/components/Publish/Metadata/index.tsx +++ b/src/components/Publish/Metadata/index.tsx @@ -124,11 +124,12 @@ export default function MetadataFields(): ReactElement { />