How to save files into AWS using signedURLs and ReactJS? - javascript

I'm trying to attach images with regular text inputs into my form in order to submit to my MongoDB.
This is what my function to create a post looks like:
const [postData, setPostData] = useState({
text: '',
images: null,
postedto: auth && auth.user.data._id === userId ? null : userId
});
const { text, images, postedto } = postData;
const handleChange = name => e => {
setPostData({ ...postData, [name]: e.target.value, images: e.target.files });
};
const createPost = async e => {
e.preventDefault();
await addPost(postData, setUploadPercentage);
};
From there I move into my action addPost; on this function I call two API routes:
// #route POST api/v1/posts
// #description Add post
// #access Private
// #task DONE
export const addPost = (formData, setUploadPercentage) => async dispatch => {
try {
// ATTACH FILES
let fileKeys = [];
for(let file of formData.images) {
const uploadConfig = await axios.get(`${API}/api/v1/uploads/getS3url?type=${file.type}`);
await axios.put(uploadConfig.data.url, file, {
headers: {
'Content-Type': file.type
}
});
fileKeys.push(uploadConfig.data.key);
}
console.log(fileKeys);
// INSERT NEW BLOG
const config = {
headers: {
'Content-Type': 'multipart/form-data; application/json'
},
onUploadProgress: ProgressEvent => {
setUploadPercentage(
parseInt(Math.round(ProgressEvent.loaded * 100) / ProgressEvent.total)
);
// Clear percentage
setTimeout(() => setUploadPercentage(0), 10000);
}
};
formData.images = fileKeys;
const res = await axios.post(`${API}/api/v1/posts`, formData, config);
dispatch({
type: ADD_POST,
payload: res.data
});
dispatch(setAlert('Post Created', 'success'));
} catch (err) {
const errors = err.response && err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: POST_ERROR,
payload: { msg: err.response && err.response.statusText, status: err.response && err.response.status }
});
}
};
My getS3url function looks exactly like this:
exports.uploadFile = asyncHandler(async (req, res, next) => {
const { type } = req.query;
const fileExtension = type.substring(type.indexOf('/') + 1);
const key = `${process.env.WEBSITE_NAME}-${req.user._id}-${
req.user.email
}-${Date.now().toString()}.${fileExtension}`;
const params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: key,
ContentType: type
};
s3.getSignedUrl(`putObject`, params, (err, url) => {
if (err) {
return next(
new ErrorResponse(
`There was an error with the files being uploaded`,
500
)
);
}
return res.status(201).json({ success: true, key: url });
});
});
I would like to point out that every post might have more than one image file and the function should return a signedURL for each single file; let's say I upload two files, I then should have two URLS retrieved in order to attach them into my post.
I'm sure there's nothing wrong with the way I;m managing state to submit data because it always return what I expect when using on console.log(postData) , even the files are shown.
Now I'm assuming the problem resides on my action, especially the code before the /// INSERT NEW BLOG comment because when I console.log(fileKeys) nothing is returned, not even an error/undefined/null.....I mean just nothing!.
My uploadFile is working fine when used with a single file....well not really because yes, it returns an URL of the 'supposed' uploaded file but when I get into my AWS console/bucket, there's nothing..but thats for its own post.
What I need help with?
Well, I'm trying to upload one/multiple files into my AWS using signedURL to return them as strings and attach them into my post. Is there any problem with my action file?.
Thanks!!.

for my case, I have been looping through the images and generating signed URLs and returning them since s3 doesn't support the signed URL option for multiple files at once.

In the end I found my own solution, here it is:
export const addPost = (formData, images, setUploadPercentage) => async dispatch => {
try {
let fileKeys = [];
for(let i = 0; i < images.length; i++) {
/// STEP 3
const token = localStorage.getItem("xAuthToken");
api.defaults.headers.common["Authorization"] = `Bearer ${token}`
const uploadConfig = await api.get(`/uploads/getS3url?name=${images[i].name}&type=${images[i].type}&size=${images[i].size}`);
// STEP 1
delete api.defaults.headers.common['Authorization'];
await api.put(uploadConfig.data.postURL, images[i], {
headers: {
'Content-Type': images[i].type
}
});
fileKeys.push(uploadConfig.data.getURL);
}
// INSERT NEW BLOG
const config = {
onUploadProgress: ProgressEvent => {
setUploadPercentage(
parseInt(Math.round(ProgressEvent.loaded * 100) / ProgressEvent.total)
);
setTimeout(() => setUploadPercentage(0), 10000);
}
};
// STEP 2
const token = localStorage.getItem("xAuthToken");
api.defaults.headers.common["Authorization"] = `Bearer ${token}`
const res = await api.post(`/posts`, {...formData, images: fileKeys}, config);
dispatch({
type: ADD_POST,
payload: res.data
});
dispatch(setAlert('Post Created', 'success'));
} catch (err) {
const errors = err.response && err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: POST_ERROR,
payload: { msg: err.response && err.response.statusText, status: err.response && err.response.status }
});
}
};

Related

Empty results while fetching data from mongoDB nextjs getServerSideProps

I am trying to fetch data from my mongoDB with NextJS getServerSideProps. Adding data is working but when I use find it does not work.
Here is my model
import { Schema, model, models } from "mongoose";
const testSchema = new Schema({
name: String,
email: {
type: String,
required: true,
unique: true,
}
});
const Test = models.Test || model('Test', testSchema);
console.log(models);
export default Test;
This works so my connection is okay
const createTest = async (event) => {
event.preventDefault();
const name = event.target.name.value;
const email = event.target.email.value;
const res = await fetch('/api/test/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name,
email,
}),
});
const data = await res.json();
console.log('data: ', data);
};
But this does not work. It shows the 404 page even though there is data
export const getServerSideProps = async () => {
try {
await connectDB();
const tests = await Test.find();
console.log('FETCHED DOCUMENT');
return {
props: {
tests: JSON.parse(json.stringify(tests)),
}
}
} catch (error) {
console.log(JSON.stringify(error,null,2));
return {
notFound: true
}
}
}
Thank you in advance!

How to upload local files to IMGBB with base64 string with axios js

I've tried the imgbb-uploader npm package but I only got it to work with other image URLs and not local files.
axios
.post("https://api.imgbb.com/1/upload", {
image: BASE_64_STRING,
name: file.name,
key: process.env.MY_API_KEY,
})
.then((res) => console.log(res))
.catch((err) => console.log(err));```
What about this:
// fileinput is the file/index 0 from input-type-file eg: e.target.myfileinput.files[0]
const uploadImg = ( fileinput ) => {
const formData = new FormData();
formData.append( "image", fileinput ); // has to be named 'image'!
let apiresponse = axios.post( 'https://api.imgbb.com/1/upload?key=your-api-key', formData )
.then( res => { return res.data } )
.catch( error => { return null } )
return apiresponse;
}
//From graph ql perspective
const { createReadStream, filename } = await file;
const url = "<URL_TO_IMAGE_SERVER&key=<YOUR_API_KEY>";
const stream = createReadStream();
const form = new FormData();
form.append("image", stream, filename);
try {
const response = await axios.post(url, form, {
headers: { ...form.getHeaders() },
});
console.log({ response });
return { Location: response.data.display_url };
} catch (error) {
return { ...error };
}

Send data to Express backend

I'm having trouble sending data to the Backend. I want to send data f1 to QueryBackend.js but when I try to console.log(req.body.f1) it's always undefined but in Services.js get the value.
Toolbar.js
handlePrintLetter = async(fieldName, fieldValue) => {
const { formId, selectedRows, displayData, onNotification } = this.props;
const idSelected = selectedRows.data.map(d => displayData[d.dataIndex].id);
const res = await getBookmarkDocument(idSelected); // Send Data to Backend
if (res.success) {
onNotification({ mode: 'success', text: 'success' });
} else {
onNotification({ mode: 'error', text: fieldName + ' ' + fieldValue });
}
}
Service.js
export const getBookmarkDocument = async (f1) => {
console.log(f1) // get value from Toolbar.js
const token = localStorage.getItem('token');
return axios.get(API + 'doc/show', { f1 },
{
headers: {
Authorization: `Bearer ${token}`
}
})
.then((response) => response.data || [])
.catch((error) => {
ErrorAPI(error);
return [];
});
}
How to get data f1 in here?
QueryBackend.js
router.get('/show', async (req, res) => {
try {
console.log(req.body.f1) // undefined
const pool = await poolPromise;
const result = await pool.query('SELECT sid_ddocument_key FROM sid_ddocument WHERE sid_ddocument_key = $1', ['I WANNA PUT DATA 'f1' IN HERE']); // Put Data f1
res.status(200).json({
success: true,
data: result.rows
});
} catch (err) {
res.status(500).json({
success: false,
response: err.message
});
}
});
GET requests can't have bodies. Encode the data in the query string and read it with req.query
const f1 = 'example';
const API = 'http://example.com/';
const url = new URL(`${API}doc/show`);
url.searchParams.append("f1", f1);
console.log(url.toString());

Node Script wont stop after async await in a loop

const axios = require("axios");
const Parser = require("./utils/parser");
const WebStore = require("./models/webstore");
const mongoose = require("mongoose");
require("./db/connection");
require("dotenv").config();
const url = "";
const app_secret = process.env.APP_SECRET;
const buff = new Buffer(app_secret);
const base64 = buff.toString("base64");
axios
.get(url, {
headers: {
Accept: "application/json",
Authorization: `Basic ${base64}`,
},
params: {
from_date: "2020-02-19",
to_date: "2021-02-21",
},
})
.then(async (response) => {
const data = response.data.split("\n");
const events = [];
data.forEach((point) => {
try {
const dat = Parser.toDB(JSON.parse(Parser.parser(point)));
events.push(dat);
} catch (err) {}
});
events.forEach(async (event) => {
try {
const e = new WebStore(event);
await e.save();
console.log("saved");
} catch (err) {
console.log("fail");
}
});
})
.catch((err) => {
console.error(err);
});
So After the execution the script outputs saved multiple times but the script is not closed itself.
The data is stored in the database after the execution I have tried mongoose.disconnect() and I've also tried mongoose.connection.close(). How do I resolve this issue ?

Images and Videos are not uploading to server using axios while in debugging mode

I'm using react-native-image-crop-picker to get image from gallery and trying to upload it on the server using Axios.But its not uploading to the server and when I hit the api to upload it starts sending and never-ending and no response getting from server.But when I try to make its build and then try to upload then its uploaded successfully and gettting reponse from server.
Here is my code .
const handleProfilePic = () => {
const date = new Date();
const formData = new FormData();
formData.append('files', {
uri: image.path,
type: image.mime,
name: 'image_' + Math.floor(date.getTime() + date.getSeconds() / 2),
});
console.log(formData);
new Promise((rsl, rej) => {
setLoading(true);
updatePic(formData, user.auth, rsl, rej);
})
.then((res) => {
Snackbar.show({
text: res,
duration: Snackbar.LENGTH_SHORT,
});
setLoading(false);
})
.catch((errorData) => {
setLoading(false);
Snackbar.show({
text: errorData,
duration: Snackbar.LENGTH_SHORT,
});
});
};
//add pic code
export const updatePic = (data, token, rsl, rej) => {
return (dispatch) => {
axios(`${BASE_URL}/Authentication/addpicture`, {
method: 'post',
data,
headers: {
auth: token,
},
})
.then((res) => {
console.log(res);
if (res.data.status == true) {
rsl(res.data.message);
} else {
rej(res.data.message);
}
})
.catch((err) => {
console.log(err);
rej(err.message);
});
};
};
I've solved it by commenting this line
Open this dir 'android/app/src/debug/java/com/flatApp/ReactNativeFlipper.java'
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
#Override
public void apply(OkHttpClient.Builder builder) {
// builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});

Categories