add user signup through loopback

This commit is contained in:
Berkeley Martinez
2015-06-09 16:43:08 -07:00
parent 39d57db782
commit a8494b29da
10 changed files with 140 additions and 244 deletions

View File

@ -1,19 +0,0 @@
var debug = require('debug')('freecc:models:user');
module.exports = function(User) {
debug('setting up user hooks');
/*
* NOTE(berks): not sure if this is still needed
User.observe('before save', function setUsername(ctx, next) {
// set username from twitter
if (ctx.instance.username && ctx.instance.username.match(/twitter/g)) {
ctx.instance.username =
ctx.instance.username.match(/twitter/g) ?
ctx.instance.username.split('.').pop().toLowerCase() :
ctx.instance.username;
debug('username set', ctx.instance.username);
}
next();
});
*/
};

View File

@ -3,6 +3,7 @@
"base": "User",
"trackChanges": false,
"idInjection": true,
"strict": true,
"properties": {
"email": {
"type": "string",

View File

@ -422,14 +422,18 @@ profileValidation.directive('uniqueUsername', ['$http', function($http) {
link: function (scope, element, attrs, ngModel) {
element.bind("keyup", function (event) {
ngModel.$setValidity('unique', true);
if (element.val()) {
$http.get("/api/checkUniqueUsername/" + element.val()).success(function (data) {
if (element.val() === scope.storedUsername) {
ngModel.$setValidity('unique', true);
} else if (data) {
ngModel.$setValidity('unique', false);
}
});
var username = element.val();
if (username) {
var config = { params: { username: username } };
$http
.get('/api/users/exists', config)
.success(function (exists) {
if (username === scope.storedUsername) {
ngModel.$setValidity('unique', true);
} else if (exists) {
ngModel.$setValidity('unique', false);
}
});
}
});
}
@ -449,11 +453,13 @@ profileValidation.directive('existingUsername',
element.removeClass('ng-dirty');
ngModel.$setPristine();
}
if (element.val()) {
var username = element.val();
if (username) {
var config = { params: { username: username } };
$http
.get('/api/checkExistingUsername/' + element.val())
.success(function (data) {
ngModel.$setValidity('exists', data);
.get('/api/users/exists', config)
.success(function(exists) {
ngModel.$setValidity('exists', exists);
});
}
});
@ -468,14 +474,18 @@ profileValidation.directive('uniqueEmail', ['$http', function($http) {
link: function getUnique (scope, element, attrs, ngModel) {
element.bind("keyup", function (event) {
ngModel.$setValidity('unique', true);
var email = element.val();
if (element.val()) {
$http.get("/api/checkUniqueEmail/" + encodeURIComponent(element.val())).success(function (data) {
if (element.val() === scope.storedEmail) {
ngModel.$setValidity('unique', true);
} else if (data) {
ngModel.$setValidity('unique', false);
}
});
var config = { params: { email: email } };
$http
.get('/api/users/exists', config)
.success(function (exists) {
if (email === scope.storedEmail) {
ngModel.$setValidity('unique', true);
} else if (exists) {
ngModel.$setValidity('unique', false);
}
});
};
});
}

View File

@ -0,0 +1,84 @@
var debug = require('debug')('freecc:extendUser');
module.exports = function(app) {
var User = app.models.User;
debug('setting up user hooks');
// send verification email to new camper
User.afterRemote('create', function(ctx, user, next) {
debug('user created, sending email');
if (!user.email) { return next(); }
var mailOptions = {
type: 'email',
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Welcome to Free Code Camp!',
redirect: '/',
text: [
'Greetings from San Francisco!\n\n',
'Thank you for joining our community.\n',
'Feel free to email us at this address if you have ',
'any questions about Free Code Camp.\n',
'And if you have a moment, check out our blog: ',
'blog.freecodecamp.com.\n',
'Good luck with the challenges!\n\n',
'- the Free Code Camp Volunteer Team'
].join('')
};
user.verify(mailOptions, function(err) {
if (err) { return next(err); }
debug('verification email sent');
ctx.req.flash({
msg: 'Please check your email and click on the verification link '
+ 'before logging in.'
});
ctx.res.redirect('/');
});
});
User.doesExist = function doesExist(username, email, cb) {
debug('checking existence');
var where = {};
if (username) {
where.username = username;
} else {
where.email = email;
}
User.count(
{ where: where },
function (err, count) {
if (err) { return cb(err); }
if (count > 0) {
return cb(null, true);
}
return cb(null, false);
}
);
};
User.remoteMethod(
'doesExist',
{
description: 'checks whether a user exists using email or username',
accepts: [
{
arg: 'username',
type: 'string'
},
{
arg: 'email',
type: 'string'
}
],
returns: [
{
arg: 'exists',
type: 'boolean'
}
],
http: {
path: '/exists'
}
}
);
};

View File

@ -35,12 +35,8 @@ module.exports = function(app) {
router.post('/reset/:token', postReset);
router.get('/email-signup', getEmailSignup);
router.get('/email-signin', getEmailSignin);
router.post('/email-signup', postEmailSignup);
// router.post('/email-signin', postSignin);
// router.post('/email-signup', postEmailSignup);
router.get('/account/api', getAccountAngular);
router.get('/api/checkUniqueUsername/:username', checkUniqueUsername);
router.get('/api/checkExistingUsername/:username', checkExistingUsername);
router.get('/api/checkUniqueEmail/:email', checkUniqueEmail);
router.post('/account/profile', postUpdateProfile);
router.post('/account/password', postUpdatePassword);
router.post('/account/delete', postDeleteAccount);
@ -65,49 +61,6 @@ module.exports = function(app) {
});
}
/**
* POST /signin
* Sign in using email and password.
*/
/*
* TODO(berks): this should be done using loopback
function postSignin (req, res, next) {
req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password cannot be blank').notEmpty();
var errors = req.validationErrors();
if (errors) {
req.flash('errors', errors);
return res.redirect('/signin');
}
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
req.flash('errors', { msg: info.message });
return res.redirect('/signin');
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
req.flash('success', { msg: 'Success! You are logged in.' });
if (/hotStories/.test(req.session.returnTo)) {
return res.redirect('../news');
}
if (/field-guide/.test(req.session.returnTo)) {
return res.redirect('../field-guide');
}
return res.redirect(req.session.returnTo || '/');
});
})(req, res, next);
}
*/
/**
* GET /signout
* Log out.
@ -146,107 +99,6 @@ module.exports = function(app) {
});
}
/**
* POST /email-signup
* Create a new local account.
*/
function postEmailSignup (req, res, next) {
req.assert('email', 'valid email required').isEmail();
var errors = req.validationErrors();
if (errors) {
req.flash('errors', errors);
return res.redirect('/email-signup');
}
var possibleUserData = req.body;
if (possibleUserData.password.length < 8) {
req.flash('errors', {
msg: 'Your password is too short'
});
return res.redirect('email-signup');
}
if (possibleUserData.username.length < 5 || possibleUserData.length > 20) {
req.flash('errors', {
msg: 'Your username must be between 5 and 20 characters'
});
return res.redirect('email-signup');
}
var user = new User({
email: req.body.email.trim(),
password: req.body.password,
profile: {
username: req.body.username.trim(),
picture:
'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'
}
});
User.findOne({ email: req.body.email }, function(err, existingEmail) {
if (err) {
return next(err);
}
if (existingEmail) {
req.flash('errors', {
msg: 'Account with that email address already exists.'
});
return res.redirect('/email-signup');
}
User.findOne(
{ 'profile.username': req.body.username },
function(err, existingUsername) {
if (err) {
return next(err);
}
if (existingUsername) {
req.flash('errors', {
msg: 'Account with that username already exists.'
});
return res.redirect('/email-signup');
}
user.save(function(err) {
if (err) { return next(err); }
req.logIn(user, function(err) {
if (err) { return next(err); }
res.redirect('/email-signup');
});
});
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
user: secrets.mandrill.user,
pass: secrets.mandrill.password
}
});
var mailOptions = {
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Welcome to Free Code Camp!',
text: [
'Greetings from San Francisco!\n\n',
'Thank you for joining our community.\n',
'Feel free to email us at this address if you have ',
'any questions about Free Code Camp.\n',
'And if you have a moment, check out our blog: ',
'blog.freecodecamp.com.\n',
'Good luck with the challenges!\n\n',
'- the Free Code Camp Volunteer Team'
].join('')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return err; }
});
});
});
}
/**
* GET /account
* Profile page.
@ -268,59 +120,6 @@ module.exports = function(app) {
});
}
/**
* Unique username check API Call
*/
function checkUniqueUsername (req, res, next) {
User.count(
{ 'profile.username': req.params.username.toLowerCase() },
function (err, data) {
if (err) { return next(err); }
if (data === 1) {
return res.send(true);
} else {
return res.send(false);
}
});
}
/**
* Existing username check
*/
function checkExistingUsername (req, res, next) {
User.count(
{ 'profile.username': req.params.username.toLowerCase() },
function (err, data) {
if (err) { return next(err); }
if (data === 1) {
return res.send(true);
} else {
return res.send(false);
}
}
);
}
/**
* Unique email check API Call
*/
function checkUniqueEmail (req, res, next) {
User.count(
{ email: decodeURIComponent(req.params.email).toLowerCase() },
function (err, data) {
if (err) { return next(err); }
if (data === 1) {
return res.send(true);
} else {
return res.send(false);
}
}
);
}
/**
* GET /campers/:username

View File

@ -2,5 +2,8 @@
"db": {
"name": "db",
"connector": "mongodb"
},
"mail": {
"connector": "mail"
}
}

View File

@ -1,6 +1,19 @@
var secrets = require('../config/secrets');
module.exports = {
db: {
connector: 'mongodb',
url: process.env.MONGOHQ_URL
},
mail: {
connector: 'mail',
transports: [{
type: 'smtp',
service: 'Mandrill',
auth: {
user: secrets.mandrill.user,
pass: secrets.mandrill.password
}
}]
}
};

View File

@ -8,7 +8,8 @@
]
},
"User": {
"dataSource": "db"
"dataSource": "db",
"public": false
},
"AccessToken": {
"dataSource": "db",
@ -26,6 +27,10 @@
"dataSource": "db",
"public": false
},
"Email": {
"dataSource": "mail",
"public": false
},
"bonfire": {
"dataSource": "db",
"public": true

View File

@ -2,7 +2,7 @@ extends ../layout
block content
.jumbotron.text-center(ng-controller="emailSignInController")
h2 Sign in with an email address here:
form(method='POST', action='/email-signin')
form(method='POST', action='/api/user/login')
input(type='hidden', name='_csrf', value=_csrf)
.col-sm-6.col-sm-offset-3
.form-group
@ -24,4 +24,4 @@ block content
br
br
br
br
br

View File

@ -2,7 +2,7 @@ extends ../layout
block content
.jumbotron.text-center
h2 Sign up with an email address here:
form.form-horizontal(method='POST', action='/email-signup', name="signupForm", novalidate="novalidate")
form.form-horizontal(method='POST', action='/api/users', name="signupForm", novalidate="novalidate")
input(type='hidden', name='_csrf', value=_csrf)
.form-group
.col-sm-6.col-sm-offset-3