「Cognitoユーザー認証によるS3 のAccess制御をAmplifyとReactとDropzoneを使って実装する。(その3)」の続きです。
npm start
します。Browseが起動して、Login画面が表示されます。画面中付近に、 Upload Fileを入力できるボタンが表示されます。
S3のBucketが空であることを確認しておきます。Management ConsoleからS3を開き、upload Bucketをクリックします。
Web Applicationに戻って、FileをUploadします。 「Browse」をクリックして、Fileを指定します。今回はTiff Fileのみ選択できるようにしてあるので、適当なTiff Fileを指定して、「開く」をクリックします。
指定したFileが表示されていることを確認して、「Upload File」をクリックします。Uploadできず、Errorが表示されます。Loginしていない状態では、FileのUploadが出来ないことを確認しました。
再度、S3のUpload Bucketが空であることを確認しておきます。
Loginして、同様にFileをUploadします。Fileは指定されたままなので、「Upload File」をクリックします。もちろん「Browse」をクリックして、Fileを再指定しても良いです。FileがUploadできました。
S3にFileがUploadされているか確認します。Management ConsoleからS3を開き、Upload Bucketをクリックします。Bucketの内容を表示している画面のままでしたら、更新のIconをクリックします。「protected」というFolderが作成されています。「protected」をクリックします。「ap-northeast-1:」で始まるFolderが作成されています。そのFolderをクリックします。「upload」というFolderが作成されています。「upload」をクリックします。UploadしたFileが見えます。今回は、AmplifyのStorageのLevelにProtectedを指定したので、上記のような階層にFileがUploadされます。Policyを使ってS3へのAccess制御を指定しましたが、Amplify StorageのLevelとPolicyを細かく指定することによって、User間でお互いにFileを見れるようにしたり、他のUserからは見れないようにしたりすることが可能です。
この方法ではUploadするFileを一つ一つ指定してUploadする必要があります。それでは不便なため、複数のFileを一気にUploadできるようにするためにDropZoneを使ってUploadするFileを指定できるようにします。まず、react-dropzoneをInstallします。cd upload
npm install -save react-dropzone
App.jsを編集してDropZoneからUpload Fileを指定するように変更します。
import React, { useState, useCallback, useMemo } from 'react';
import { useDropzone } from 'react-dropzone';
import Storage from "@aws-amplify/storage";
import { SetS3Config } from "./services";
import logo from './logo.svg';
import './App.css';
const baseStyle = {
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '20px',
borderWidth: 2,
borderRadius: 2,
borderColor: '#eeeeee',
borderStyle: 'dashed',
backgroundColor: '#fafafa',
color: '#bdbdbd',
outline: 'none',
transition: 'border .24s ease-in-out'
};
const activeStyle = {
borderColor: '#2196f3'
};
const acceptStyle = {
borderColor: '#00e676'
};
const rejectStyle = {
borderColor: '#ff1744'
};
function App(props) {
const [response, setResponse] = useState("");
const onDrop = useCallback(acceptedFiles => {
acceptedFiles.forEach(file => {
const reader = new FileReader();
reader.onload = () => {
const fileAsArrayBuffer = new Uint8Array(reader.result);
// do whatever you want with the file content
SetS3Config(process.env.REACT_APP_bucket_name, "protected");
Storage.put('upload/' + file.name, fileAsArrayBuffer, { contentType: file.type })
.then(result => {
console.log(result);
setResponse("File is uploaded!");
return true;
})
.catch(err => {
console.log(err);
setResponse(`File is not uploaded: ${err}`);
return true;
});
};
reader.onabort = () => {
console.log("Reading file was aborted");
setResponse("Reading file was aborted");
}
reader.onerror = () => {
console.log("Reading file has failed");
setResponse("Reading file has failed");
}
reader.readAsArrayBuffer(file);
});
}, []);
const {acceptedFiles, getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject} = useDropzone({onDrop, accept: 'image/tif, image/tiff'});
const files = acceptedFiles.map(file => (
<div align="center">
{file.path} - {file.size} bytes
</div>
));
const style = useMemo(() => ({
...baseStyle,
...(isDragActive ? activeStyle : {}),
...(isDragAccept ? acceptStyle : {}),
...(isDragReject ? rejectStyle : {})
}), [
isDragActive,
isDragAccept,
isDragReject
]);
if(props.authState === 'signedIn') {
return (
<div className="App">
<div {...getRootProps({style})}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
<div>
<h4>Files</h4>
<p>{files}</p>
</div>
{!!response && <div>{response}</div>}
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
} else if(props.authState === 'confirmSignUp') {
return (
<div className="Your account is not granted">
<header className="App-header">
Your account is not granted.
</header>
</div>
);
} else if(props.authState === 'signIn') {
return (
<div className="Welcome to the world">
<header className="App-header">
Welcome to the world.
</header>
</div>
);
} else {
return (
<div className="Login failed">
<header className="App-header">
Login failed.
</header>
</div>
);
}
}
export default App;
App.jsの編集が完了したら、npm start
します。 Browseが起動して、Login画面が表示されたら、Loginします。Loginすると、UploadするFileをDrag&Dropする領域が出来ています。Uploadする複数のFileをDrag&Dropします。Drag&Dropする領域をクリックして、File Browserから複数のFileを指定することもできます。Uploadが完了したら、Management ConsoleからS3を開き、UploadされたFileを確認します。
これで、 File Upload機能 の実装は完了です。
それでは、以前と同様にS3にDeployしてみましょう。
package.jsonにhomepageのentryが設定されているか確認します。cd upload
npm run build
aws s3 sync --exact-timestamps --delete --acl public-read
dirname bucketname
Management ConsoleからS3を開き、export.hacya.comのindex.htmlのURLを確認して、BrowserでそのURLを開きます。同様にTiff FileをUploadします。
Uploadできました。これで完了です。