React and Loopback 3 verify user email - javascript

I am built a sign up component by using React and Loopback 3. At first I was not using email verification. In the code below I was getting response from rest api about user creation.
export function signUpUser(user) {
let userEmail = user.email;
let userPassword = user.password;
let userName = user.userName;
let privilege="user"
let credentials = {
email: userEmail,
password: userPassword,
userName: userName,
privilege:privilege
};
//console.log(credentials);
return dispatch => {
axios
.request({
method: "post",
url: loopBack + "/blogusers",
data: credentials
})
.then(response => {
console.log(response)
return dispatch(signUpSuccess(response.data));
})
.catch(error => {
return dispatch(signUpFailure(error));
});
};
}
My user model js was that
"use strict";
module.exports = function(Bloguser) {
};
After I add hook to create api my user model js is that.
"use strict";
var config = require("../../server/config.json");
var path = require("path");
var senderAddress = "jp6t63je22rfqgf7#ethereal.email";
module.exports = function(Bloguser) {
//send verification email after registration.
Bloguser.afterRemote("create", function(context, userInstance, next) {
console.log(">user.afterRemote triggered");
var options = {
type: "email",
to: userInstance.email,
from: senderAddress,
subject: "Thanks for registering.",
template: path.resolve(__dirname, "../../server/views/verify.ejs"),
Bloguser: userInstance
};
userInstance.verify(options, function(err, response) {
if (err) {
Bloguser.deleteById(userInstance.id);
return next(err);
}
console.log(">verification email sent.", response);
context.res.render("response", {
title: "Signed up successfully",
content:
"Please check your email and click on the verification link" +
"before logging in.",
redirectTo: "/login",
redirectToLinkText: "Log in"
});
});
});
};
By this code I can successfully send verification email and I can verify user by the link in the email. However I cannot get response from the Post api in the signUpUser() function. I need to get response to show the user status of his/her sign up process

I changed
context.res.render("response", {
title: "Signed up successfully",
content:
"Please check your email and click on the verification link" +
"before logging in.",
redirectTo: "/login",
redirectToLinkText: "Log in"
});
with
context.res.status(200).send(userInstance)
And Voile it worked.

Related

Why am I not getting the appropriate error messages displayed upon (network) request?

I'm trying to work out how to receive helpful error messages on the client side, but keep getting generic error messages. For example, trying to sign up with an email that is not available should result in the email#email.com is already in use error message. I, however, get the generic Request failed with status code 409 message, which is obviously unhelpful to the user. The network response is as expected as seen in the screenshot below. What gives? Why am I not getting the same error message as my (Redux) payload?
Below are the relevant code snippets.
Sign up controller
export default {
signup: async (req, res, next) => {
try {
const { fullname, username, email, password } = req.body;
// Check if there is a user with the same email
const foundUser = await User.findOne({ email });
if (foundUser) {
return res.status(409).send({ error: `${email} is already in use` });
}
const newUser = await User.create({
fullname,
username,
email,
password,
});
// Assign token to succesfully registered user
const token = authToken(newUser);
return res.status(200).send({ token, user: newUser });
} catch (error) {
next(error);
}
},
};
Sign up action
export const createAccount = ({
fullname,
username,
email,
password,
history
}) => async dispatch => {
dispatch({
type: actionTypes.CREATE_ACCOUNT_REQUEST,
});
try {
const {
data: {
newUser: { token, user },
},
} = await request.post('/auth/signup', {
fullname,
username,
email,
password,
});
localStorage.setItem('auth-token', token);
dispatch({
type: actionTypes.CREATE_ACCOUNT_SUCCESS,
payload: user
});
// Redirect to home
history.push('/home');
} catch (error) {
dispatch({
type: actionTypes.CREATE_ACCOUNT_FAILURE,
payload: error.message
});
}
};
Sign up network response
Redux sign up error payload
Try 'error.response.data.error' instead of 'error.message'

Nodemailer: No recipients Defined, how to fix?

When trying to send data from a form on a react.js component I am getting this error when I push the submit button to send the data to an e-mail address:
Error: No recipients defined
Can anyone tell me how I can fix this issue to get the data sending to an e-mail address I want?
Here is my mail.js file code:
const { Email } = require("./email_template");
const getEmailData = (template) => {
let data = null;
switch (template) {
case "hello":
data = {
from: "Contact Form",
to: "matthew.devonport.test#gmail.com",
subject: `Message from the contact form!`,
html: Email()
}
break;
default:
data;
}
return data;
}
const sendEmail = (to, name, type) => {
const smtpTransport = mailer.createTransport({
service: "Gmail",
auth: {
user: "testemail#gmail.com",
pass: "testpass"
}
})
const mail = getEmailData(to, name, type)
smtpTransport.sendMail(mail, function(error, response) {
if(error) {
console.log(error)
} else {
alert( "Thank you! We will be in touch shortly!")
}
smtpTransport.close();
})
}
module.exports = { sendEmail }```
Check your input to your function:
getEmailData(template)
When you invoke the method in sendEmail you don't match the input parameters
const mail = getEmailData(to, name, type)
Which returns null and gives the error implying on missing data.

How to reset password of AWS Cognito user?

If I click the "reset password" button for a user in the AWS Cognito, all it does is re-send the verification email, containing the account registration email code.
However, if the user takes that code and enters it on the verification page, AWS returns the error:
NotAuthorizedException: User cannot be confirmed. Current status is RESET_REQUIRED
First, how do I get Cognito to send a real "password reset" email instead of the "confirm your registration" email?
I assume it's giving me this error because the verification JS is calling:
createCognitoUser(email).confirmRegistration(code, true, function confirmCallback(err, result)
and not some undocumented password reset function. What function should I be calling?
You should be calling forgotPassword. From the AWS Documentation at Using Amazon Cognito User Identity Pools Javascript Examples:
cognitoUser.forgotPassword({
onSuccess: function (result) {
console.log('call result: ' + result);
},
onFailure: function(err) {
alert(err);
},
inputVerificationCode() {
var verificationCode = prompt('Please input verification code ' ,'');
var newPassword = prompt('Enter new password ' ,'');
cognitoUser.confirmPassword(verificationCode, newPassword, this);
}
});
So Even I faced a same issue, Even in AWS cognito documentation it was not clear, basically the process involves two steps.
call cognitoUser.forgotPassword() this will start forgot password process flow, and the user will receive a verification code.
then call cognitoUser.confirmPassword() which will reset the password verifying the code send to the email of user.
Below I have given a cognitoUserClass which has static methods forgotPassword() and confirmPassword() methods which implements those two steps.
import * as AmazonCognitoIdentity from 'amazon-cognito-identity-js'
class cognitoUserClass {
static cognitouser: AmazonCognitoIdentity.CognitoUser
static userPool = new AmazonCognitoIdentity.CognitoUserPool({
UserPoolId: 'your pool id',
ClientId: 'your client id',
})
static forgotPassword(userName: string): void {
const userData = {
Username: userName,
Pool: cognitoUserClass.userPool,
}
cognitoUserClass.cognitouser = new AmazonCognitoIdentity.CognitoUser(
userData
)
cognitoUserClass.cognitouser.forgotPassword({
onSuccess: (data) => {
console.log(data)
},
onFailure: (err) => {
console.log('ERR:', err)
},
})
}
static confirmPassword(
verificationCode: string,
newPassword: string
): void {
cognitoUserClass.cognitouser.confirmPassword(
verificationCode,
newPassword,
{
onFailure(err) {
console.log(err)
},
onSuccess(data) {
console.log(data)
},
}
)
}
}
export { cognitoUserClass }

ClientSide Notification for failed Login

I have a node.js project where I can fill a login form which will be send to my server.js as url params. If the sent data can be verified as registered, the client will be logged in. My Problem is now how do notificate the client when it didn't work?
My login.html contains a div which will be shown if it's triggered by my login.js file. But how do I activate the trigger, can I send url params to client and change the site's behaviour?
server.js
app.get("/signUp/:username/:password", (req, res) => {
auth.signUp({
username: req.params.username,
password: req.params.password
}, (result) => {
if (result) {
res.redirect("../../index.html");
} else {
res.redirect("../../index.html");
// res.send("Login failed");
}
})
})
app.get("/signIn/:username/:password", (req, res) => {
auth.signIn({
username: req.params.username,
password: req.params.password
}, (result) => {
if (result) {
res.redirect("../../index.html");
} else {
res.send("Login failed");
}
})
})
login.js Client-Side
signIn = () => {
let user = document.getElementById('signDiv-username').value;
let pass = document.getElementById('signDiv-password').value;
hideErrorLog();
window.location.replace("/signIn/" + user + "/" + pass);
}
signUp = () => {
let user = document.getElementById('signDiv-username').value;
let pass = document.getElementById('signDiv-password').value;
hideErrorLog();
window.location.replace("/signUp/" + user + "/" + pass);
}
hideErrorLog = () => {
let errorLog = document.getElementById("error-log");
errorLog.style.display = "none";
errorLog.innerText = "";
}
showErrorLog = (signUp) => {
let errorLog = document.getElementById("error-log");
errorLog.style.display = "block";
if (signUp) {
errorLog.innerText = "Benutzername existiert bereits!";
} else {
errorLog.innerText = "Benutzername/Passwort falsch!";
}
}
I see that you have been calling SignUp and SignIn APIs by using window.location.replace() and you are just replacing username and password as a part of the url which is not the way to make API calls AFAIK. And also never pass sensitive data like username and password in the URL, send them as part of body of the request.
You need to make use of fetch() and call showErrorLog() inside the catch() which means there's error in the API call.
Sample fetch code
fetch('http://example.com/movies.json')
.then(function(response) {
// Add some code here
})
.then(function(myJson) {
// call showErrorLog() here
});

Show inline field validation errors along with email sent message to an end user filling up a form

I'm working on an app being developed on Nodejs, Expressjs, Mongoose stack.
I'm building a form on submission of which if there are some validation errors[ want to use only mongoose validation, just to keep validation code at one place] then re-render these error messages back to form and if all fields are valid then send an email to end user if that email is not already available in mongoose.
So this form is very usual form except I'm doing rendering this form by expressjs and also want that enduser should get the info that there are field errors also send an email and notify the end user at the same time that email is in process of being sent, and if email already exists then notify the user instantly on form.
Some psuedocode which can help me to think in Nodejs way would be much appreciated. I'm coming from python/Django stack.
Below is email sender module which returns a promise object.
mailer.js
var path = require('path')
, templatesDir = path.resolve(__dirname, '..', 'email_templates')
, emailTemplates = require('email-templates')
, nodemailer = require('nodemailer')
, rsvp = require('rsvp')
;
var sendEmail = function (template_name, locals) {
return new rsvp.Promise(function(resolve,reject){
emailTemplates(templatesDir, function(err, template) {
if (err) {
return reject({error: err})
} else {
emailFrom = 'an_email_address',
mailer = {
host: 'some_amazon_instance',
port: 25,
service: 'SMTP', // Gmail, SMTP, Zoho
auth: {
user: 'credential',
pass: 'credential'
}
};
var transport = nodemailer.createTransport("SMTP", mailer);
var emailTo = emailFrom;
if (!locals.admin) {
emailTo = locals.email;
}
// Send a single email
template(template_name, locals, function(err, html, text) {
if (err) {
} else {
transport.sendMail({
from: emailFrom,
to: emailTo,
subject: locals.title,
html: html,
text: text
}, function(err, responseStatus) {
if (err) {
transport.close();
return reject({error: err});
} else {
resolve({result: responseStatus.message});
}
transport.close();
});
}
});
}
});
});
}
exports.sendEmail = sendEmail;
Below is the mongoose model to handle form data, validation and email sending.
invite.js
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose')
, Schema = mongoose.Schema
, sendEmail = require('meanio').loadConfig().sendEmail
, rsvp = require('rsvp')
;
var StudioInviteSchema = new Schema({
name: {
type: String, required: [true, 'name is required']
},
email: {
type: String,
index: true,
unique: true,
required: [true, 'email is required']
},
phone: {
type: Number,
index: true,
unique: true,
required: [true, 'phone is required']
},
address: {
type: String, required: [true, 'address is required']
},
email_template: {type: String, required: true},
title: {type: String, require: true}
});
StudioInviteSchema.path('phone').validate(function (value) {
return parseInt(value)!=NaN && value.toString().length == 10;
}, 'Enter a valid phone number');
StudioInviteSchema.path('email').validate(function (value) {
var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)| (\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(value)
}, 'Enter a valid email');
StudioInviteSchema.methods = {
saveAndEmailToAdmin: function () {
var instance = this;
console.log(instance, this, 42);
return new rsvp.Promise(function (resolve, reject) {
instance.save(function (err) {
if (err) {
if (err.code == 11000) {
return reject({message: 'duplicate invite'})
}
return reject({message: err})
}
var admin_email_context = {
name: instance.name,
email: instance.email,
phone: instance.phone,
address: instance.address,
title: instance.title,
admin: true
}
var studio_email_context = {
name: instance.name,
message: "We'll contact you shortly",
email: instance.email,
title: 'invite received',
admin: false
}
var admin_email = sendEmail(instance.email_template, admin_email_context)
var studio_email = sendEmail('userinvite', studio_email_context)
rsvp.allSettled([admin_email, studio_email])
.then(function (array) {
console.log(array)
resolve({message: 'success'})
}, function (error) {
resolve({message: 'error'})
})
})
});
}
};
mongoose.model('StudioInvite', StudioInviteSchema);
And finally below is the controller of html view which invoke saveAndEmailToAdmin of invite.js model for form validation and email sending.
invite_controller.js
exports.studioInvite = function (req, res) {
var invite = new StudioInvite({
name: req.body.name,
email: req.body.email,
phone: req.body.phone,
address: req.body.address,
email_template: 'studioinvite',
title: 'Invite request from studio'
});
/*
TODO:
have to use notifications to send messages to end users
like invite is sent successfully or there is some duplicacy
*/
invite.saveAndEmailToAdmin()
.then(function (result) {
console.log(result)
return [ send success messages ]
}, function (error) {
console.log(error);
return [ send error messages]
});
return [ i dont want to return at this line but if email sending takes time then have to return a response ]
}
I've found that i can use blocking code that means i've to put the user on hold untill everything is done on server, also I can use socket.io to send realtime notifications to end users about validation messages and email sent notifications.
But solution doesn't seem good to me.

Categories