Download GridFS files to disk - gridfs

I am requesting a file stored in MongoDB using GridFS, I am using gridfs-stream to read the file.
The server-side code:
exports.getFile = catchAsync(async (req, res, next) => {
gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
if (err)
return res.status(404).json({
status: 'error',
message: 'Something went wrong',
});
if (!file || file.length === 0) {
return res.status(404).json({
status: 'error',
message: 'File not found',
});
}
res.set({
'Content-Type': file.mimeType,
'Content-Disposition': 'attachment; filename=' + file.filename,
});
const readStream = gridfsBucket.openDownloadStream(file._id);
readStream.on('error', function (err) {
res.end();
});
readStream.pipe(res);
});
});
On the client-side, I am using Axios to request the file using the GET method:
Client-side code:
export const downloadFile = (filename) => {
return (dispatch) => {
api.get(`/api/v1/chats/file/${filename}`).then((res) => {
console.log(res.data);
});
};
};
The data I receive for an image looks like this:
enter image description here
Now all I want is to store the file on the disk.

Related

NextJS contact form with nodemailer throws Error 500 in Production

I have a simple contact form in a NextJS app and I wanted to switch from emailjs to something custom.
The contact form works perfect in development, but in production(cpanel, not vercel) I get a status 500 error(Internal Server Error). I've researched around and implemented async/await, promises, res.send status and everything I've found but I still can't find a way through.
Here's the post method:
const checkForm = async () => {
try {
const values = await form.validateFields();
fetch('/api/contact', {
method: 'POST',
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
});
} catch (error) {
console.log('Failed:', error);
}
};
And the /api/contact
import nodemailer from 'nodemailer';
export default async (req, res) => {
const { first_name, last_name, email, phone_number, subject, message } = req.body;
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
await new Promise((resolve, reject) => {
transporter.verify(function (error, success) {
if (error) {
console.log(error);
reject(error);
} else {
console.log('Server is ready to take our messages');
resolve(success);
}
});
});
const mailOption = {
from: `${email}`,
replyTo: `${email}`,
to: `${process.env.EMAIL}`,
subject: `${subject}`,
html: `<p><strong>Name:</strong> ${first_name + ' ' + last_name}</p>
<p><strong>Email:</strong> ${email}</p>
<p><strong>Phone number:</strong> ${phone_number}</p>
<p><strong>Message:</strong><br /> ${message}</p>
`
};
await new Promise((resolve, reject) => {
transporter.sendMail(mailOption, (err, info) => {
if (err) {
console.error(err);
reject(err);
res.send('error:' + JSON.stringify(err));
} else {
console.log(info);
resolve(info);
res.send('success');
}
});
});
res.status(200).json({ status: 'OK' });
};

Angular - Post request failing to download pdf file

I am trying to do a POST request to download a pdf file from the sever. The error I get is message: "Http failure during parsing". I'm not sure why it would work for a GET request but not for a POST request or I am missing something.
this.httpClient.post(url, {
responseType: 'blob' as 'json',
observe: 'response'
})
.pipe(take(1))
.subscribe((data:HttpResponse<Blob>) => {
const blob = new Blob([data.body], { type: 'application/pdf' });
saveAs(blob, 'test.pdf');
});
However if I do a GET request, it seems to work.
this.httpClient.get<Blob>(url,
{
observe: 'response',
responseType: (('blob') as any) as 'json'
})
.pipe(take(1))
.subscribe(
(response: HttpResponse<Blob>) => {
const blob = new Blob([response.body], { type: mediaType });
saveAs(blob, 'Report.pdf');
},
(error: any) => {
console.error(error);
}
);
Server
[HttpPost]
[Route("download/{id}")]
public IHttpActionResult DownloadPdf()
{
var buffer = _test.RenderDrawing();
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(buffer)
};
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"Test.pdf"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return ResponseMessage(result);
}
In you post request, you are defining types differently. try something like this:
this.httpClient.post(url, {
responseType: 'blob',
observe: 'response'
})
.pipe(take(1))
.subscribe((data:HttpResponse<Blob>) => {
const blob = new Blob([data.body], { type: 'application/pdf' });
saveAs(blob, 'test.pdf');
});

NzUploadModule with AngularFireStorage

I'm trying to upload a file with AngularFireStorage service. File is uploaded and I can get download URL, but I can't pass status(progress,downloadurl) to nz-upload component. Is there someone solves it? I think S3 way may look like similar.
uploadFile = (item: UploadXHRArgs) => {
console.log('call uploadFile');
console.log(item);
const file = item.file;
const filePath = `${this.authService.user.uid}/${file.uid}`;
const fileRef = this.storage.ref(filePath);
const task = this.storage.upload(filePath, file)
return task.snapshotChanges().pipe(
finalize(() => {
fileRef.getDownloadURL().subscribe(result => {
console.log(result);
});
})
)
.subscribe();
}
handleChange({ file, fileList }: UploadChangeParam): void {
console.log(file.status);
const status = file.status;
if (status !== 'uploading') {
console.log(file, fileList);
}
if (status === 'done') {
this.msg.success(`${file.name} file uploaded successfully.`);
} else if (status === 'error') {
this.msg.error(`${file.name} file upload failed.`);
}
}
In browser console
call uploadFile
Object { action: "", name: "file", headers: undefined, file: File, postFile: File, data: undefined, withCredentials: false, onProgress: onProgress(e), onSuccess: onSuccess(ret, xhr), onError: onError(xhr)
}
uploading
https://firebasestorage.googleapis.com/v0/b/xxxx.appspot.com/o/bc7Q7zMxCWdJW0FtHrWtC0y6Vle2%2Fmnjvjqua0z?alt=media&token=6a50e16d-2b42-43b3-907a-add7f7a9b8f6
On a page
Solved, thanks to https://github.com/ezhuo/ngx-alain/blob/master/src/app/#core/utils/image.compress.service.ts#L123
uploadFile = (item: UploadXHRArgs) => {
const file = item.file;
const filePath = `${this.authService.user.uid}/${file.uid}`;
const fileRef = this.storage.ref(filePath);
const task = this.storage.upload(filePath, file);
return task.snapshotChanges().pipe(
finalize(() => {
fileRef.getDownloadURL().subscribe(result => {
item.onSuccess(result, item.file, result);
});
})
)
.subscribe(
(result) => {
const event = { percent: 0};
event.percent = (result.bytesTransferred / result.totalBytes) * 100;
item.onProgress(event, item.file);
},
err => {
item.onError(err, item.file);
}
);
}
P.S. Still trying to understand item.onSuccess(result, item.file, result); but upload and preview and progress, works.

Observable from 2 promises

I think my solution is in this question but I can't get it to work Promise.all behavior with RxJS Observables?
I'm trying to return an observable on two promises via forkJoin.
One promise gets an ID from the server and another processes a file to generate a thumbnail.
export function createSceneFromFile(action$) {
return action$.ofType(CREATE_SCENE_FROM_FILE)
.mergeMap(({locationId,file}) =>
createSceneThumb(locationId,file)
.map((res,preview) => {
console.log(res,preview)
if (res.error) {
return { type: CREATE_SCENE_FAILED, payload: res.message }
} else {
return {type: CREATE_SCENE_SUCCESS, payload: {...res.payload,preview} }
}
})
.catch(err => { return { type: CREATE_SCENE_FAILED, message: err } })
)
}
function createSceneThumb(locationId,file){
const request = fetch(`${API_URL}/location/${locationId}/createscene/${file.name}/`, {
method: 'get',
credentials: 'include',
}).then(res => res.json())
const thumb = fileToScenePreview(file)
return Observable.forkJoin(request,thumb)
}
export function fileToScenePreview(file){
return new Promise((resolve,reject)=>{
getFileThumb(file).then((canvas)=> {
canvas.toBlob((blob) => {
blob.lastModifiedDate = new Date()
blob.name = 'scenepreview_' + file.name + '.png'
const uploader = new S3Upload({
getSignedUrl: getSignedUrl,
uploadRequestHeaders: {'x-amz-acl': 'public-read'},
contentType: 'image/png',
scrubFilename: (filename) => filename.replace(/[^\w\d_\-.]+/ig, ''),
contentDisposition: 'auto',
s3path: 'assets/',
onError:()=>reject,
onFinishS3Put: ()=>resolve(blob.name),
})
uploader.uploadFile(blob)
})
})
})
}
But i never get a response.
Is this the right way of going about it?

Ionic 3 File-Transport multipart/form-data

i am actually working on a mobile app in ionic v3 with angular5
The goal is to be able to take a picture or choose from existing ones and then upload it to the server. The first part is done, but i am struggling with the upload.
The api needs multipart/form-data which must consist of two requests. First with text part and second is the image.
Is there any solution for this?
This is what I have done for similar requirement
takePhoto() {
this.camera.getPicture({
quality: 100,
destinationType: this.camera.DestinationType.FILE_URI,
sourceType: this.camera.PictureSourceType.CAMERA,
encodingType: this.camera.EncodingType.PNG,
saveToPhotoAlbum: true
}).then(imageData => {
this.myPhoto = imageData;
this.uploadPhoto(imageData);
}, error => {
this.functions.showAlert("Error", JSON.stringify(error));
});
}
selectPhoto(): void {
this.camera.getPicture({
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
destinationType: this.camera.DestinationType.FILE_URI,
quality: 100,
encodingType: this.camera.EncodingType.PNG,
}).then(imageData => {
this.myPhoto = imageData;
this.uploadPhoto(imageData);
}, error => {
this.functions.showAlert("Error", JSON.stringify(error));
});
}
private uploadPhoto(imageFileUri: any): void {
this.file.resolveLocalFilesystemUrl(imageFileUri)
.then(entry => (<FileEntry>entry).file(file => this.readFile(file)))
.catch(err => console.log(err));
}
private readFile(file: any) {
const reader = new FileReader();
reader.onloadend = () => {
const formData = new FormData();
const imgBlob = new Blob([reader.result], { type: file.type });
formData.append('evaluationID', this.currentEvaluation.evaluationId);
formData.append('standardID', this.currentEvaluation.id);
formData.append('score', this.currentEvaluation.score);
formData.append('comment', this.currentEvaluation.comment);
formData.append('file', imgBlob, file.name);
this.saveStandard(formData);
};
reader.readAsArrayBuffer(file);
}
And here is code for provider
saveStandard(receivedStandardInfo:any){
return new Promise((resolve, reject) => {
this.http.post(apiSaveStandard,receivedStandardInfo)
.subscribe(res => {
resolve(res);
}, (err) => {
console.log(err);
reject(err);
});
}).catch(error => { console.log('caught', error.message); });
}

Resources