From bcd92a9f19b62f169b88cb7e1e39828035ab4e81 Mon Sep 17 00:00:00 2001 From: Mikhail Petrov Date: Thu, 15 Aug 2024 19:00:31 +0300 Subject: [PATCH 1/2] web: Move formatBytes func to handle file Signed-off-by: Mikhail Petrov --- src/App.js | 10 ---------- src/Components/ContainerItem/ContainerItem.js | 2 -- src/Components/TreeView/TreeView.js | 8 +------- src/Functions/handle.js | 9 +++++++++ src/Getobject.js | 2 +- src/Profile.js | 2 -- 6 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/App.js b/src/App.js index 2524ce2..9939e98 100644 --- a/src/App.js +++ b/src/App.js @@ -34,15 +34,6 @@ function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } -function formatBytes(bytes) { - const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; - let i = 0 - for (i; bytes >= 1024; i += 1) { - bytes /= 1024; - } - return `${bytes === 0 ? bytes : bytes.toFixed(1)} ${units[i]}`; -} - export const App = () => { const location = useLocation(); const navigate = useNavigate(); @@ -1861,7 +1852,6 @@ export const App = () => { element={ { @@ -11,7 +12,6 @@ const Tree = ({ children }) => { const Branch = ({ params, - formatBytes, objectPath, containerItem, containerChildren, @@ -31,7 +31,6 @@ const Branch = ({ { const File = ({ params, - formatBytes, name, containerItem, objectItem, @@ -305,7 +302,6 @@ Tree.Branch = Branch; export default function TreeView({ params, - formatBytes, containerItem, walletData, onModal, @@ -325,7 +321,6 @@ export default function TreeView({ {objectPath !== '/' && ( = 1024; i += 1) { + bytes /= 1024; + } + return `${bytes === 0 ? bytes : bytes.toFixed(1)} ${units[i]}`; +} diff --git a/src/Getobject.js b/src/Getobject.js index d226185..d381cef 100644 --- a/src/Getobject.js +++ b/src/Getobject.js @@ -6,11 +6,11 @@ import { Heading, Box, } from 'react-bulma-components'; +import { formatBytes } from './Functions/handle'; import api from './api'; const Getobject = ({ onModal, - formatBytes, ContentTypeHeader, AuthorizationHeader, }) => { diff --git a/src/Profile.js b/src/Profile.js index 7230c78..d64f280 100644 --- a/src/Profile.js +++ b/src/Profile.js @@ -18,7 +18,6 @@ function formatAddress(address) { const Profile = ({ params, - formatBytes, NeoFSContract, activeNet, walletData, @@ -289,7 +288,6 @@ const Profile = ({ Date: Thu, 15 Aug 2024 19:02:21 +0300 Subject: [PATCH 2/2] web: Switch to new REST object APIs, closes #214 Signed-off-by: Mikhail Petrov --- src/App.js | 82 +++++++------------ src/Components/ContainerItem/ContainerItem.js | 30 +------ src/Components/EACLPanel/EACLPanel.js | 14 +--- src/Components/TreeView/TreeView.js | 82 ++++++------------- src/Getobject.js | 34 ++++---- src/Profile.js | 11 --- src/api.js | 17 +++- 7 files changed, 92 insertions(+), 178 deletions(-) diff --git a/src/App.js b/src/App.js index 9939e98..190ba76 100644 --- a/src/App.js +++ b/src/App.js @@ -47,14 +47,6 @@ export const App = () => { scriptHash: Neon.create.account(process.env.REACT_APP_NEOFS_ACCOUNT).scriptHash, }); - const [ContentTypeHeader] = useState("Content-Type"); - const [AuthorizationHeader] = useState("Authorization"); - const [BearerOwnerIdHeader] = useState("X-Bearer-Owner-Id"); - const [BearerForAllUsers] = useState("X-Bearer-For-All-Users"); - const [BearerSignatureHeader] = useState("X-Bearer-Signature"); - const [BearerSignatureKeyHeader] = useState("X-Bearer-Signature-Key"); - const [BearerLifetime] = useState("X-Bearer-Lifetime"); - const [params] = useState({ rest_gw: process.env.REACT_APP_RESTGW ? process.env.REACT_APP_RESTGW : 'https://rest.t5.fs.neo.org/v1', }); @@ -344,10 +336,9 @@ export const App = () => { } api('POST', '/auth', body, { - [ContentTypeHeader]: "application/json", - [BearerOwnerIdHeader]: walletData.account.address, - [BearerLifetime]: params.objectId ? 24 : 2, - [BearerForAllUsers]: true, + "X-Bearer-Owner-Id": walletData.account.address, + "X-Bearer-Lifetime": params.objectId ? 24 : 2, + "X-Bearer-For-All-Users": true, }).then((e) => { onSignMessage(e[0].token, type, operation, params); }); @@ -387,10 +378,9 @@ export const App = () => { if (type === 'object') { api('GET', '/auth/bearer?walletConnect=true', {}, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${msg}`, - [BearerSignatureHeader]: response.data + response.salt, - [BearerSignatureKeyHeader]: response.publicKey, + "Authorization": `Bearer ${msg}`, + "X-Bearer-Signature": response.data + response.salt, + "X-Bearer-Signature-Key": response.publicKey, }).then((e) => { if (params.objectId) { onModal('shareObjectLink', { ...params, token: e.token }) @@ -416,11 +406,10 @@ export const App = () => { "basicAcl": containerForm.basicAcl, "attributes": attributes, }, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.container.PUT.token}`, - [BearerOwnerIdHeader]: walletData.account.address, - [BearerSignatureHeader]: walletData.tokens.container.PUT.signature, - [BearerSignatureKeyHeader]: walletData.publicKey, + "Authorization": `Bearer ${walletData.tokens.container.PUT.token}`, + "X-Bearer-Owner-Id": walletData.account.address, + "X-Bearer-Signature": walletData.tokens.container.PUT.signature, + "X-Bearer-Signature-Key": walletData.publicKey, }).then((e) => { if (e.message && e.message.indexOf('insufficient balance to create container') !== -1) { setLoadingForm(false); @@ -442,11 +431,10 @@ export const App = () => { api('PUT', `/containers/${e.containerId}/eacl?walletConnect=true`, { "records": containerForm.eACLParams.filter((item) => delete item.isOpen), }, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.container.SETEACL.token}`, - [BearerOwnerIdHeader]: walletData.account.address, - [BearerSignatureHeader]: walletData.tokens.container.SETEACL.signature, - [BearerSignatureKeyHeader]: walletData.publicKey, + "Authorization": `Bearer ${walletData.tokens.container.SETEACL.token}`, + "X-Bearer-Owner-Id": walletData.account.address, + "X-Bearer-Signature": walletData.tokens.container.SETEACL.signature, + "X-Bearer-Signature-Key": walletData.publicKey, }).then(() => { setLoadingForm(false); onPopup('success', 'New container with EACL has been created'); @@ -493,11 +481,10 @@ export const App = () => { setLoadingForm(true); setError({ active: false, type: [], text: '' }); api('DELETE', `/containers/${containerName}?walletConnect=true`, {}, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.container.DELETE.token}`, - [BearerOwnerIdHeader]: walletData.account.address, - [BearerSignatureHeader]: walletData.tokens.container.DELETE.signature, - [BearerSignatureKeyHeader]: walletData.publicKey, + "Authorization": `Bearer ${walletData.tokens.container.DELETE.token}`, + "X-Bearer-Owner-Id": walletData.account.address, + "X-Bearer-Signature": walletData.tokens.container.DELETE.signature, + "X-Bearer-Signature-Key": walletData.publicKey, }).then((e) => { setLoadingForm(false); if (e.message) { @@ -534,16 +521,15 @@ export const App = () => { setError({ active: false, type: [], text: '' }); setLoadingForm(true); - let formdata = new FormData(); - formdata.append('data', objectForm.file); - formdata.append('name', objectForm.name); - const attributesHeaders = {}; - attributes.map((attribute) => attributesHeaders[`X-Attribute-${attribute.key}`] = attribute.value); - api('POST', `/upload/${containerId}`, formdata, { - 'Content-Type': "multipart/form-data", - [AuthorizationHeader]: `Bearer ${walletData.tokens.object.bearer}`, - ...attributesHeaders, + attributes.map((attribute) => attributesHeaders[attribute.key] = attribute.value); + api('POST', `/objects/${containerId}`, objectForm.file, { + 'Content-Type': objectForm.file.type, + "Authorization": `Bearer ${walletData.tokens.object.bearer}`, + 'X-Attributes': JSON.stringify({ + 'FileName': objectForm.name, + ...attributesHeaders, + }), }).then((e) => { setLoadingForm(false); if (e.message && e.message.indexOf('access to object operation denied') !== -1) { @@ -574,12 +560,8 @@ export const App = () => { const onDeleteObject = (containerId, objectId) => { setError({ active: false, type: [], text: '' }); setLoadingForm(true); - api('DELETE', `/objects/${containerId}/${objectId}?walletConnect=true`, {}, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.object.token}`, - [BearerOwnerIdHeader]: walletData.account.address, - [BearerSignatureHeader]: walletData.tokens.object.signature, - [BearerSignatureKeyHeader]: walletData.publicKey, + api('DELETE', `/objects/${containerId}/${objectId}`, {}, { + "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { setLoadingForm(false); if (e.message) { @@ -1842,9 +1824,6 @@ export const App = () => { path="/getobject" element={} /> { isLoadContainers={isLoadContainers} setLoadContainers={setLoadContainers} onDisconnectWallet={onDisconnectWallet} - ContentTypeHeader={ContentTypeHeader} - AuthorizationHeader={AuthorizationHeader} - BearerOwnerIdHeader={BearerOwnerIdHeader} - BearerSignatureHeader={BearerSignatureHeader} - BearerSignatureKeyHeader={BearerSignatureKeyHeader} onModal={onModal} onPopup={onPopup} />} diff --git a/src/Components/ContainerItem/ContainerItem.js b/src/Components/ContainerItem/ContainerItem.js index 644d714..27795bf 100644 --- a/src/Components/ContainerItem/ContainerItem.js +++ b/src/Components/ContainerItem/ContainerItem.js @@ -15,7 +15,6 @@ import { import api from '../../api'; export default function ContainerItem({ - params, containerItem, onAuth, walletData, @@ -25,11 +24,6 @@ export default function ContainerItem({ index, isLoadContainers, setLoadContainers, - ContentTypeHeader, - AuthorizationHeader, - BearerOwnerIdHeader, - BearerSignatureHeader, - BearerSignatureKeyHeader, }) { const ObjectsPerPage = 40; const [isOpen, setIsOpen] = useState(false); @@ -89,14 +83,10 @@ export default function ContainerItem({ const onGetObjects = (containerId, pageTemp = pagination.page) => { setPagination({ ...pagination, page: pageTemp}); setLoadingObjects(true); - api('POST', `/objects/${containerId}/search?walletConnect=true&limit=${ObjectsPerPage}&offset=${pageTemp * ObjectsPerPage}`, { + api('POST', `/objects/${containerId}/search?limit=${ObjectsPerPage}&offset=${pageTemp * ObjectsPerPage}`, { "filters": [], }, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.object.token}`, - [BearerOwnerIdHeader]: walletData.account.address, - [BearerSignatureHeader]: walletData.tokens.object.signature, - [BearerSignatureKeyHeader]: walletData.publicKey, + "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { setLoadingObjects(false); if (e.message) { @@ -110,9 +100,8 @@ export default function ContainerItem({ const onGetEACL = (containerId) => { setLoadingEACL(true); - api('GET', `/containers/${containerId}/eacl?walletConnect=true`, {}, { - [ContentTypeHeader]: "application/json", - [BearerOwnerIdHeader]: walletData.account.address, + api('GET', `/containers/${containerId}/eacl`, {}, { + "X-Bearer-Owner-Id": walletData.account.address, }).then((e) => { setLoadingEACL(false); if (e.records) { @@ -239,11 +228,6 @@ export default function ContainerItem({ setLoadContainers={setLoadContainers} eACLParams={eACLParams} setEACLParams={setEACLParams} - ContentTypeHeader={ContentTypeHeader} - AuthorizationHeader={AuthorizationHeader} - BearerOwnerIdHeader={BearerOwnerIdHeader} - BearerSignatureHeader={BearerSignatureHeader} - BearerSignatureKeyHeader={BearerSignatureKeyHeader} /> )} @@ -329,17 +313,11 @@ export default function ContainerItem({ Objects not found )} {!(pagination.page === 0 && pagination.objects === 0) && (
diff --git a/src/Components/EACLPanel/EACLPanel.js b/src/Components/EACLPanel/EACLPanel.js index 726d390..c01b6ec 100644 --- a/src/Components/EACLPanel/EACLPanel.js +++ b/src/Components/EACLPanel/EACLPanel.js @@ -16,11 +16,6 @@ export default function EACLPanel({ setLoadContainers, eACLParams, setEACLParams, - ContentTypeHeader, - AuthorizationHeader, - BearerOwnerIdHeader, - BearerSignatureHeader, - BearerSignatureKeyHeader, isEdit = true, isErrorParent, }) { @@ -44,11 +39,10 @@ export default function EACLPanel({ api('PUT', `/containers/${containerId}/eacl?walletConnect=true`, { "records": eACLParams.filter((item) => delete item.isOpen), }, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.container.SETEACL.token}`, - [BearerOwnerIdHeader]: walletData.account.address, - [BearerSignatureHeader]: walletData.tokens.container.SETEACL.signature, - [BearerSignatureKeyHeader]: walletData.publicKey, + "Authorization": `Bearer ${walletData.tokens.container.SETEACL.token}`, + "X-Bearer-Owner-Id": walletData.account.address, + "X-Bearer-Signature": walletData.tokens.container.SETEACL.signature, + "X-Bearer-Signature-Key": walletData.publicKey, }).then((e) => { setLoadingForm(false); if (e.message) { diff --git a/src/Components/TreeView/TreeView.js b/src/Components/TreeView/TreeView.js index fd1d87d..f17f228 100644 --- a/src/Components/TreeView/TreeView.js +++ b/src/Components/TreeView/TreeView.js @@ -19,11 +19,6 @@ const Branch = ({ onGetObjects, containerIndex, onModal, - ContentTypeHeader, - AuthorizationHeader, - BearerOwnerIdHeader, - BearerSignatureHeader, - BearerSignatureKeyHeader, }) => { return ( @@ -38,27 +33,16 @@ const Branch = ({ containerChildren={containerChildren[objectPath]} containerIndex={containerIndex} onGetObjects={onGetObjects} - ContentTypeHeader={ContentTypeHeader} - AuthorizationHeader={AuthorizationHeader} - BearerOwnerIdHeader={BearerOwnerIdHeader} - BearerSignatureHeader={BearerSignatureHeader} - BearerSignatureKeyHeader={BearerSignatureKeyHeader} /> )))} {containerChildren[objectPath]['/'] && containerChildren[objectPath]['/'].map((objectItem, objectIndex) => ( ))} @@ -92,17 +76,11 @@ const Folder = ({ name, children }) => { }; const File = ({ - params, name, containerItem, objectItem, walletData, onModal, - ContentTypeHeader, - AuthorizationHeader, - BearerOwnerIdHeader, - BearerSignatureHeader, - BearerSignatureKeyHeader, }) => { const [isOpen, setIsOpen] = useState(false); const [objectDate, setObjectDate] = useState(null); @@ -110,12 +88,8 @@ const File = ({ const handleToggle = e => { setIsOpen(!isOpen); if (!isOpen) { - api('GET', `/objects/${containerItem.containerId}/${objectItem.address.objectId}?walletConnect=true`, {}, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.object.token}`, - [BearerOwnerIdHeader]: walletData.account.address, - [BearerSignatureHeader]: walletData.tokens.object.signature, - [BearerSignatureKeyHeader]: walletData.publicKey, + api('HEAD', `/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { setObjectDate(e); }); @@ -168,12 +142,20 @@ const File = ({
Attributes - {objectDate.attributes.map((attribute) => ( - - {`${attribute.key}: `} - {attribute.value} - - ))} + {objectDate ? ( + <> + {Object.keys(objectDate.attributes).map((attributeKey) => ( + + {`${attributeKey}: `} + {objectDate.attributes[attributeKey]} + + ))} + + Content-Type: + {objectDate.contentType} + + + ) : '-'}
Manage @@ -184,9 +166,8 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('GET', `/get/${containerItem.containerId}/${objectItem.address.objectId}`, {}, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.object.bearer}`, + api('GET', `/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((data) => { if (data.message) { onModal('failed', data.message); @@ -220,9 +201,8 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('GET', `/get/${containerItem.containerId}/${objectItem.address.objectId}`, {}, { - [ContentTypeHeader]: "application/json", - [AuthorizationHeader]: `Bearer ${walletData.tokens.object.bearer}`, + api('GET', `/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((data) => { if (data.message) { onModal('failed', data.message); @@ -254,7 +234,9 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('HEAD', `/get/${containerItem.containerId}/${objectItem.address.objectId}`).then((e) => { + api('HEAD', `/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + "Authorization": `Bearer ${walletData.tokens.object.bearer}`, + }).then((e) => { onModal('shareObjectLink', { type: e === 200 ? 'public' : 'private', containerId: containerItem.containerId, @@ -301,18 +283,12 @@ Tree.Folder = Folder; Tree.Branch = Branch; export default function TreeView({ - params, containerItem, walletData, onModal, containerIndex, onGetObjects, objects, - ContentTypeHeader, - AuthorizationHeader, - BearerOwnerIdHeader, - BearerSignatureHeader, - BearerSignatureKeyHeader, }) { return ( @@ -320,7 +296,6 @@ export default function TreeView({
{objectPath !== '/' && ( )} {Object.keys(objects).length === (index + 1) && objects['/'] && objects['/'].map((objectItem, objectIndex) => ( ))}
diff --git a/src/Getobject.js b/src/Getobject.js index d381cef..269bc8a 100644 --- a/src/Getobject.js +++ b/src/Getobject.js @@ -11,8 +11,6 @@ import api from './api'; const Getobject = ({ onModal, - ContentTypeHeader, - AuthorizationHeader, }) => { const [searchParams] = useSearchParams(); const [objectData, setObjectData] = useState(null); @@ -26,10 +24,9 @@ const Getobject = ({ const payload = {}; if (token) { - payload[ContentTypeHeader] = "application/json"; - payload[AuthorizationHeader] = `Bearer ${token}`; + payload["Authorization"] = `Bearer ${token}`; } - api('GET', `/objects/${containerId}/${objectId}?fullBearer=true`, {}, payload).then((e) => { + api('HEAD', `/objects/${containerId}/by_id/${objectId}`, {}, payload).then((e) => { if (e.message) { onModal('failed', e.message); } else { @@ -43,10 +40,9 @@ const Getobject = ({ const payload = {}; if (params.token) { - payload[ContentTypeHeader] = "application/json"; - payload[AuthorizationHeader] = `Bearer ${params.token}`; + payload["Authorization"] = `Bearer ${params.token}`; } - api('GET', `/get/${params.containerId}/${params.objectId}`, {}, payload).then((data) => { + api('GET', `/objects/${params.containerId}/by_id/${params.objectId}`, {}, payload).then((data) => { if (data.message) { onModal('failed', data.message); } else { @@ -54,7 +50,7 @@ const Getobject = ({ document.body.appendChild(a); const url = window.URL.createObjectURL(data.res); a.href = url; - a.download = objectData['x-attribute-filename'] ? objectData['x-attribute-filename'] : params.objectId; + a.download = objectData.filename ? objectData.filename : params.objectId; a.target = '_blank'; a.click(); setTimeout(() => { @@ -98,12 +94,20 @@ const Getobject = ({
Attributes - {objectData ? objectData.attributes.map((attribute) => ( - - {`${attribute.key}: `} - {attribute.value} - - )) : '-'} + {objectData ? ( + <> + {Object.keys(objectData.attributes).map((attributeKey) => ( + + {`${attributeKey}: `} + {objectData.attributes[attributeKey]} + + ))} + + Content-Type: + {objectData.contentType} + + + ) : '-'}
Manage diff --git a/src/Profile.js b/src/Profile.js index d64f280..1d572f1 100644 --- a/src/Profile.js +++ b/src/Profile.js @@ -30,11 +30,6 @@ const Profile = ({ neolineN3, isLoadContainers, setLoadContainers, - ContentTypeHeader, - AuthorizationHeader, - BearerOwnerIdHeader, - BearerSignatureHeader, - BearerSignatureKeyHeader, onAuth, }) => { const [isLoading, setIsLoading] = useState(false); @@ -287,7 +282,6 @@ const Profile = ({ {containers.map((containerItem, index) => ( ))} diff --git a/src/api.js b/src/api.js index 57035fd..6bc8f34 100644 --- a/src/api.js +++ b/src/api.js @@ -5,9 +5,8 @@ async function serverRequest(method, url, params, headers) { method, headers, } - if (json['headers']['Content-Type'] === 'multipart/form-data') { + if (json['headers']['Content-Type']) { json['body'] = params; - delete json['headers']['Content-Type']; } else if (Object.keys(params).length > 0) { json['body'] = JSON.stringify(params); json['headers']['Content-Type'] = 'application/json'; @@ -30,10 +29,22 @@ export default function api(method, url, params = {}, headers = {}) { }); } else { let res = response; - if (method === 'GET' && url.indexOf(`/get/`) !== -1 && response.status === 200) { + if (method === 'GET' && url.indexOf(`/by_id/`) !== -1 && response.status === 200) { res = await response.blob(); const header = response.headers.get('Content-Type'); resolve({ header, res, status: response.status }); + } else if (method === 'HEAD' && url.indexOf(`/by_id/`) !== -1 && response.status === 200) { + const attributes = response.headers.get('x-attributes') ? JSON.parse(response.headers.get('x-attributes')) : {}; + const res = { + 'containerId': response.headers.get('x-container-Id'), + 'objectId': response.headers.get('x-object-id'), + 'ownerId': response.headers.get('x-owner-Id'), + 'filename': attributes['FileName'], + 'attributes': attributes, + 'contentType': response.headers.get('Content-Type'), + 'objectSize': response.headers.get('Content-Length') ? response.headers.get('Content-Length') : response.headers.get('x-neofs-payload-length'), + } + resolve(res); } else if (method === 'HEAD') { resolve(response.status); } else if (response.status === 413) {