diff --git a/common/models/user.js b/common/models/user.js new file mode 100644 index 0000000000..e7163aca3e --- /dev/null +++ b/common/models/user.js @@ -0,0 +1,140 @@ +var debug = require('debug')('freecc:user:remote'); + +module.exports = function(User) { + // NOTE(berks): user email validation currently not needed but build in. This + // work around should let us sneak by + // see: + // https://github.com/strongloop/loopback/issues/1137#issuecomment-109200135 + delete User.validations.email; + 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('success', { + msg: [ + 'Please check your email and click on the verification link ' + + 'before logging in.' + ] + }); + ctx.res.redirect('/'); + }); + }); + + User.beforeRemote('login', function(ctx, instance, next) { + debug('before called'); + debug(ctx, instance, next); + next(); + }); + + User.afterRemote('login', function(ctx, instance, next) { + var res = ctx.res; + var req = ctx.req; + + if (!instance || instance.emailVerified !== true) { + debug(instance); + req.flash('errors', { + msg: [ + 'Please verify your email address.' + ] + }); + return res.redirect('/'); + } + + var config = { + signed: !!req.signedCookies, + maxAge: 1000 * accessToken.ttl + }; + if (accessToken && accessToken.id) { + res.cookie('access_token', accessToken.id, config); + res.cookie('userId', accessToken.userId, config); + } + res.redirect('/'); + }); + + + + User.afterRemote('logout', function(ctx, result, next) { + var res = ctx.result; + res.clearCookie('access_token'); + res.clearCookie('userId'); + next(); + }); + + User.doesExist = function doesExist(username, email, cb) { + if (!username && !email) { + return process.nextTick(function() { + cb(null, false); + }); + } + debug('checking existence'); + var where = {}; + if (username) { + where.username = username.toLowerCase(); + } else { + where.email = email ? email.toLowerCase() : email; + } + debug('where', where); + User.count( + where, + function (err, count) { + if (err) { + debug('err checking existance: ', 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', + verb: 'get' + } + } + ); +}; diff --git a/common/models/user.json b/common/models/user.json index 8e15a241dc..7aeca01d1e 100644 --- a/common/models/user.json +++ b/common/models/user.json @@ -242,5 +242,5 @@ "property": "doesExist" } ], - "methods": [] + "methods": ["login"] } diff --git a/server/boot/a-extendUser.js b/server/boot/a-extendUser.js index ebb7b4724a..879112ab0a 100644 --- a/server/boot/a-extendUser.js +++ b/server/boot/a-extendUser.js @@ -1,121 +1,140 @@ -var debug = require('debug')('freecc:extendUser'); - -module.exports = function(app) { - var User = app.models.User; - // NOTE(berks): user email validation currently not needed but build in. This - // work around should let us sneak by - // see: - // https://github.com/strongloop/loopback/issues/1137#issuecomment-109200135 - delete User.validations.email; - 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.afterRemote('login', function(ctx, accessToken) { - var res = ctx.res; - var req = ctx.req; - - var config = { - signed: !!req.signedCookies, - maxAge: 1000 * accessToken.ttl - }; - if (accessToken && accessToken.id) { - res.cookie('access_token', accessToken.id, config); - res.cookie('userId', accessToken.userId, config); - } - res.redirect('/'); - }); - - User.afterRemote('logout', function(ctx, result, next) { - var res = ctx.result; - res.clearCookie('access_token'); - res.clearCookie('userId'); - next(); - }); - - User.doesExist = function doesExist(username, email, cb) { - if (!username && !email) { - return process.nextTick(function() { - cb(null, false); - }); - } - debug('checking existence'); - var where = {}; - if (username) { - where.username = username.toLowerCase(); - } else { - where.email = email ? email.toLowerCase() : email; - } - debug('where', where); - User.count( - where, - function (err, count) { - if (err) { - debug('err checking existance: ', 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', - verb: 'get' - } - } - ); -}; +//var debug = require('debug')('freecc:extendUser'); +// +//module.exports = function(app) { +// var User = app.models.User; +// // NOTE(berks): user email validation currently not needed but build in. This +// // work around should let us sneak by +// // see: +// // https://github.com/strongloop/loopback/issues/1137#issuecomment-109200135 +// delete User.validations.email; +// 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('success', { +// msg: [ +// 'Please check your email and click on the verification link ' +// + 'before logging in.' +// ] +// }); +// ctx.res.redirect('/'); +// }); +// }); +// +// User.beforeRemote('login', function(ctx, results, next) { +// debug('before called'); +// next(); +// }); +// +// User.afterRemote('login', function(ctx, instance, next) { +// debug('after called'); +// var res = ctx.res; +// var req = ctx.req; +// +// if (!instance || !instance.emailVerified) { +// req.flash('errors', { +// msg: [ +// 'Please verify your email address.' +// ] +// }); +// return res.redirect('/'); +// } +// +// var config = { +// signed: !!req.signedCookies, +// maxAge: 1000 * accessToken.ttl +// }; +// if (accessToken && accessToken.id) { +// res.cookie('access_token', accessToken.id, config); +// res.cookie('userId', accessToken.userId, config); +// } +// res.redirect('/'); +// }); +// +// +// +// User.afterRemote('logout', function(ctx, result, next) { +// var res = ctx.result; +// res.clearCookie('access_token'); +// res.clearCookie('userId'); +// next(); +// }); +// +// User.doesExist = function doesExist(username, email, cb) { +// if (!username && !email) { +// return process.nextTick(function() { +// cb(null, false); +// }); +// } +// debug('checking existence'); +// var where = {}; +// if (username) { +// where.username = username.toLowerCase(); +// } else { +// where.email = email ? email.toLowerCase() : email; +// } +// debug('where', where); +// User.count( +// where, +// function (err, count) { +// if (err) { +// debug('err checking existance: ', 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', +// verb: 'get' +// } +// } +// ); +//}; diff --git a/server/boot/user.js b/server/boot/user.js index e2e4ec0494..f5753c9b98 100644 --- a/server/boot/user.js +++ b/server/boot/user.js @@ -654,7 +654,6 @@ module.exports = function(app) { R.forEach(function (comment) { comment.author.picture = picture; comment.author.username = username; - comment.markModified('author'); tasks.push(function (cb) { comment.save(cb); }); @@ -663,7 +662,6 @@ module.exports = function(app) { R.forEach(function (story) { story.author.picture = picture; story.author.username = username; - story.markModified('author'); tasks.push(function (cb) { story.save(cb); }); diff --git a/server/model-config.json b/server/model-config.json index f944fb292a..56cd5a317d 100644 --- a/server/model-config.json +++ b/server/model-config.json @@ -61,7 +61,10 @@ }, "user": { "dataSource": "db", - "public": true + "public": true, + "options": { + "emailVerificationRequired": true + } }, "userCredential": { "dataSource": "db", diff --git a/server/views/account/email-signin.jade b/server/views/account/email-signin.jade index 4bc51797a2..b1c3fa4b46 100644 --- a/server/views/account/email-signin.jade +++ b/server/views/account/email-signin.jade @@ -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='/auth/local') + form(method='POST', action='/api/users/login') input(type='hidden', name='_csrf', value=_csrf) .col-sm-6.col-sm-offset-3 .form-group