Sails.js Can't set headers after they are sent - callback

I am using sailsjs v0.10.5.
I am trying to redirect to login after verifying user email and update the database before redirect.
I am using redirection in my update callback. But it sending the error after updating the database
'Cant send headers after they are sent'.
The following is the code am using for redirection:
verifyEmail: function(req, res){
var userId = req.param('userId');
User.update({id: userId},{isVerified: true}).exec(function(err, user) {
if (!err) {
req.flash('error', 'Your email is verified please login');
res.redirect('/login'); }else { return res.send(user, 400); }
});

Update waterline function is asynchronous, are you sure there isnt some res method later in the scope that may be fired before?

Its recommended to use return res.* for so-called "terminal methods" see http://sailsjs.org/#/documentation/reference/res/res.forbidden.html?q=notes

Related

How to stop the user from entering the duplicate record on default save

I have a custom module where there is an email field. Now i want to stop the user if the email is already in the database.
I want to stop the user on save button and show the error. Like when a required field goes empty.
I tried to get some help but was not able to understand it.
Note: I realized after posting this that you are using suitecrm which this answer will not be applicable toward but I will leave it in case anyone using Sugar has this question.
There are a couple of ways to accomplish this so I'll do my best to walk through them in the order I would recommend. This would apply if you are using a version of Sugar post 7.0.0.
1) The first route is to manually create an email address relationship. This approach would use the out of box features which will ensure your system only keeps track of a single email address. If that would work for your needs, you can review this cookbook article and let me know if you have any questions:
https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_9.2/Cookbook/Adding_the_Email_Field_to_a_Bean/
2) The second approach, where you are using a custom field, is to use field validation. Documentation on field validation can be found here:
https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_9.2/Cookbook/Adding_Field_Validation_to_the_Record_View/index.html
The code example I would focus on is:
https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_9.2/Cookbook/Adding_Field_Validation_to_the_Record_View/#Method_1_Extending_the_RecordView_and_CreateView_Controllers
For your example, I would imagine you would do something like this:
Create a language key for your error message:
./custom/Extension/application/Ext/Language/en_us.error_email_exists_message.php
<?php
$app_strings['ERROR_EMAIL_EXISTS_MESSAGE'] = 'This email already exists.';
Create a custom controller for the record creation (you may also want to do this in your record.js):
./custom/modules//clients/base/views/create/create.js
({
extendsFrom: 'RecordView',
initialize: function (options) {
this._super('initialize', [options]);
//reference your language key here
app.error.errorName2Keys['email_exists'] = 'ERROR_EMAIL_EXISTS_MESSAGE';
//add validation tasks
this.model.addValidationTask('check_email', _.bind(this._doValidateEmail, this));
},
_doValidateEmail: function(fields, errors, callback) {
var emailAddress = this.model.get('your_email_field');
//this may take some time so lets give the user an alert message
app.alert.show('email-check', {
level: 'process',
title: 'Checking for existing email address...'
});
//make an api call to a custom (or stock) endpoint of your choosing to see if the email exists
app.api.call('read', app.api.buildURL("your_custom_endpoint/"+emailAddress), {}, {
success: _.bind(function (response) {
//dismiss the alert
app.alert.dismiss('email-check');
//analyze your response here
if (response == '<email exists>') {
errors['your_email_field'] = errors['your_email_field'] || {};
errors['your_email_field'].email_exists = true;
}
callback(null, fields, errors);
}, this),
error: _.bind(function (response) {
//dismiss the alert
app.alert.dismiss('email-check');
//throw an error alert
app.alert.show('email-check-error', {
level: 'error',
messages: "There was an error!",
autoClose: false
});
callback(null, fields, errors);
})
});
},
})
Obviously, this isn't a fully working example but it should get you most of the way there. Hope this helps!

facebook api not returning email

I am trying to return user email address using facebook api. Few days ago it was working fine, but today stopped working, and don't know why.
So first I get access token:
FB.login(response => {
if (response.authResponse) {
resolve(response.authResponse.accessToken);
} else {
reject({
error: 'User cancelled login or did not fully authorize.'
});
}
}, {
scope: 'public_profile,email'
});
then I try to get user data
FB.api('/me', {fields: 'first_name,last_name,email'}, function(response) {
console.log(response);
});
but I only get data for first_name and last_name. There is no email.
Also when I ask for permissions, it gives me email as granted, but as I said, email is not returned.
FB.api('/me/permissions', function(response) {
console.log(response);
});
Does anyone knows what can be the problem?
BTW: I am using API v2.4.
FB.api('/me?fields=email,name', function(response) { /* stuff here */ });
Try adding your return fields to your request.
I know this is old question however if someone still seraching for answers then following workaround worked for me.
You need to add email in scope scope="public_profile,email".
<fb:login-button scope="public_profile,email" autologoutlink="false" onlogin="OnRequestPermission();"></fb:login-button>
A possible cause is that the user did not validate the email. Try with another user with validated email to make sure this is not the problem.
See also this answer
If you set all code correctly and still don't get an email from API. The user probably doesn't have an email bound to the account or the email not confirmed by the user.
I made it work using a promise and adding {scope:'email'} to the initial request then including 'email' in the fb.api fields.
fb.login({scope:'email'}).then(function (resp) {
if (resp.status === 'connected') {
fb.api('/me', 'get', {fields:'id,email,first_name,gender,...'}).then(function (FbUserData) {
console.log(FbUserData);
});
}
});
I spent a lot of time trying to figure out why the email is not returned on the FacebookLoginASPnetWebForms Asp.Net application (https://github.com/nickpinheiro/FacebookLoginASPnetWebForms).
I got it working, thanks to N Nem's post above (thanks!).
Open Default.aspx.cs
In HyperLink1.NaviagteUrl, add the query string parameter: &scope=public_profile,email
HyperLink1.NavigateUrl = "https://www.facebook.com/v2.4/dialog/oauth/?client_id=" + ConfigurationManager.AppSettings["FacebookAppId"] + "&redirect_uri=http://" + Request.ServerVariables["SERVER_NAME"] + ":" + Request.ServerVariables["SERVER_PORT"] + "/account/user.aspx&response_type=code&state=1&scope=public_profile,email";
I also had to fix some bugs to parse the access token correctly.
This time, the email address is available! I hope this helps?
N Nem above fixed for me. Had the code correct, but missing the scope on the login button. Code I use is below.
function statusChangeCallback(response){
if(response.status === 'connected'){
registerUser(response);
}
}
function checkLoginState() {
FB.getLoginStatus(function(response) {
statusChangeCallback(response);
});
}
function registerUser(statusResponse){
let userId = statusResponse.authResponse.userID;
FB.api('/'+userId+'/?fields=id,email,first_name,last_name',function(response){
if(response && !response.error){
console.log(response);
}
});
}
This is kinda old post but I am sharing the solution that worked for me.
FB Login SDK version: v6.0
First, make sure that the user (which is you for testing purposes) has a valid/verified email. Refer to the code below.
FB.login(response => {
// your code
}, {
scope: 'public_profile,email',
return_scopes: true,
auth_type: 'rerequest'
});
And in getting the user details
const response = await axios({
method: 'get',
url: 'https://graph.facebook.com/v6.0/me?fields=id,name,email&access_token=ACCESS_TOKEN&pretty=0&sdk=joey&suppress_http_code=1'
});
I've added the parameter fields=id,name,email

verify email using accounts.ui package

I want to send a verification email when some user is created. I use the accounts-password package, so any Accounts methods are called in my code.
I read in documentation that I need to call:
Accounts.sendVerificationEmail(userId, [email])
but the problem is that I don't know when to call it.
I tried to call in the callback function of Accounts.onCreateUser(func) but the user had not been created yet in the database.
Any ideas?
on the serverside:
Accounts.config({sendVerificationEmail: true, forbidClientAccountCreation: false});
got the answer from the comments above.
sendVerificationEmail is only available server-side. What I usually do is to use a setInterval inside onCreateUser to wait for Meteor to create the user before sending an email.
Read More: Verify an Email with Meteor Accounts.
// (server-side)
Accounts.onCreateUser(function(options, user) {
user.profile = {};
// we wait for Meteor to create the user before sending an email
Meteor.setTimeout(function() {
Accounts.sendVerificationEmail(user._id);
}, 2 * 1000);
return user;
});
You need specify mail in enviroment variables.
Then use Accounts.sendVerificationEmail(userId, [email]) in callback of Account.onCreateUser sorry for mistake and delay.
Like this (below is full example js file):
Template.register.events({
'submit #register-form' : function(e, t) {
e.preventDefault();
var email = t.find('#account-email').value
, password = t.find('#account-password').value;
// Trim and validate the input
Accounts.onCreateUser({email: email, password : password}, function(err){
if (err) {
// Inform the user that account creation failed
} else {
// Success. Account has been created and the user
// has logged in successfully.
Accounts.sendVerificationEmail(this.userId, email);
}
});
return false;
} });
if(Meteor.isServer){
Meteor.startup(function(){
process.env.MAIL_URL='smtp://your_mail:your_password#host:port'
}
}
I refered to this pages :
http://blog.benmcmahen.com/post/41741539120/building-a-customized-accounts-ui-for-meteor
http://sendgrid.com/blog/send-email-meteor-sendgrid/
How come my Meteor app with accounts package is not sending a verification email?

How can I send a success status to browser from nodejs/express?

I've written the following piece of code in my nodeJS/Expressjs server:
app.post('/settings', function(req, res){
var myData = {
a: req.param('a')
,b: req.param('b')
,c: req.param('c')
,d: req.param('d')
}
var outputFilename = 'config.json';
fs.writeFile(outputFilename, JSON.stringify(myData, null, 4), function(err) {
if(err) {
console.log(err);
} else {
console.log("Config file as been overwriten");
}
});
});
This allows me to get the submitted form data and write it to a JSON file.
This works perfectly. But the client remains in some kind of posting state and eventually times out. So I need to send some kind of success state or success header back to the client.
How should I do this?
Thank you in advance!
Express Update 2015:
Use this instead:
res.sendStatus(200)
This has been deprecated:
res.send(200)
Just wanted to add, that you can send json via the res.json() helper.
res.json({ok:true}); // status 200 is default
res.json(500, {error:"internal server error"}); // status 500
Update 2015:
res.json(status, obj) has been deprecated in favor of res.status(status).json(obj)
res.status(500).json({error: "Internal server error"});
In express 4 you should do:
res.status(200).json({status:"ok"})
instead of the deprecated:
res.json(200,{status:"ok"})
Jup, you need to send an answer back, the simplest would be
res.send(200);
Inside the callback handler of writeFile.
The 200 is a HTTP status code, so you could even vary that in case of failure:
if (err) {
res.send(500);
} else {
res.send(200);
}

Mongoose + Everyauth weird behavior

Using everyauth, when I login with a never autenticated before user on my website, the following code is launched. Checks if the user is already in my mongodb, if not it writes it. The issue right now is that works for the first authenticated user, then if a second user logins, my joiningUser._id parameters is properly initiated, but all the other parameters of my schema are from the first ever saved user, its like my parameters are never reinitialised... weird, my console.log shows the right new parameters, and not what is actually written in the database. My authentication is done via the everyauth module, I use the express framework.
exports.findOrCreateFacebookUser = function(fbUserData, promise){
User.findOne({_id:fbUserData.id}, function(err, user) {
if(err) {
console.log("Error in finding user for auth. Check Db");
promise.fail(err);
return;
}
else if(user){
console.log("User found ");
promise.fulfill(user);
}
else{
var joiningUser = new User();
joiningUser._id = fbUserData.id;
joiningUser.firstName = fbUserData.first_name;
joiningUser.lastName = fbUserData.last_name;
joiningUser.email = fbUserData.email;
//console.log(JSON.stringify(joiningUser));
joiningUser.save(function(err){
if(err){
console.log("Couldnt save new user: " + err);
promise.fail(err);
return;
}
else{
console.log("User wasnt existant, it is now created: " + JSON.stringify(joiningUser));
promise.fulfill(joiningUser);
}
});
}
});
};
Use mongoose-auth. It takes care of the combination of mongoose and everyauth for you.
There seems to be an issue with assigning _id with a forced value. So I created another id for the profile specific id (ex: facebookId).