diff --git a/app/controllers/users.server.controller.js b/app/controllers/users.server.controller.js
index b8b4c76f6f..4a4884f081 100755
--- a/app/controllers/users.server.controller.js
+++ b/app/controllers/users.server.controller.js
@@ -7,6 +7,12 @@ var mongoose = require('mongoose'),
passport = require('passport'),
User = mongoose.model('User'),
_ = require('lodash');
+ /* Requires for reset password */
+var nodemailer = require('nodemailer');
+var LocalStrategy = require('passport-local').Strategy;
+var bcrypt = require('bcrypt-nodejs');
+var async = require('async');
+var crypto = require('crypto');
/**
* Get the error message from error object
@@ -92,6 +98,160 @@ exports.signin = function(req, res, next) {
})(req, res, next);
};
+/**
+ * Forgot for reset password (forgot POST)
+ */
+exports.forgot = function(req, res, next) {
+ async.waterfall([
+ // Generate random token
+ function(done) {
+ crypto.randomBytes(20, function(err, buf) {
+ var token = buf.toString('hex');
+ done(err, token);
+ });
+ },
+ // Lookup user by email address
+ function(token, done) {
+ if (req.body.email) {
+ User.findOne({ email: req.body.email }, function(err, user) {
+ if (!user) {
+ return res.send(400, {
+ message: 'No account with that email address exists'
+ });
+ }
+
+ user.resetPasswordToken = token;
+ user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
+
+ user.save(function(err) {
+ done(err, token, user);
+ });
+ });
+ } else {
+ return res.send(400, {
+ message: 'Email field must not be blank'
+ });
+ }
+
+ },
+ // If valid email, send reset email using service
+ function(token, user, done) {
+ var smtpTransport = nodemailer.createTransport('SMTP', {
+ service: 'SendGrid', // Choose email service, default SendGrid
+ auth: {
+ user: 'your_sendgrid_email@domain.com',
+ pass: 'your_sendgrid_password'
+ }
+ });
+ var mailOptions = {
+ to: user.email,
+ from: 'your_email@domain.com',
+ subject: 'Password Reset',
+ text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
+ 'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
+ 'http://' + req.headers.host + '/auth/reset/' + token + '\n\n' +
+ 'If you did not request this, please ignore this email and your password will remain unchanged.\n'
+ };
+ smtpTransport.sendMail(mailOptions, function(err) {
+ res.send(200, {
+ message: 'An email has been sent to ' + user.email + ' with further instructions.'
+ });
+ done(err, 'done');
+ });
+ }
+ ], function(err) {
+ if (err) return next(err);
+ });
+};
+
+/**
+ * Reset password GET from email token
+ */
+exports.resetGet = function(req, res) {
+ User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
+ if (!user) {
+ // res.render('404');
+ res.send(400, {
+ message: 'Password reset token is invalid or has expired.'
+ });
+ return res.redirect('/#!/forgot');
+ }
+
+ res.redirect('/#!/reset/' + req.params.token);
+
+ });
+};
+
+/**
+ * Reset password POST from email token
+ */
+exports.resetPost = function(req, res) {
+ // Init Variables
+ var passwordDetails = req.body;
+ var message = null;
+
+ async.waterfall([
+ function(done) {
+ User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
+ if (!err && user) {
+ if (passwordDetails.newPassword === passwordDetails.verifyPassword) {
+ user.password = passwordDetails.newPassword;
+ user.resetPasswordToken = undefined;
+ user.resetPasswordExpires = undefined;
+
+ user.save(function(err) {
+ if (err) {
+ return res.send(400, {
+ message: getErrorMessage(err)
+ });
+ } else {
+ req.login(user, function(err) {
+ if (err) {
+ res.send(400, err);
+ } else {
+ done(err, user);
+ }
+ });
+ }
+ });
+ } else {
+ return res.send(400, {
+ message: 'Passwords do not match'
+ });
+ }
+ } else {
+ return res.send(400, {
+ message: 'Password reset token is invalid or has expired.'
+ });
+ }
+ });
+ },
+ function(user, done) {
+ var smtpTransport = nodemailer.createTransport('SMTP', {
+ service: 'SendGrid',
+ auth: {
+ user: 'your_sendgrid_email@domain.com',
+ pass: 'your_sendgrid_password'
+ }
+ });
+ var mailOptions = {
+ to: user.email,
+ from: 'your_email@domain.com',
+ subject: 'Your password has been changed',
+ text: 'Hello,\n\n' +
+ 'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
+ };
+ smtpTransport.sendMail(mailOptions, function(err) {
+ res.send(200, {
+ message: 'Password changed successfully'
+ });
+ });
+ }
+ ], function(err) {
+ res.redirect('/');
+ });
+};
+
/**
* Update user details
*/
diff --git a/app/models/user.server.model.js b/app/models/user.server.model.js
index 6cfe08c231..6af0c8b3ad 100755
--- a/app/models/user.server.model.js
+++ b/app/models/user.server.model.js
@@ -81,7 +81,14 @@ var UserSchema = new Schema({
created: {
type: Date,
default: Date.now
- }
+ },
+ /* For reset password */
+ resetPasswordToken: {
+ type: String
+ },
+ resetPasswordExpires: {
+ type: Date
+ }
});
/**
diff --git a/app/routes/users.server.routes.js b/app/routes/users.server.routes.js
index f925eb0618..d7cd2fa71b 100644
--- a/app/routes/users.server.routes.js
+++ b/app/routes/users.server.routes.js
@@ -17,6 +17,9 @@ module.exports = function(app) {
app.route('/auth/signup').post(users.signup);
app.route('/auth/signin').post(users.signin);
app.route('/auth/signout').get(users.signout);
+ app.route('/auth/forgot').post(users.forgot);
+ app.route('/auth/reset/:token').get(users.resetGet);
+ app.route('/auth/reset/:token').post(users.resetPost);
// Setting the facebook oauth routes
app.route('/auth/facebook').get(passport.authenticate('facebook', {
diff --git a/package.json b/package.json
index bf7aed985c..7ff7db95d4 100755
--- a/package.json
+++ b/package.json
@@ -41,7 +41,10 @@
"forever": "~0.11.0",
"bower": "~1.3.1",
"grunt-cli": "~0.1.13",
- "glob": "~3.2.9"
+ "glob": "~3.2.9",
+ "bcrypt-nodejs": "0.0.3",
+ "async": "~0.8.0",
+ "nodemailer": "~0.6.3"
},
"devDependencies": {
"supertest": "~0.10.0",
diff --git a/public/dist/application.min.js b/public/dist/application.min.js
index 62a5f946a5..059a714d7f 100644
--- a/public/dist/application.min.js
+++ b/public/dist/application.min.js
@@ -1 +1 @@
-"use strict";var ApplicationConfiguration=function(){return{applicationModuleName:"mean",applicationModuleVendorDependencies:["ngResource","ngAnimate","ui.router","ui.bootstrap","ui.utils"],registerModule:function(moduleName){angular.module(moduleName,[]),angular.module(this.applicationModuleName).requires.push(moduleName)}}}();angular.module(ApplicationConfiguration.applicationModuleName,ApplicationConfiguration.applicationModuleVendorDependencies),angular.module(ApplicationConfiguration.applicationModuleName).config(["$locationProvider",function($locationProvider){$locationProvider.hashPrefix("!")}]),angular.element(document).ready(function(){"#_=_"===window.location.hash&&(window.location.hash="#!"),angular.bootstrap(document,[ApplicationConfiguration.applicationModuleName])}),ApplicationConfiguration.registerModule("articles"),ApplicationConfiguration.registerModule("core"),ApplicationConfiguration.registerModule("users"),angular.module("articles").run(["Menus",function(Menus){Menus.addMenuItem("topbar","Articles","articles"),Menus.addMenuItem("topbar","New Article","articles/create")}]),angular.module("articles").config(["$stateProvider",function($stateProvider){$stateProvider.state("listArticles",{url:"/articles",templateUrl:"modules/articles/views/list-articles.client.view.html"}).state("createArticle",{url:"/articles/create",templateUrl:"modules/articles/views/create-article.client.view.html"}).state("viewArticle",{url:"/articles/:articleId",templateUrl:"modules/articles/views/view-article.client.view.html"}).state("editArticle",{url:"/articles/:articleId/edit",templateUrl:"modules/articles/views/edit-article.client.view.html"})}]),angular.module("articles").controller("ArticlesController",["$scope","$stateParams","$location","Authentication","Articles",function($scope,$stateParams,$location,Authentication,Articles){$scope.authentication=Authentication,$scope.create=function(){var article=new Articles({title:this.title,content:this.content});article.$save(function(response){$location.path("articles/"+response._id)},function(errorResponse){$scope.error=errorResponse.data.message}),this.title="",this.content=""},$scope.remove=function(article){if(article){article.$remove();for(var i in $scope.articles)$scope.articles[i]===article&&$scope.articles.splice(i,1)}else $scope.article.$remove(function(){$location.path("articles")})},$scope.update=function(){var article=$scope.article;article.updated||(article.updated=[]),article.updated.push((new Date).getTime()),article.$update(function(){$location.path("articles/"+article._id)},function(errorResponse){$scope.error=errorResponse.data.message})},$scope.find=function(){Articles.query(function(articles){$scope.articles=articles})},$scope.findOne=function(){Articles.get({articleId:$stateParams.articleId},function(article){$scope.article=article})}}]),angular.module("articles").factory("Articles",["$resource",function($resource){return $resource("articles/:articleId",{articleId:"@_id"},{update:{method:"PUT"}})}]),angular.module("core").config(["$stateProvider","$urlRouterProvider",function($stateProvider,$urlRouterProvider){$urlRouterProvider.otherwise("/"),$stateProvider.state("home",{url:"/",templateUrl:"modules/core/views/home.client.view.html"})}]),angular.module("core").controller("HeaderController",["$scope","Authentication","Menus",function($scope,Authentication,Menus){$scope.authentication=Authentication,$scope.isCollapsed=!1,$scope.menu=Menus.getMenu("topbar"),$scope.toggleCollapsibleMenu=function(){$scope.isCollapsed=!$scope.isCollapsed}}]),angular.module("core").controller("HomeController",["$scope","Authentication",function($scope,Authentication){$scope.authentication=Authentication}]),angular.module("core").service("Menus",[function(){this.defaultRoles=["user"],this.menus={};var shouldRender=function(user){if(!user)return!this.requiresAuthentication;for(var userRoleIndex in user.roles)for(var roleIndex in this.roles)if(this.roles[roleIndex]===user.roles[userRoleIndex])return!0;return!1};this.validateMenuExistance=function(menuId){if(menuId&&menuId.length){if(this.menus[menuId])return!0;throw new Error("Menu does not exists")}throw new Error("MenuId was not provided")},this.getMenu=function(menuId){return this.validateMenuExistance(menuId),this.menus[menuId]},this.addMenu=function(menuId,requiresAuthentication,roles){return this.menus[menuId]={requiresAuthentication:requiresAuthentication||!0,roles:roles||this.defaultRoles,items:[],shouldRender:shouldRender},this.menus[menuId]},this.removeMenu=function(menuId){this.validateMenuExistance(menuId),delete this.menus[menuId]},this.addMenuItem=function(menuId,menuItemTitle,menuItemURL,menuItemUIRoute,requiresAuthentication,roles){return this.validateMenuExistance(menuId),this.menus[menuId].items.push({title:menuItemTitle,link:menuItemURL,uiRoute:menuItemUIRoute||"/"+menuItemURL,requiresAuthentication:requiresAuthentication||!1,roles:roles||this.defaultRoles,shouldRender:shouldRender}),this.menus[menuId]},this.removeMenuItem=function(menuId,menuItemURL){this.validateMenuExistance(menuId);for(var itemIndex in this.menus[menuId].items)this.menus[menuId].items[itemIndex].menuItemURL===menuItemURL&&this.menus[menuId].items.splice(itemIndex,1);return this.menus[menuId]},this.addMenu("topbar")}]),angular.module("users").config(["$httpProvider",function($httpProvider){$httpProvider.interceptors.push(["$q","$location","Authentication",function($q,$location,Authentication){return{responseError:function(rejection){switch(rejection.status){case 401:Authentication.user=null,$location.path("signin");break;case 403:}return $q.reject(rejection)}}}])}]),angular.module("users").config(["$stateProvider",function($stateProvider){$stateProvider.state("profile",{url:"/settings/profile",templateUrl:"modules/users/views/settings/edit-profile.client.view.html"}).state("password",{url:"/settings/password",templateUrl:"modules/users/views/settings/change-password.client.view.html"}).state("accounts",{url:"/settings/accounts",templateUrl:"modules/users/views/settings/social-accounts.client.view.html"}).state("signup",{url:"/signup",templateUrl:"modules/users/views/signup.client.view.html"}).state("signin",{url:"/signin",templateUrl:"modules/users/views/signin.client.view.html"})}]),angular.module("users").controller("AuthenticationController",["$scope","$http","$location","Authentication",function($scope,$http,$location,Authentication){$scope.authentication=Authentication,$scope.authentication.user&&$location.path("/"),$scope.signup=function(){$http.post("/auth/signup",$scope.credentials).success(function(response){$scope.authentication.user=response,$location.path("/")}).error(function(response){$scope.error=response.message})},$scope.signin=function(){$http.post("/auth/signin",$scope.credentials).success(function(response){$scope.authentication.user=response,$location.path("/")}).error(function(response){$scope.error=response.message})}}]),angular.module("users").controller("SettingsController",["$scope","$http","$location","Users","Authentication",function($scope,$http,$location,Users,Authentication){$scope.user=Authentication.user,$scope.user||$location.path("/"),$scope.hasConnectedAdditionalSocialAccounts=function(){for(var i in $scope.user.additionalProvidersData)return!0;return!1},$scope.isConnectedSocialAccount=function(provider){return $scope.user.provider===provider||$scope.user.additionalProvidersData&&$scope.user.additionalProvidersData[provider]},$scope.removeUserSocialAccount=function(provider){$scope.success=$scope.error=null,$http.delete("/users/accounts",{params:{provider:provider}}).success(function(response){$scope.success=!0,$scope.user=Authentication.user=response}).error(function(response){$scope.error=response.message})},$scope.updateUserProfile=function(){$scope.success=$scope.error=null;var user=new Users($scope.user);user.$update(function(response){$scope.success=!0,Authentication.user=response},function(response){$scope.error=response.data.message})},$scope.changeUserPassword=function(){$scope.success=$scope.error=null,$http.post("/users/password",$scope.passwordDetails).success(function(){$scope.success=!0,$scope.passwordDetails=null}).error(function(response){$scope.error=response.message})}}]),angular.module("users").factory("Authentication",[function(){var _this=this;return _this._data={user:window.user},_this._data}]),angular.module("users").factory("Users",["$resource",function($resource){return $resource("users",{},{update:{method:"PUT"}})}]);
\ No newline at end of file
+"use strict";var ApplicationConfiguration=function(){var applicationModuleName="mean",applicationModuleVendorDependencies=["ngResource","ngAnimate","ui.router","ui.bootstrap","ui.utils"],registerModule=function(moduleName){angular.module(moduleName,[]),angular.module(applicationModuleName).requires.push(moduleName)};return{applicationModuleName:applicationModuleName,applicationModuleVendorDependencies:applicationModuleVendorDependencies,registerModule:registerModule}}();angular.module(ApplicationConfiguration.applicationModuleName,ApplicationConfiguration.applicationModuleVendorDependencies),angular.module(ApplicationConfiguration.applicationModuleName).config(["$locationProvider",function($locationProvider){$locationProvider.hashPrefix("!")}]),angular.element(document).ready(function(){"#_=_"===window.location.hash&&(window.location.hash="#!"),angular.bootstrap(document,[ApplicationConfiguration.applicationModuleName])}),ApplicationConfiguration.registerModule("articles"),ApplicationConfiguration.registerModule("core"),ApplicationConfiguration.registerModule("users"),angular.module("articles").run(["Menus",function(Menus){Menus.addMenuItem("topbar","Articles","articles"),Menus.addMenuItem("topbar","New Article","articles/create")}]),angular.module("articles").config(["$stateProvider",function($stateProvider){$stateProvider.state("listArticles",{url:"/articles",templateUrl:"modules/articles/views/list-articles.client.view.html"}).state("createArticle",{url:"/articles/create",templateUrl:"modules/articles/views/create-article.client.view.html"}).state("viewArticle",{url:"/articles/:articleId",templateUrl:"modules/articles/views/view-article.client.view.html"}).state("editArticle",{url:"/articles/:articleId/edit",templateUrl:"modules/articles/views/edit-article.client.view.html"})}]),angular.module("articles").controller("ArticlesController",["$scope","$stateParams","$location","Authentication","Articles",function($scope,$stateParams,$location,Authentication,Articles){$scope.authentication=Authentication,$scope.create=function(){var article=new Articles({title:this.title,content:this.content});article.$save(function(response){$location.path("articles/"+response._id)},function(errorResponse){$scope.error=errorResponse.data.message}),this.title="",this.content=""},$scope.remove=function(article){if(article){article.$remove();for(var i in $scope.articles)$scope.articles[i]===article&&$scope.articles.splice(i,1)}else $scope.article.$remove(function(){$location.path("articles")})},$scope.update=function(){var article=$scope.article;article.$update(function(){$location.path("articles/"+article._id)},function(errorResponse){$scope.error=errorResponse.data.message})},$scope.find=function(){$scope.articles=Articles.query()},$scope.findOne=function(){$scope.article=Articles.get({articleId:$stateParams.articleId})}}]),angular.module("articles").factory("Articles",["$resource",function($resource){return $resource("articles/:articleId",{articleId:"@_id"},{update:{method:"PUT"}})}]),angular.module("core").config(["$stateProvider","$urlRouterProvider",function($stateProvider,$urlRouterProvider){$urlRouterProvider.otherwise("/"),$stateProvider.state("home",{url:"/",templateUrl:"modules/core/views/home.client.view.html"})}]),angular.module("core").controller("HeaderController",["$scope","Authentication","Menus",function($scope,Authentication,Menus){$scope.authentication=Authentication,$scope.isCollapsed=!1,$scope.menu=Menus.getMenu("topbar"),$scope.toggleCollapsibleMenu=function(){$scope.isCollapsed=!$scope.isCollapsed}}]),angular.module("core").controller("HomeController",["$scope","Authentication",function($scope,Authentication){$scope.authentication=Authentication}]),angular.module("core").service("Menus",[function(){this.defaultRoles=["user"],this.menus={};var shouldRender=function(user){if(!user)return this.isPublic;for(var userRoleIndex in user.roles)for(var roleIndex in this.roles)if(this.roles[roleIndex]===user.roles[userRoleIndex])return!0;return!1};this.validateMenuExistance=function(menuId){if(menuId&&menuId.length){if(this.menus[menuId])return!0;throw new Error("Menu does not exists")}throw new Error("MenuId was not provided")},this.getMenu=function(menuId){return this.validateMenuExistance(menuId),this.menus[menuId]},this.addMenu=function(menuId,isPublic,roles){return this.menus[menuId]={isPublic:isPublic||!1,roles:roles||this.defaultRoles,items:[],shouldRender:shouldRender},this.menus[menuId]},this.removeMenu=function(menuId){this.validateMenuExistance(menuId),delete this.menus[menuId]},this.addMenuItem=function(menuId,menuItemTitle,menuItemURL,menuItemUIRoute,isPublic,roles){return this.validateMenuExistance(menuId),this.menus[menuId].items.push({title:menuItemTitle,link:menuItemURL,uiRoute:menuItemUIRoute||"/"+menuItemURL,isPublic:isPublic||this.menus[menuId].isPublic,roles:roles||this.defaultRoles,shouldRender:shouldRender}),this.menus[menuId]},this.removeMenuItem=function(menuId,menuItemURL){this.validateMenuExistance(menuId);for(var itemIndex in this.menus[menuId].items)this.menus[menuId].items[itemIndex].link===menuItemURL&&this.menus[menuId].items.splice(itemIndex,1);return this.menus[menuId]},this.addMenu("topbar")}]),angular.module("users").config(["$httpProvider",function($httpProvider){$httpProvider.interceptors.push(["$q","$location","Authentication",function($q,$location,Authentication){return{responseError:function(rejection){switch(rejection.status){case 401:Authentication.user=null,$location.path("signin");break;case 403:}return $q.reject(rejection)}}}])}]),angular.module("users").config(["$stateProvider",function($stateProvider){$stateProvider.state("profile",{url:"/settings/profile",templateUrl:"modules/users/views/settings/edit-profile.client.view.html"}).state("password",{url:"/settings/password",templateUrl:"modules/users/views/settings/change-password.client.view.html"}).state("accounts",{url:"/settings/accounts",templateUrl:"modules/users/views/settings/social-accounts.client.view.html"}).state("signup",{url:"/signup",templateUrl:"modules/users/views/signup.client.view.html"}).state("signin",{url:"/signin",templateUrl:"modules/users/views/signin.client.view.html"})}]),angular.module("users").controller("AuthenticationController",["$scope","$http","$location","Authentication",function($scope,$http,$location,Authentication){$scope.authentication=Authentication,$scope.authentication.user&&$location.path("/"),$scope.signup=function(){$http.post("/auth/signup",$scope.credentials).success(function(response){$scope.authentication.user=response,$location.path("/")}).error(function(response){$scope.error=response.message})},$scope.signin=function(){$http.post("/auth/signin",$scope.credentials).success(function(response){$scope.authentication.user=response,$location.path("/")}).error(function(response){$scope.error=response.message})}}]),angular.module("users").controller("SettingsController",["$scope","$http","$location","Users","Authentication",function($scope,$http,$location,Users,Authentication){$scope.user=Authentication.user,$scope.user||$location.path("/"),$scope.hasConnectedAdditionalSocialAccounts=function(){for(var i in $scope.user.additionalProvidersData)return!0;return!1},$scope.isConnectedSocialAccount=function(provider){return $scope.user.provider===provider||$scope.user.additionalProvidersData&&$scope.user.additionalProvidersData[provider]},$scope.removeUserSocialAccount=function(provider){$scope.success=$scope.error=null,$http.delete("/users/accounts",{params:{provider:provider}}).success(function(response){$scope.success=!0,$scope.user=Authentication.user=response}).error(function(response){$scope.error=response.message})},$scope.updateUserProfile=function(){$scope.success=$scope.error=null;var user=new Users($scope.user);user.$update(function(response){$scope.success=!0,Authentication.user=response},function(response){$scope.error=response.data.message})},$scope.changeUserPassword=function(){$scope.success=$scope.error=null,$http.post("/users/password",$scope.passwordDetails).success(function(){$scope.success=!0,$scope.passwordDetails=null}).error(function(response){$scope.error=response.message})}}]),angular.module("users").factory("Authentication",[function(){var _this=this;return _this._data={user:window.user},_this._data}]),angular.module("users").factory("Users",["$resource",function($resource){return $resource("users",{},{update:{method:"PUT"}})}]);
\ No newline at end of file
diff --git a/public/modules/users/config/users.client.routes.js b/public/modules/users/config/users.client.routes.js
index e715870ad4..8b35fac649 100755
--- a/public/modules/users/config/users.client.routes.js
+++ b/public/modules/users/config/users.client.routes.js
@@ -24,6 +24,14 @@ angular.module('users').config(['$stateProvider',
state('signin', {
url: '/signin',
templateUrl: 'modules/users/views/signin.client.view.html'
+ }).
+ state('forgot', {
+ url: '/forgot',
+ templateUrl: 'modules/users/views/forgot.client.view.html'
+ }).
+ state('reset', {
+ url: '/reset/:token',
+ templateUrl: 'modules/users/views/reset.client.view.html'
});
}
]);
\ No newline at end of file
diff --git a/public/modules/users/controllers/authentication.client.controller.js b/public/modules/users/controllers/authentication.client.controller.js
index a4ac880a25..46b88b561f 100644
--- a/public/modules/users/controllers/authentication.client.controller.js
+++ b/public/modules/users/controllers/authentication.client.controller.js
@@ -1,7 +1,7 @@
'use strict';
-angular.module('users').controller('AuthenticationController', ['$scope', '$http', '$location', 'Authentication',
- function($scope, $http, $location, Authentication) {
+angular.module('users').controller('AuthenticationController', ['$scope', '$stateParams', '$http', '$location', 'Authentication',
+ function($scope, $stateParams, $http, $location, Authentication) {
$scope.authentication = Authentication;
//If user is signed in then redirect back home
@@ -30,5 +30,37 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$http
$scope.error = response.message;
});
};
+
+ $scope.forgot = function() {
+ $scope.success = $scope.error = null;
+
+ $http.post('/auth/forgot', $scope.credentials).success(function(response) {
+ // Show user success message and clear form
+ $scope.credentials = null;
+ $scope.success = response.message;
+
+ }).error(function(response) {
+ // Show user error message and clear form
+ $scope.credentials = null;
+ $scope.error = response.message;
+ });
+ };
+
+ // Change user password
+ $scope.reset = function() {
+ $scope.success = $scope.error = null;
+
+ $http.post('/auth/reset/' + $stateParams.token,
+ $scope.passwordDetails).success(function(response) {
+
+ // If successful show success message and clear form
+ $scope.success = response.message;
+ $scope.passwordDetails = null;
+
+ }).error(function(response) {
+ $scope.error = response.message;
+ });
+ };
+
}
]);
\ No newline at end of file
diff --git a/public/modules/users/views/forgot.client.view.html b/public/modules/users/views/forgot.client.view.html
new file mode 100644
index 0000000000..19213dce7f
--- /dev/null
+++ b/public/modules/users/views/forgot.client.view.html
@@ -0,0 +1,21 @@
+Forgot your password?
+ Reset your password
+