Iron Router - Download and Redirect - meteor

I want a user to be able to click a button to download a file and be redirected to the same view / stay there. I'm being able to download the file but then I can't redirect from this server route. Any ideas on how can I accomplish this? Thanks!
Router.route('/analytics-download', {
name: "analytics-download",
where: "server",
action: function() {
try {
var filename = 'test.csv';
var headers = {
'Content-Type': 'text/csv',
'Content-Disposition': "attachment; filename=" + filename
};
this.response.writeHead(200, headers);
this.response.end(data);
// this.response.redirect('/analytics');
} catch (err) {
console.error(err);
}
}
});

Related

How to cutomise the url sent with Meteor Accounts.ui forgetpassword

I'm using accounts.ui for forget password
Accounts.forgotPassword({email: "test#test.com"}, function (e, r) {
if (e) {
console.log(e.reason);
} else {
// success
}
});
When I send the email for forget password I simply get below email
Can someone tell me how to simply change the url and send the token with the same token
I tried using below code but that didn't work
main.js(client)
Meteor.startup(() => {
Accounts.resetPassword.text = function(user, url) {
url = url.replace('#/', '/');
console.log("url ==== ", url)
return `Click this link to reset your password: ${url}`;
}
});
On the server side:
Accounts.emailTemplates.resetPassword.subject = function () {
return "Forgot your password?";
};
Accounts.emailTemplates.resetPassword.text = function (user, url) {
return "Click this link to reset your password:\n\n" + url;
};
Read: https://docs.meteor.com/api/passwords.html#Accounts-emailTemplates
To change the resetPassword url to a custom one you have to run below code on your server (inside of /server/main.js file).
Accounts.urls.resetPassword = function (token) {
return FlowRouter.url("/reset-password/:token/", { token });
};
In this case, I am using a FlowRouter to generate that URL but you could technically just return a template literal if you like.
If the above code is in the server main.js file and you run Accounts.forgotPassword() function on the frontend from a localhost, it would generate this link:
http://localhost:3000/reset-password/C9cGfgaLEgGXbCVYJcCLnDYiRi3XJpmt2irLOOaKe56

Angular 2 save Excel File

I'm trying to save a Excel File from my server to Client PC but it get all messed up.
When I request my file to the server the body of the request comes like this:
��ࡱ�>�� &����
I guess it's normal since excel is in binary format. I'm using file-saver plugin to save my files, at the moment I have the CSV and ASCII files working well.
This is my function to download:
downloadFile(filePath: string, name: string): void{
this.dataImportService.downloadFile(filePath)
.then(data => {
this.headers = data.headers;
let content = this.headers.get('content-type');
var blob = new Blob([data._body], { type: content });
importedSaveAs(blob, name);
});
}
Anything that I'm doing wrong or that I can improve?
Thank you in advance for the help.
EDIT: This is my server code:
[HttpGet]
public void downloadFile(string path)
{
try
{
string extension = Path.GetExtension(path);
string fileName = Path.GetFileName(path);
HttpResponse response = System.Web.HttpContext.Current.Response;
response.AppendHeader("Content-Disposition", "attachment; filename="+fileName);
response.AddHeader("Content-Type", Utils.MimeTypesConverter.GetMimeType(extension));
response.TransmitFile(path);
Response.End();
}
catch (Exception ex)
{
Response.Write(ex.Message);
return;
}
}
and my dataImportService.ts
downloadFile(filePath: string): any{
return this.http.get(SERVICE_URL + 'DataImport/downloadFile?path=' + filePath)
.toPromise()
.then(response =>{
return response;
})
.catch(this.handleError);
}
My http response from server:
You have to map the Response which includes HTTP Headers to the Blob on it's own.
So change code to an Observable wtih a map to transform response.
downloadFile(filePath: string): Observable<any> {
return this.http.get(
`${SERVICE_URL}DataImport/downloadFile?path=${filePath}`,
{responseType: ResponseContentType.Blob }
)
.map(res:Response => res.blob());
}

Ionic XMLHttpRequest FormData empty after append file

I'm trying to send a file with a post with ionic 2
In order to ask for the file, i use an invisible input type file
<input type="file" accept="image/*;" #file id="fileUpoload" style="display: none">
The button call the function in this way:
(click)="onFileUpoloadButtonPressed(file)"
And this is the function called:
onFileUpoloadButtonPressed(element){
document.getElementById("fileUpoload").onchange = function(e : any){
let file = {
name: e.srcElement.files[0].name,
file: e.srcElement.files[0],
};
//I get the id of the user since i have to perform an edit call to my api
this.storage.get("userLogged").then((value) => {
setTimeout(function(){
this.postChangeAvatar(this, parseInt(value.data.utenti_id), file,
function (ext, result){ //Success callback
console.log(result);
},
function(ext, error){ //Error callback
console.log(error);
alert(error);
}
)
}, 100)
})
}
element.click();
}
This is the postChangeAvatar function that perform the post request:
postChangeAvatar(ext, id, file, successCallback, errorCallback){
let formData : any = new FormData();
let xhr : any = new XMLHttpRequest();
console.log(id);
console.log(file); //File is successfully get
formData.append('user_photo', file.file, file.name);
for (var pair of formData.entries()) { //This is showing nothing
console.log(pair[0]+ ', ' + pair[1]);
}
xhr.onreadystatechange = () => {
if (xhr.readyState == 4){
if (xhr.status == 200){
successCallback(ext, xhr.response);
}
else {
errorCallback(ext, xhr.response);
}
}
}
xhr.open('POST', "http://xxxxxxxxxx/api/edit/utenti/" + id, true);
xhr.send(formData);
}
The post is performed but the formData remains empty after append the file, trying to print the formdata with the for each doesn't show anything, so the only thing wrong is the formData being empty when post is performed
As you can see i tried to encapsulate the entire request in a setTimeout to be sure the file is obtained, the file is in there but is not appendend in the formData
From the server i can see the body of the request empty
I tried this method in another project and in there was successfully working so i'm a bit surprised seeing this not working
If i'm not able to get this working maybe there's another way to post selected files with ionic 2?
Here is working piece of code (base64 file upload). Try setting header. Add enctype to Access-Control-Expose-Headers to prevent CORS.
insertPost(data): Observable<any> {
let headers = new Headers({ "enctype": "multipart/form-data" });
data.userId = this.globalProvider.userId;
var form_data = new FormData();
for (var key in data) {
form_data.append(key, data[key]);
}
return this.http.post(`${baseURL}insertPost`, form_data, { headers: headers })
.map((response: Response) => {
return response.json();
})
.catch(this.handleError);
}

Meteor slingshot file upload to Google Cloud Storage internal server error

I am trying to upload files using edgee:slingshot, but I have several errors. I have did everything as described in github page. This is my settings on server:
Slingshot.GoogleCloud.directiveDefault.GoogleSecretKey = Assets.getText('google-cloud-service-key.pem');
Slingshot.createDirective("myFileUploads", Slingshot.GoogleCloud, {
bucket: 'dossum-app',
GoogleAccessId: "GOOGXXXX",
GoogleSecretKey: "qZEsLZ/NiXXXXXXXXXXXXUW8NVjSvRb8SgdxXXXXX2",
acl: 'bucket-owner-full-control',
authorize: function() {
if (!this.userId) {
var message = 'Please login before posting file';
throw new Meteor.Error('Login Required', message);
}
return true;
},
key: function(file) {
var user = Meteor.users.findOne(this.userId);
return user.username + '/' + file.name;
}
});
And this is cors.json:
[{"origin": ["http://localhost:3000", "http://qnekt.zehinz.com"], "responseHeader": ["Origin", "Accept", "X-Requested-With", "Authorization", "Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token"], "method": ["GET", "HEAD", "DELETE", "PUT", "POST", "HEAD"], "maxAgeSeconds": 3600}]
If I run with above configuration I get this error without any details: {error: 500, reason: "Internal server error"....
I have tried to comment this line: //GoogleSecretKey:"qZEsLZ/NiEkXo641XHIUW8NVjSvRb8SgdxIyYcV2"
This time I receive this error:
{error: "Forbidden - 403", reason: "Failed to upload file to cloud storage", details: undefined ...
Can anyone please guide me?
Where should I get GoogleAccessId if I am using .pem file instead of GoogleSecretKey?
What should be the cors.json file for file uploading and public reading?
I had troubles with edgee:slingshot and Google Cloud Storage. But this settings now work for me:
//server
Slingshot.GoogleCloud.directiveDefault.GoogleSecretKey = Assets.getText('google-cloud-service-key.pem');
Slingshot.createDirective('avatarUploader', Slingshot.GoogleCloud, {
bucket: 'my_bucket',
GoogleAccessId: 'xxxxxxxxxxxxxx#developer.gserviceaccount.com',
acl: 'public-read',
authorize: function() {
if (!this.userId) {
var message = 'Please login before posting file';
throw new Meteor.Error('Login Required', message);
}
return true;
},
key: function(file) {
var user = Meteor.users.findOne(this.userId);
var ext = file.type.split('/')[1];
return user.username + '/' + randomString(20) + '.' + ext;
}
});
//CORS settings
[
{
"origin": ["*"],
"responseHeader": ["*"],
"method": ["GET", "POST", "PUT", "HEAD"],
"maxAgeSeconds": 3000
}
]
For details look here.

Basic static file server in NodeJS

I'm trying to create a static file server in nodejs more as an exercise to understand node than as a perfect server. I'm well aware of projects like Connect and node-static and fully intend to use those libraries for more production-ready code, but I also like to understand the basics of what I'm working with. With that in mind, I've coded up a small server.js:
var http = require('http'),
url = require('url'),
path = require('path'),
fs = require('fs');
var mimeTypes = {
"html": "text/html",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"png": "image/png",
"js": "text/javascript",
"css": "text/css"};
http.createServer(function(req, res) {
var uri = url.parse(req.url).pathname;
var filename = path.join(process.cwd(), uri);
path.exists(filename, function(exists) {
if(!exists) {
console.log("not exists: " + filename);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('404 Not Found\n');
res.end();
}
var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
res.writeHead(200, mimeType);
var fileStream = fs.createReadStream(filename);
fileStream.pipe(res);
}); //end path.exists
}).listen(1337);
My question is twofold
Is this the "right" way to go about creating and streaming basic html etc in node or is there a better/more elegant/more robust method ?
Is the .pipe() in node basically just doing the following?
.
var fileStream = fs.createReadStream(filename);
fileStream.on('data', function (data) {
res.write(data);
});
fileStream.on('end', function() {
res.end();
});
Thanks everyone!
Less is more
Just go command prompt first on your project and use
$ npm install express
Then write your app.js code like so:
var express = require('express'),
app = express(),
port = process.env.PORT || 4000;
app.use(express.static(__dirname + '/public'));
app.listen(port);
You would then create a "public" folder where you place your files. I tried it the harder way first but you have to worry about mime types which is just having to map stuff which is time consuming and then worry about response types, etc. etc. etc.... no thank you.
Your basic server looks good, except:
There is a return statement missing.
res.write('404 Not Found\n');
res.end();
return; // <- Don't forget to return here !!
And:
res.writeHead(200, mimeType);
should be:
res.writeHead(200, {'Content-Type':mimeType});
Yes pipe() does basically that, it also pauses/resumes the source stream (in case the receiver is slower).
Here is the source code of the pipe() function: https://github.com/joyent/node/blob/master/lib/stream.js
I like understanding what's going on under the hood as well.
I noticed a few things in your code that you probably want to clean up:
It crashes when filename points to a directory, because exists is true and it tries to read a file stream. I used fs.lstatSync to determine directory existence.
It isn't using the HTTP response codes correctly (200, 404, etc)
While MimeType is being determined (from the file extension), it isn't being set correctly in res.writeHead (as stewe pointed out)
To handle special characters, you probably want to unescape the uri
It blindly follows symlinks (could be a security concern)
Given this, some of the apache options (FollowSymLinks, ShowIndexes, etc) start to make more sense. I've update the code for your simple file server as follows:
var http = require('http'),
url = require('url'),
path = require('path'),
fs = require('fs');
var mimeTypes = {
"html": "text/html",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"png": "image/png",
"js": "text/javascript",
"css": "text/css"};
http.createServer(function(req, res) {
var uri = url.parse(req.url).pathname;
var filename = path.join(process.cwd(), unescape(uri));
var stats;
try {
stats = fs.lstatSync(filename); // throws if path doesn't exist
} catch (e) {
res.writeHead(404, {'Content-Type': 'text/plain'});
res.write('404 Not Found\n');
res.end();
return;
}
if (stats.isFile()) {
// path exists, is a file
var mimeType = mimeTypes[path.extname(filename).split(".").reverse()[0]];
res.writeHead(200, {'Content-Type': mimeType} );
var fileStream = fs.createReadStream(filename);
fileStream.pipe(res);
} else if (stats.isDirectory()) {
// path exists, is a directory
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Index of '+uri+'\n');
res.write('TODO, show index?\n');
res.end();
} else {
// Symbolic link, other?
// TODO: follow symlinks? security?
res.writeHead(500, {'Content-Type': 'text/plain'});
res.write('500 Internal server error\n');
res.end();
}
}).listen(1337);
var http = require('http')
var fs = require('fs')
var server = http.createServer(function (req, res) {
res.writeHead(200, { 'content-type': 'text/plain' })
fs.createReadStream(process.argv[3]).pipe(res)
})
server.listen(Number(process.argv[2]))
How about this pattern, which avoids checking separately that the file exists
var fileStream = fs.createReadStream(filename);
fileStream.on('error', function (error) {
response.writeHead(404, { "Content-Type": "text/plain"});
response.end("file not found");
});
fileStream.on('open', function() {
var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
response.writeHead(200, {'Content-Type': mimeType});
});
fileStream.on('end', function() {
console.log('sent file ' + filename);
});
fileStream.pipe(response);
I made a httpServer function with extra features for general usage based on #Jeff Ward answer
custtom dir
index.html returns if req === dir
Usage:
httpServer(dir).listen(port);
https://github.com/kenokabe/ConciseStaticHttpServer
Thanks.
the st module makes serving static files easy. Here is an extract of README.md:
var mount = st({ path: __dirname + '/static', url: '/static' })
http.createServer(function(req, res) {
var stHandled = mount(req, res);
if (stHandled)
return
else
res.end('this is not a static file')
}).listen(1338)
#JasonSebring answer pointed me in the right direction, however his code is outdated. Here is how you do it with the newest connect version.
var connect = require('connect'),
serveStatic = require('serve-static'),
serveIndex = require('serve-index');
var app = connect()
.use(serveStatic('public'))
.use(serveIndex('public', {'icons': true, 'view': 'details'}))
.listen(3000);
In connect GitHub Repository there are other middlewares you can use.

Resources