I am currently building a signup form with React, Redux, JavaScript, Node, Adonisjs. I'm attempting to upload profile images to my AWS s3 Bucket. At the moment I've got it so the file is appearing in the bucket. However when I try to click on the link provided by AWS s3 i get the following error. AWS ERROR IMAGE.
I have set my permissions to public and I have provided the correct credential keys. I'm stuck on how to solve this so any help would be greatly appreciated. Please see code below.
Below is my AWS Controller:
"use strict";
require("dotenv").config();
const aws = require("aws-sdk");
const fs = require("fs");
const Helpers = use("Helpers");
const Drive = use("Drive");
class awsController {
async upload({ request, response }) {
aws.config.update({
region: "ap-southeast-2", // AWS region
accessKeyId: process.env.S3_KEY,
secretAccessKey: process.env.S3_SECERT
});
const S3_BUCKET = process.env.S3_BUCKET;
const s3Bucket = new aws.S3({
region: "ap-southeast-2",
accessKeyId: process.env.S3_KEY,
secretAccessKey: process.env.S3_SECERT,
Bucket: process.env.S3_BUCKET
}); // Create a new instance of S3
const fileName = request.all().body.fileName;
console.log(fileName);
const fileType = request.all().body.fileType;
const params = {
Bucket: S3_BUCKET,
Key: fileName,
ContentType: fileType,
ACL: "public-read"
};
s3Bucket.putObject(params, function(err, data) {
if (err) {
response.send(err);
}
console.log(data);
const returnData = {
signedRequest: data,
url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
};
console.log(returnData);
response.send("Success");
});
}
}
module.exports = awsController;
** Below handles uploading of file **
import React, { Component } from "react";
import axiosAPI from "./../resorterAPI";
import axios from "axios";
class ImageUpload extends Component {
constructor(props) {
super(props);
this.state = {
success: false,
url: ""
};
}
handleChange = event => {};
handleUpload = event => {
let uploadedFile = this.uploadInput.files[0];
// Splits name of file
let fileParts = this.uploadInput.files[0].name.split(".");
let fileName = fileParts[0];
let fileType = fileParts[1];
let fullFileName = uploadedFile.name;
console.log("preparing upload");
axiosAPI
.post("/s3Upload", {
body: {
fileName:
Math.round(Math.random() * 1000 * 300000).toString() +
"_" +
uploadedFile.name,
fileType: fileType
}
})
.then(response => {
console.log("Success");
});
};
render() {
return (
<div>
<center>
<input
onChange={this.handleChange}
ref={ref => {
this.uploadInput = ref;
}}
type="file"
/>
<br />
<button onClick={this.handleUpload}> Upload </button>
</center>
</div>
);
}
}
export default ImageUpload;
**Below is where the image upload service is called **
import React from "react";
// Redux
import { Field, reduxForm } from "redux-form";
import { connect } from "react-redux";
import { getCountry } from "./../../redux/actions/getCountryAction.js";
import Store from "./../../redux/store.js";
// Services
import axiosAPI from "./../../api/resorterAPI";
import ImageUpload from "./../../api/services/ImageUpload";
// Calls a js file with all area codes matched to countries.
import phoneCodes from "./../../materials/PhoneCodes.json";
// Component Input
import {
renderField,
renderSelectField,
renderFileUploadField
} from "./../FormField/FormField.js";
// CSS
import styles from "./signupForm.module.css";
import classNames from "classnames";
function validate(values) {
let errors = {};
if (!values.specialisations) {
errors.firstName = "Required";
}
if (!values.resort) {
errors.lastName = "Required";
}
if (!values.yearsOfExperience) {
errors.email = "Required";
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = "Invalid Email";
}
if (!values.spokenLanguages) {
errors.password = "Required";
}
if (values.sport !== values.confirmPassword) {
errors.confirmPassword = "Passwords don't match";
}
return errors;
}
class SignupFormStepTwo extends React.Component {
constructor(props) {
super(props);
this.state = {
countries: [],
selectedCountry: [],
dialCodes: []
};
}
// Below gets the countries from axios call made in redux actions
async componentDidMount() {
const countries = await getCountry();
// The below maps through the json file and gets all the dial codes
const codes = phoneCodes.phoneCode.map(code => {
return code.dial_code;
});
return this.setState({ countries: countries, dialCodes: codes });
}
// Handles when someone changes the select fields
handleChange = event => {
const selectedCountry = event.target.value;
return this.setState({ selectedCountry: selectedCountry });
};
// uploadFile = (values, url = "") => {
// axiosAPI.post("/displayImageUpload", { ...values, imageURL: url}).then(response => {
// console.log("Success");
// })
// }
render() {
return (
<div>
<form onSubmit={this.props.handleSubmit}>
<div className={styles.signupContainer}>
<div className={styles.signupInputContainer}>
{/* <Field
name="displayImage"
component={renderFileUploadField}
type="text"
label="Display Image"
/> */}
<ImageUpload />
<div
className={classNames({
[styles.bioField]: true,
[styles.signupInputContainer]: true
})}
>
<Field
name="bio"
component={renderField}
type="text"
label="Bio"
placeholder="Introduce yourself - Where you're from, what your hobbies are, etc..."
/>
</div>
</div>
{/* Renders the select field */}
<div className={styles.signupInputContainer}>
<Field
name="specialisations"
component={renderSelectField}
type="select"
label="Specialisations"
placeholder="Specialisations"
options={this.state.countries}
onChange={this.handleChange}
multiple={false}
/>
<Field
name="resort"
component={renderSelectField}
options={this.state.dialCodes}
type="select"
label="Resort"
placeholder="Select the resorts you can work at"
/>
<Field
name="yearsOfExperience"
component={renderSelectField}
options={this.state.dialCodes}
type="select"
label="Years of Experience"
/>
<Field
name="spokenLanguages"
component={renderSelectField}
options={this.state.dialCodes}
type="select"
label="Spoken Languages"
/>
</div>
</div>
<div className={styles.signupButtonContainer}>
<button className={styles.signupButton} type="submit">
{" "}
Submit{" "}
</button>
</div>
</form>
</div>
);
}
}
// destroyOnUnmount - saves it in state
SignupFormStepTwo = reduxForm({
form: "signupStageTwo",
destroyOnUnmount: false,
validate
})(SignupFormStepTwo);
const mapStateToProps = state => {
return {
form: state.form
};
};
export default SignupFormStepTwo;
UPDATE: Solved the error thanks to Jarmod, I was actually not separating the file extension from the file name so it was uploading image.png.png.