# Upload files to AWS S3

This example shows you how to implement a smart action to upload image files to an AWS S3 bucket.\
\
Here we have a `companies` model that has two fields corresponding to files stored in an AWS S3 bucket:

* A certificate of incorporation
* A proof of identity

We implemented a smart action to upload the files for each company.&#x20;

![](/files/-MJ1G1Q0Vl4hUdsUUq0W)

## Requirements

* An admin backend running on forest-express-sequelize
* An AWS S3 bucket with access credentials
* The [aws-sdk](https://www.npmjs.com/package/aws-sdk) npm package
* The [bluebird](https://www.npmjs.com/package/bluebird) npm package
* The [parse-data-uri](https://www.npmjs.com/package/parse-data-uri) npm package

## How it works

### Directory: /models

This directory contains the `companies.js` file where the `companies` model is declared.&#x20;

{% tabs %}
{% tab title="companies.js" %}

```javascript
module.exports = (sequelize, DataTypes) => {
  const { Sequelize } = sequelize;
  const Companies = sequelize.define('companies', {
    name: {
      type: DataTypes.STRING,
    },
    industry: {
      type: DataTypes.STRING,
    },
    headquarter: {
      type: DataTypes.STRING,
    },
    status: {
      type: DataTypes.STRING,
    },
    description: {
      type: DataTypes.STRING,
    },
    createdAt: {
      type: DataTypes.DATE,
    },
    updatedAt: {
      type: DataTypes.DATE,
    },
    certificateOfIncorporationId: {
      type: DataTypes.UUID,
    },
    passportId: {
      type: DataTypes.UUID,
    },
  }, {
    tableName: 'companies',
    underscored: true,
    schema: process.env.DATABASE_SCHEMA,
  });

  return Companies;
};


```

{% endtab %}
{% endtabs %}

### Directory: /forest

This directory contains the `companies.js` file where the smart action `Upload Legal Docs` is declared.&#x20;

{% hint style="info" %}
You need to specify that the widget `file picker` is applicable to the input field used to upload the file.
{% endhint %}

{% code title="companies.js" %}

```javascript
const { collection } = require('forest-express-sequelize');

collection('companies', {
  actions: [
    {
      name: 'Upload Legal Docs',
      type: 'single',
      fields: [{
        field: 'Certificate of Incorporation',
        description: 'The legal document relating to the formation of a company or corporation.',
        type: 'File',
        isRequired: true,
      }, {
        field: 'Valid proof of ID',
        description: 'ID card or passport if the document has been issued in the EU, EFTA, or EEA / ID card or passport + resident permit or driving licence if the document has been issued outside the EU, EFTA, or EEA of the legal representative of your company',
        type: 'File',
        isRequired: true,
      }],
    },
  ],
  fields: [],
  segments: [],
});
```

{% endcode %}

### Directory: /services

This directory contains an `s3-helper.js` file where the methods to upload files to s3 is declared.

{% hint style="info" %}
You need to configure your AWS credentials inside your app to get access to your bucket. You can read more about it in the AWS documentation [here](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html).
{% endhint %}

```javascript
const P = require('bluebird');
const parseDataUri = require('parse-data-uri');
const AWS = require('aws-sdk');

function S3Helper() {
  this.upload = (rawData, filename) => new P((resolve, reject) => {
    // Create the S3 client.
    const s3Bucket = new AWS.S3({ params: { Bucket: process.env.S3_BUCKET } });
    const parsed = parseDataUri(rawData);

    const data = {
      Key: filename,
      Body: parsed.data,
      ContentDisposition: 'inline',
      ContentType: parsed.mimeType,
    };
    
    // Upload the image.
    s3Bucket.upload(data, (err, response) => {
      if (err) {
        return reject(err);
      }
      return resolve(response);
    });
  });
}

module.exports = S3Helper;
```

### Directory: /routes

This directory contains the `companies.js` file where the logic of the smart action is implemented.

{% code title="companies.js" %}

```javascript
const express = require('express');
const { PermissionMiddlewareCreator } = require('forest-express-sequelize');
const { companies } = require('../models');
const uuid = require('uuid/v4');
const S3Helper = require('../services/s3-helper');
const P = require('bluebird');


const router = express.Router();
const permissionMiddlewareCreator = new PermissionMiddlewareCreator('companies');

function uploadLegalDoc(companyId, doc, field) {
  const id = uuid();
  //upload the files using the helper
  return new S3Helper().upload(doc, `livedemo/legal/${id}`)
  //once the file is uploaded, update the relevant company field with the file id
    .then(() => companies.findByPk(companyId))
    .then((company) => {
      company[field] = id;
      return company.save();
    })
    .catch((e) => e);
}

router.post('/actions/upload-legal-docs', permissionMiddlewareCreator.smartAction(), (req, res) => {
  // Get the current company id
  const companyId = req.body.data.attributes.ids[0];

  // Get the values of the input fields entered by the admin user.
  const attrs = req.body.data.attributes.values;
  const certificateOfIncorporation = attrs['Certificate of Incorporation'];
  const passportId = attrs['Valid proof of ID'];

  P.all([
    uploadLegalDoc(companyId, certificateOfIncorporation, 'certificateOfIncorporationId'),
    uploadLegalDoc(companyId, passportId, 'passportId'),
  ])
    .then(() => {
      // Once the upload is finished, send a success message to the admin user in the UI.
      return res.send({ success: 'Legal documents are successfully uploaded.' });
    });
});

module.exports = router;
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestadmin.com/woodshop/how-tos/upload-files-to-s3.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
