I am working with digital ocean spaces and I have uploaded the images on it in a temporary folder. Now I want to move that image from temporary folder to permanent folder. I have searched the things from all over but got nothing much satisfying. Is it possible to do so ?
and if yes please help me with the javascript code.
First I generated the signed url and with the help of that signed url I uploaded the image on digitalocean spaces. Following is the code for generating signed url and uploading images.
const getSignedUrl = async () => {
const body = {
fileName: 'temp/' + file.name,
fileType: file.type,
}
const response = await fetch(`${API_URL}/presigned_url`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
})
const { signedUrl } = await response.json()
return signedUrl
}
const uploadFile = async signedUrl => {
const res = await fetch(signedUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type,
'x-amz-acl': 'public-read',
}
})
return res
}
please help me how can I move my image from temporary folder to permanent folder.
So finally after searching I got the answer,
From the front end side I call an API to copy my image
const copyFile = async (file) => {
try {
const body = {
fileName: file.name
}
const res = await fetch(`${API_URL}/copy_file`, {
method: 'PUT',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
})
return res
} catch (error) {
console.log(error);
}
}
And in the backend side the API I made is
app.put('/copy_file', (req, res) => {
const fileName = req.body.fileName
console.log("body", fileName);
const params = {
Bucket: config.spaces.spaceName,
CopySource: `/bucketName/temp/${fileName}`,
Key: `original/${fileName}`,
}
spaces.copyObject(params, function (err, data) {
if (err) {
console.log("Error", err)
// console.log(err, err.stack); // an error occurred
} else {
res.json({ data })
}
});
});
This will copy you image in original folder
Related
I am trying to upload a file to an API using multipart/form-data.
I am able to successfully do this using insomnia as follows:
Headers are set to Content-Type multipart/form-data and the basic auth is also set.
When I try to replicate this in my code I receive a 400 error.
Here is what I have at the moment:
const URL = 'https://api.app.uploadplace.com/v1/';
const token = 'randomkey';
async function readFile(path: string) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', function (err, data) {
if (err) {
reject(err);
}
resolve(data);
});
});
}
export const Upload = async (path: string) => {
const FormData = require('form-data');
const form = new FormData();
let file = await readFile(path);
form.append('file', file);
const config = {
headers: {
'content-type': 'multipart/form-data'
},
auth: {
username: token,
password: ''
}
}
await axios.post(URL, form, config).then(() => {
console.log('success')
}).catch(err => {
console.log(err);
})
};
The problem is that you are appending the file contents as a string to your form data.
Instead, append the file readable stream...
form.append("file", fs.createReadStream(path));
const config = {
headers: form.getHeaders() // this includes correct mime boundary tokens
auth: {
username: token,
password: ''
}
}
See https://github.com/axios/axios#form-data
I would like to upload a file in vuejs to my nodejs server. However, I can't receive my file in the backend. Someone could help me. I have tried several things but I still can't get it. If anyone can help me I would be very grateful :-)
VueJS Upload Page Code
<input id="input-file" name="input-file" type="file" ref="file" #change="newFile($event)"/>
const formData = new FormData();
formData.append("file", document.getElementById("input-file"))
const createUserResponse = await RequestManager.executePostRequest("/users/upload", formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
RequestManager executePostRequest Function
static async executePostRequest(url: string, params: any, specialConfig?: AxiosRequestConfig) {
const postToken = Utils.buildHmacSha256Signature(params);
let headers: AxiosRequestHeaders = {
"x-access-token": config.server.backendAccessToken,
}
if (RequestManager.token) {
headers = {
"x-access-token": config.server.backendAccessToken,
"x-token-data": RequestManager.token,
}
}
if (specialConfig && specialConfig.headers) {
headers = Utils.mergeObjects(headers, specialConfig.headers) as AxiosRequestHeaders;
}
const instance = axios.create({
baseURL: config.server.host,
headers: headers
});
console.log(headers);
const paramsPost = {
data: params,
token: postToken
}
return new Promise<any>((resolve, reject) => {
instance
.post(url, paramsPost)
.then(response => {
resolve(response.data);
})
.catch(error => {
reject(error);
});
});
}
Backend NodeJS
UserRouter.get("/upload", (req, res) => {
console.log(req.files);
res.send("ok");
});
The goal is to have users enter in some information into a form and spit that out into a PDF. I'm using JSPDF to parse and create the PDF. I've successfully gotten my code to make a printable PDF, but in an effort to not have paper floating around the office, I made a cloud function to instead email that PDF to the customer.
Here is my code on the front end. maildoc is the pdf that I've made, it hasn't been printed or anything. So it only exists in memory.
mailDoc = mailDoc.output('datauri');
mailFunction += "&?data=" + mailDoc;
//axios request to the cloud function
axios.get(mailFunction).then( function (response) {
console.log(response);
}).catch(function (error) {
console.log(error)
})
And here is my code on the cloud function
exports.sendMail = functions.https.onRequest((req, res) => {
cors(req, res, () => {
// getting dest email by query string
//?dest= DestinationEmail
const dest = req.query.dest;
const data = req.query.data;
const mailOptions = {
from: 'whatever <whatever#hoobashaka.com>',
to: dest,
subject: "You're Equipment Return to HBCI", // email subject
attachments :[
{
filename: 'return.pdf',
contentType: 'application/pdf',
path: data,
}
],
};
return transporter.sendMail(mailOptions, (erro, info) => {
if(erro){
return res.send(erro.toString());
}
return res.send('Sended');
});
});
If I try and send the data via URI, I get a 413 error, probably because that URI is enormous. But I can't think of another way of sending that generated PDF to the function.
On your client, instead of uploading the file as a datauri, I'd instead use POST and send the PDF inside the request body (just as if you had submitted a file using a form).
mailDocBlob = mailDoc.output('blob');
const data = new FormData();
data.set('dest', someEmail);
data.append('file', mailDocBlob, 'return.pdf');
axios({
method: 'post',
url: 'https://your-cloud-function.here/sendMail',
data: data,
headers: {
'Content-Type': `multipart/form-data; boundary=${data._boundary}`,
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
On the server you would handle the multipart form data using the busboy package.
const BusBoy = require('busboy');
exports.sendMail = functions.https.onRequest((req, res) => {
cors(req, res, (err) => {
if (err) {
// CORS failed. Abort.
console.log("CORS failed/rejected");
res.sendStatus(403); // 403 FORBIDDEN
return;
}
if (req.method !== 'POST') {
res.set('Allow', 'POST, OPTIONS').sendStatus(405); // 405 METHOD_NOT_ALLOWED
return;
}
let busboy = new BusBoy({headers: req.headers, limits: {files: 1}}); // limited to only a single file
const mailOptions = {
from: 'whatever <whatever#hoobashaka.com>',
to: dest,
subject: "Your Equipment Return to HBCI", // email subject - fixed typo
attachments: []
};
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
// add new file attachment
mailOptions.attachments.push({
filename: 'return.pdf',
contentType: 'application/pdf',
content: file, // file is a stream
});
})
.on('finish', () => {
if (mailOptions.attachments.length == 0) {
// not enough attachments
res.status(400).send('Error: not enough attachments');
return;
}
return transporter.sendMail(mailOptions, (erro, info) => {
if (erro) {
return res.status(500).send('Error: ' + erro.toString());
}
return res.send('Sent');
})
})
.on('error', (err) => {
console.error(err);
res.status(500).send('Error: ' + err.code);
});
req.pipe(busboy);
});
Get all contacts from phonebook and upload to server but got following error.
While append image in request body FormData
Tried code
pass file url contact thumbnailPath
const path = con.thumbnailPath
body.append('image', {
uri: path,
type: 'image/jpeg',
name: 'photo.jpg',
type: 'multipart/form-data'
})
Tried code
pass file url contact thumbnailPath without "file://"
const path = con.thumbnailPath.replace('file://', '')
body.append('image', {
uri: path,
type: 'image/jpeg',
name: 'photo.jpg',
type: 'multipart/form-data'
})
Tried code
check file exist on path or not with using react-native-fs
if (con.thumbnailPath != '') {
let isExist = RNFS.exists(con.thumbnailPath)
if (isExist) {
const path = con.thumbnailPath.replace('file://', '')
console.log("Exist", path)
body.append('image', {
uri: path,
type: 'image/jpeg',
name: 'photo.jpg',
type: 'multipart/form-data'
})
}
}
Request
fetch(url, {
method: 'POST',
headers: {
'Authorization': token,
'token': token
},
body: params
})
.then((res) => res.json())
.then((json) => {
console.log("RESPONSE:- ", json)
if (json.response[0].status == 'false') {
let msg = json.response[0].response_msg
callback(new Error(msg), json.response[0])
}
else {
callback(null, json.response[0])
}
})
.catch((err) => {
console.log(err)
callback(err, null)
})
The issues comes from react-native#0.63.2's internal bug.
A quick solution is to revert this commit: https://github.com/facebook/react-native/commit/31980094107ed37f8de70972dbcc319cc9a26339#diff-9a034658197479288c4d346a0eb4d98c
After manually revert this commit in node_modules, recompile the app and the image uploading will be working without any issues.
Replace the function loadImageForURL in /Libraries/Image/RCTLocalAssetImageLoader.mm with the following:
- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
__block auto cancelled = std::make_shared<std::atomic<bool>>(false);
RCTExecuteOnMainQueue(^{
if (cancelled->load()) {
return;
}
UIImage *image = RCTImageFromLocalAssetURL(imageURL);
if (image) {
if (progressHandler) {
progressHandler(1, 1);
}
completionHandler(nil, image);
} else {
NSString *message = [NSString stringWithFormat:#"Could not find image %#", imageURL];
RCTLogWarn(#"%#", message);
completionHandler(RCTErrorWithMessage(message), nil);
}
});
return ^{
cancelled->store(true);
};
}
This problem is fixed in 0.63.3 ✅
**For IOS** in
node_modules/react-native/Libraries/Image/RCTLocalAssetImageLoader.mm file
**Replace Below**
- -(RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
UIImage *image = RCTImageFromLocalAssetURL(imageURL);
if (image) {
if (progressHandler) {
progressHandler(1, 1);
}
completionHandler(nil, image);
} else {
NSString *message = [NSString stringWithFormat:#"Could not find image %#", imageURL];
RCTLogWarn(#"%#", message);
completionHandler(RCTErrorWithMessage(message), nil);
}
return nil;
}
**With**
- -(RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
__block auto cancelled = std::make_shared<std::atomic<bool>>(false);
RCTExecuteOnMainQueue(^{
if (cancelled->load()) {
return;
}
UIImage *image = RCTImageFromLocalAssetURL(imageURL);
if (image) {
if (progressHandler) {
progressHandler(1, 1);
}
completionHandler(nil, image);
} else {
NSString *message = [NSString stringWithFormat:#"Could not find image %#", imageURL];
RCTLogWarn(#"%#", message);
completionHandler(RCTErrorWithMessage(message), nil);
}
});
return ^{
cancelled->store(true);
};
}
This..
Like and Love , if it work
I have the same issue which perfectly reproducible on one of the iPhone 7 on my react-native project. It's strange but another iPhone 7's works perfectly as well as all Android devices.
My code:
formdata.append("file", {uri: photo.uri, name: name_img, type: 'image/jpeg' });
axios({
url: `${API}${'/upload'}`,
method: 'post',
headers: {
'Authorization': 'Basic ' + auth_token,
'Content-Type':'application/x-www-form-urlencoded'
},
data: formdata
}).then(response => this.saveRoute())
.catch(err => {
this.props.errorMessage({message: err})
}
})
Few things that I investigate:
I was not able to catch it in debug mode (seams smth wrong in async calls?)
I was not able to catch it with try-catch statement but seams it happened in Axios call.
So, I tried to play with Timeout and was able to make it totally unreproducible with 300ms timeout before Axios call.
formdata.append("file", {uri: photo.uri, name: name_img, type: 'image/jpeg' });
setTimeout(() =>
axios({
url: `${API}${'/upload'}`,
method: 'post',
headers: {
'Authorization': 'Basic ' + auth_token,
'Content-Type':'application/x-www-form-urlencoded'
},
data: formdata
}).then(response => this.saveRoute())
.catch(err => {
this.props.errorMessage({message: err})
}
})
, 300);
I know that it's a workaround but may help others to understand the issue for more deep research.
I temporary fixed using rn-fetch-blob, but the issue is present in 0.63.2 version and I didn't want to patch node_modules react-native images library.
To send file, you have to create a FormData and append your file into it. See EX: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Uploading_a_file
I found solution. Just put delay when you post request.
let options = {}
options.headers = headers
options.method = 'POST'
let url = {SERVER_URL}
options.body = new FormData();
for (let key in data) {
options.body.append(key, data[key]);
}
setTimeout(() => {
fetch(url, options)
.then((response) => response.json())
.then((responseJson) => {
resolve(responseJson);
})
.catch((error) => {
let errParam = {}
errParam.errMsg = error.toString()
console.log(errParam)
resolve(errParam);
})
}, 1000);
Error fixed when updating React Native to version 0.63.3
When a GET(https://graph.microsoft.com/v1.0/users/ {{user_id}} /photo/$value) request is made, the response data will be written with the same characters as image
.
After converting to base64, I tried blob format but the picture does not appear.
router.js
router.get('/photo/:id',function (req,res) {
auth.getAccessToken().then(function (token){
let userId = req.params.id;
graph.getUserPhotoData(token, userId).then(function (result) {
res.json(result);
}).catch(function (e) { console.log(e) })
});
});
graph.js
function getUserPhoto(token, userId){
return axios({
method : 'get',
url : 'https://graph.microsoft.com/v1.0/users/'+{{user_id}}+'/photo/$value',
headers: {
'Authorization':token,
// 'Content-Type': 'image/jpeg',
},
responseType : 'blob'
})
}
async function getUserPhotoData(token,userId) {
try{
let userPhoto = getUserPhoto(token,userId);
let p = userPhoto.data;
// let photo = new Buffer(userPhoto.data).toString('base64');
return p; //...013O✿\u0011�e����|��>�4+�y��\u0017�"Y...
}catch (e) { console.log(e);}
}
index.js
$.get('/photo/'+userId, function(response) {
let binaryData = [];
binaryData.push(response);
const blobUrl = window.URL.createObjectURL(new Blob(binaryData, {type: "image/jpeg"}));
document.getElementById('user-img').setAttribute("src", blobUrl );
});
UPDATE: new Buffer is deprected. Please use
<img src={'data:image/jpeg;base64,' + Buffer.from(response.data, 'binary').toString('base64')}
Original answer
it works for me
const graphEndpoint = "https://graph.microsoft.com/v1.0/me/photo/$value";
const response = await axios(graphEndpoint, { headers: { Authorization: `Bearer ${token}` }, responseType: 'arraybuffer' });
const avatar = new Buffer(response.data, 'binary').toString('base64');
Finally found a solution to this! The previous answers didn't quite work for me. What I found that worked was:
const { data: photoValue} = await axios.request({
method: 'GET',
{ headers: { Authorization: `Bearer ${token}` },
responseType: 'blob',
url: 'https://graph.microsoft.com/v1.0/me/photo/$value',
});
const blobUrl = window.URL.createObjectURL(photoValue);
and then displaying it with <img src={blobUrl} />. This is the shortest answer in my opinion, and relies on the responseType: 'blob' being given.
I solved this problem.
router.js
const request = require('request');
router.get('/photo/:id',function (req,res) {
auth.getAccessToken().then(function (token){
let userId = req.params.id;
// graph.getUserPhotoData(token, userId).then(function (result) {
// console.log(result);
// res.json(result);
// }).catch(function (e) { console.log(e) })
request({ uri: 'https://graph.microsoft.com/beta/users/'+userId+'/photo/$value', method: "GET", headers:{'Authorization' : 'Bearer' + token}, encoding: null},
function(error, response, body) {
let data = "data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString('base64');
res.send(data); //data:image/jpeg;base64,/9j/4AAQSkZJRg...
});
});
});
index.js
$.get('/photo/'+ userId, function(response) {
document.getElementById('user-img').setAttribute("src", response);
});
'graph.js' is not needed.
reference :
Node.js get image from web and encode with base64