How to Facebook Connect on server side via Ajax using Node, Express and Connect-auth - ajax

I've got a piece of code that look like this.
app.get('/auth/facebook', function( request, response ) {
if( request.session.user ){
response.render( 'index.jade' );
} else {
request.authenticate(['facebook'], function(error, authenticated) {
if( authenticated ) {
request.session.user = request.getAuthDetails().user;
response.writeHead(303, { 'Location': "/auth/facebook" });
}
});
}
});
If there is a user in session it will render the page, if not it will get a user from Facebook and store that in a session variable and reload the page... and render it. It works perfectly fine. But I want to trigger that piece of code via AJAX and do something like this:
app.get('/auth/facebook', function( request, response ) {
response.contentType('application/json');
if( request.session.user ){
response.send(JSON.stringify({'authenticated':true}));
} else {
request.authenticate(['facebook'], function(error, authenticated) {
if( authenticated ) {
request.session.user = request.getAuthDetails().user;
response.writeHead(303, { 'Location': "/auth/facebook" });
} else {
response.send(JSON.stringify({'authenticated':false}));
}
});
}
});
But that doesn't work. It says "Can't use mutable header APIs after sent" and puts it self in an endless loop saying "Can't render headers after they are sent to the client." over and over again.
Am I going about this the wrong way? I want my server code to connect with Facebook without the need of a page reload.

Related

Google Drive API file download status 0

I am using Google Drive javascript api V2 to download files. This has been working just fine for some time but today it is failing, returning status 0 with a blank response text. Looking at the network calls, I can see that I am authenticating successfully and navigating to the correct folders and retrieving a list of files but it will no longer download those files.
Looking deeper, I can see the initial response to each file download returns a status 307 (temporary redirect) and a redirect location in the response header. The browser automatically processes the location with a new request header but I do not get a response with any content, rather just an error with the status 0.
Is there a specific reason for the status 307 and is there a special way in which they should be handled?
This is the code used to download:
// Download file contents
downloadFile: function ( fileItem, callback ) {
var me = this,
accessToken,
xhr;
if ( fileItem.downloadUrl ) {
accessToken = gapi.auth.getToken().access_token;
xhr = new XMLHttpRequest();
xhr.onerror = function () {
callback( { error: { code: xhr.status, message: xhr.statusText } } );
};
xhr.open( 'GET', fileItem.downloadUrl, true );
xhr.setRequestHeader( 'Authorization', 'Bearer ' + accessToken );
xhr.overrideMimeType( "application/json" );
xhr.onreadystatechange = function () {
var DONE = this.DONE || 4;
if ( xhr.readyState === DONE ) {
if ( xhr.status === 200 ) {
callback( xhr.responseText );
} else {
callback( { error: { code: xhr.status, message: xhr.statusText } } );
};
};
};
xhr.send();
} else {
callback( { error: { code: "?", message: "Downloaded URL not specified" } } );
};
},
I am closing this question despite not getting a resolution. I have updated my code to use v3 of the Google Drive api and have got it working using that.
Strangely, if I used the HTTP request Url 'https://www.googleapis.com/drive/v3/files/<fileId>' it still didn't work but if I used the command:
gapi.client.drive.files.get( {
'fileId': fileItem.id,
'alt': 'media',
'mimeType': fileItem.mimeType
});
it works okay.
Not sure what Google have done as my previous code had been working for a couple of years without any change my end but at least I am back up and running again.

Express.js res.render not redirecting, just displayed in console

This time I want to use res.render to display html as success of DB update. I did it several times, but this time it doesn't work. It's not render html file, just displayed on chrome's console.
I think it caused because of async problem or duplicated response. I tried to many ways but I couldn't solve it, so pointers appreciated.
The code is related when the user paid service, increase user's level.
Get Access Token => Validate => res.render
app.post('/payment/validate', function(req, res, next){
// Get access token
request.post({
url : 'https://payment-company/get/token'
}, function(err, response, body) {
if(!err & response.statusCode == 200) {
var result = JSON.parse(body);
var accessToken = result.response.access_token;
// Validate payment (compare paid and would be paid)
request.get({
headers : { 'Authorization' : accessToken }
url : 'https://payment-company/find/paymentid'
}, function (err, response, body) {
if (!err && response.statusCode == 200){
var result = JSON.parse(body);
if (result.response.amount == req.body.price){
Members.findOne({id : req.user.id}, function(err, member){
// If no problem, update user level
member.level = 2;
member.save(function(err, result){
if (err) return next();
res.render('payment.view.result.ejs',
{
title : 'Success !',
description : 'level up.'
});
});
});
}
} else {
...
}
});
}
})
});
sorry to verbose code I tried to shorten code, No problem until res.render, res.render will work but it's not display page instead it just send html code to chrome's console.
Looks like there's a bit of a misunderstanding of how these requests work. What I think you intend:
Browser makes a GET request, server responds with an HTML document, the browser renders it
User takes an action
Browser makes a POST request, server responds with an HTML document, the browser renders it
What you've started coded on the frontend is an alternate method:
You make a POST request via AJAX, server responds with some JSON, you modify the current document with JavaScript to let the user know

How redirect to login page when got 401 error from ajax call in React-Router?

I am using React, React-Router and Superagent. I need authorization feature in my web application. Now, if the token is expired, I need the page redirect to login page.
I have put the ajax call functionality in a separated module and the token will be send on each request's header. In one of my component, I need fetch some data via ajax call, like below.
componentDidMount: function() {
api.getOne(this.props.params.id, function(err, data) {
if (err) {
this.setErrorMessage('System Error!');
} else if (this.isMounted()) {
this.setState({
user: data
});
}
}.bind(this));
},
If I got 401 (Unauthorized) error, maybe caused by token expired or no enough privilege, the page should be redirected to login page. Right now, in my api module, I have to use window.loication="#/login" I don't think this is a good idea.
var endCallback = function(cb, err, res) {
if (err && err.status == 401) {
return window.location('#/login');
}
if (res) {
cb(err, res.body);
} else {
cb(err);
}
};
get: function(cb) {
request
.get(BASE_URL + resources)
.end(endCallback.bind(null, cb));
},
But, I can't easily, call the react-router method in my api module. Is there an elegant way to implemented this easy feature? I don't want to add an error callback in every react components which need authorized.
I would try something like this:
Use the component's context to manipulate the router (this.context.router.transitionTo()).
Pass this method to the API callout as a param.
// component.js
,contextTypes: {
router: React.PropTypes.func
},
componentDidMount: function() {
api.getOne(this.props.params.id, this.context.router, function(err, data) {
if (err) {
this.setErrorMessage('System Error!');
} else if (this.isMounted()) {
this.setState({
user: data
});
}
}.bind(this));
},
// api.js
var endCallback = function(cb, router, err, res) {
if (err && err.status == 401) {
return router.transitionTo('login');
}
if (res) {
cb(err, res.body);
} else {
cb(err);
}
};
get: function(cb, router) {
request
.get(BASE_URL + resources)
.end(endCallback.bind(null, cb, router));
},
I know you didn't want a callback on each authenticated component, but I don't think there's any special react-router shortcuts to transition outside of the router.
The only other thing I could think of would be to spin up a brand new router on the error and manually send it to the login route. But I don't think that would necessarily work since it's outside of the initial render method.

Doing ajax call on response of another function but not working

I have registration form and i have created three function in jquery
First one is validate the form.
Second one is for checking the email uniqueness with ajax request.
Third one is for creating user this also with ajax request.
My flow on submit event is that first i am calling validation function and then on the response of that function i calling the function to check the email uniqueness on the response of this a an ajax request is done to create a user.
First one is validate the form.
function validateregForm()
{
if($('#u_name').val()=="" || !IsEmail($('#u_email').val()) || $('#u_pwd').val().length<6 || $('#c_pwd').val()!=$('#u_pwd').val())
{
if($('#u_name').val()=="")
{
$('#reg_error1').show();
}
if(!IsEmail($('#u_email').val()))
{
$('#email_msg').remove();
$('#reg_error2').show();
}
if($('#u_pwd').val().length<6)
{
$('#reg_error3').show();
}
if($('#u_pwd').val()!=$('#c_pwd').val())
{
$('#reg_error4').show();
}
return false;
}
else
{
return true ;
}
Second one is for checking the email uniqueness with ajax request.
function chkmail(email) {
var posting=$.post('http://localhost/tv100.info/index.php/user/chkmail',{u_email:$('#u_email').val()});
posting.done(function(data){
if(data=='success')
{
$('#email_error').css('display','none');
$('#email_msg').css('display','block');
return true;
}
if(data=='failure')
{
$('#email_msg').css('display','none');
$('#email_error').css('display','block');
return false;
}
});
}
Third one is for creating user this also with ajax request.
$('#regform').submit(function(event) {
var res=validateregForm()
event.preventDefault();
if(res)
{
var email=chkmail();
}
if(email)
{
$('#loading2').show();
var posting=$.post('http://localhost/tv100.info/index.php/user/create_user',$("#regform").serialize());
posting.done(function(data)
{
$('#loading2').hide();
if(data=="success")
{
$('#reg_panel').append('<span id="reg_msg">Registration successful Now You are logged IN</span>');
$('#overlay').fadeOut(300);
$('#login').html('Logout');
$('#sign_in').hide();
$('#cmmnt_field').show();
}
if(data=="failure")
{
$('#reg_panel').append('<span id="res_msg">Something Went Wrong try again Latter</span>');
}
});
}
});
Just telling the case
if(res)
{
var email=chkmail(); // for getting the result in var email, ajax will wait until the success
}
if(email) // In your case before completing the ajax request, javascript come to this line and won't return true. So it it always go to else part.
You can do the user creation on success of chkmail success part. It will work fine
Error in your first line of validateregForm() function,
change
if($('#u_name').val=="" || !IsEmail($('#u_email').val())
to
if($('#u_name').val() =="" || !IsEmail($('#u_email').val())
^ `.val()` here.
You need to learn about asynchronously and synchronously concepts. Ajax calls are usually Asynchronously. Simple set the paramter async as false of each ajax request and you will get the result. From documentation
async (default: true)
Type: Boolean
By default, all requests are sent asynchronously (i.e. this is set to true by default).
If you need synchronous requests, set this option to false.
Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation.
Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active.
As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success().
You need to use a callback to process the result of email validation
function chkmail(email, callback) {
var posting = $.post('http://localhost/tv100.info/index.php/user/chkmail', {
u_email : email
});
posting.done(function(data) {
if (data == 'success') {
callback(true);
} else if (data == 'failure') {
callback(false);
}
});
}
$('#regform').submit(function(event) {
var res = validateregForm()
event.preventDefault();
if (res) {
chkmail($('#u_email').val(), function(valid) {
if (valid) {
$('#email_error').css('display', 'none');
$('#email_msg').css('display', 'block');
$('#loading2').show();
var posting = $.post('http://localhost/tv100.info/index.php/user/create_user', $("#regform").serialize());
posting.done(function(data) {
$('#loading2').hide();
if (data == "success") {
$('#reg_panel').append('<span id="reg_msg">Registration successful Now You are logged IN</span>');
$('#overlay').fadeOut(300);
$('#login').html('Logout');
$('#sign_in').hide();
$('#cmmnt_field').show();
}
if (data == "failure") {
$('#reg_panel').append('<span id="res_msg">Something Went Wrong try again Latter</span>');
}
});
} else {
$('#email_msg').css('display', 'none');
$('#email_error').css('display', 'block');
}
});
}
});

AJAX call in expressJS

I can't seem to get the AJAX call correct. There have been other QA that deal with the $.ajax() function but I'm trying to solve this with $.post().
When the form button is clicked the javascript at the head is executed, which includes a $.post(). The url /login is routed through and passed to loginPost function. There a response is determined and sent back to the javascript (right?). Instead, webpage renders the response (pass || fail).
Why isn't the response from the AJAX call being sent back to get processed?
This is a simple example that I am working with to get me better acquainted to how AJAX in expressJS and jQuery work. Any Help is greatly appreciated!
--views/login.jade
script(src='/_js/jquery-1.8.2.min.js')
script
$(document).ready(function(req, res) {
$('#login').submit(function() {
var formData = $(this).serialize();
console.log(formData);
$.post('/login', formdata, processData).error('ouch');
function processData(data, status) {
console.log(status);
console.log(data);
if (data == 'pass') {
$('#content').html('<p>You have successfully loggin in!</p>');
} else {
if (! $('#fail').length) {
$('#formFrame').prepend('<p id="fail">Incorrect login information. Please try again)</p>');
}
}
} //end processData
}); //end submit
}); //end ready
div.main
h1= title
div#formFrame
form(id='login', action='/login', method='POST')
p
label(for='username') Username:
input(id='username', type='text', name='username')
p
label(for='password') Password:
input(id='password', type='password', name='password')
p
input(id='button', type='submit', name='button', value='Submit')
--routes/index.js
app.post('/login', loginPost);
--routes/loginPost
module.exports.loginPost = function(req, res) {
var password = 'admin'
, username = 'user'
, data = req.body;
if (data.username == username && data.password == password) {
res.send('pass');
} else {
res.send('fail');
}
};
You still have to stop the <form> from submitting via its default action, which can be done with event.preventDefault():
$('#login').submit(function(evt) {
evt.preventDefault();
// ...
});
Otherwise, the <form> will redirect the page to its action (or back to the current address if no action was given), interrupting the $.post request.

Resources