Cognitoユーザー認証によるS3 のAccess制御をAmplifyとReactとDropzoneを使って実装する。(その4)

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-readdirname bucketname

Management ConsoleからS3を開き、export.hacya.comのindex.htmlのURLを確認して、BrowserでそのURLを開きます。同様にTiff FileをUploadします。

Uploadできました。これで完了です。

コメントを残す