Issue #675 to recover/change passwords done

parent 849161fa
......@@ -279,7 +279,7 @@ module.exports = {
var message = sails.__({
phrase: 'change_password_mail',
locale: params.lang || 'es-es'
}) + 'https://' + req.headers.host + '/sup/changepass/' + sailsTokenAuth.issueToken(supervisor.id, 60*24*7); // expires in 1 week
}) + 'https://' + req.headers.host + '/app/#/changepass/' + sailsTokenAuth.issueToken(sup.id, 60); // expires in 1 hour
sails.log.debug("Sending request email: \n" + message);
mailService.mailer()
......@@ -304,20 +304,20 @@ module.exports = {
*/
change_password: function (req, res) {
if (!req.params.token)
if (!req.body.token)
return res.badRequest("Invalid URL");
sailsTokenAuth.verifyToken(req.params.token, function(err, token) {
sailsTokenAuth.verifyToken(req.body.token, function(err, token) {
if (err)
return res.badRequest("Invalid token");
Supervisor.findOne(token).then(function (supervisor) {
if (!supervisor)
throw new Error("Error when looking for user");
supervisor.password = req.params.password;
supervisor.password = req.body.password;
supervisor.save();
return res.view('passwordChanged', {sup: supervisor, login_url: 'https://' + req.headers.host + '/app'});
return res.ok();
})
.catch(function (err) {
return res.serverError("Error when activating account " + err);
return res.serverError("Error when changing password " + err);
});
});
},
......
......@@ -89,6 +89,7 @@
"error_downloading_offices": "Error downloading offices",
"error_fetching_students": "Error when loading students",
"error_only_support_images": "Only images are supported (JPG, PNG or GIF files)",
"error_on_request": "The request has not been processed. Please, check your fields",
"error_loading_pictos": "Error loading pictos information",
"expand_navigation": "Expand navigation",
"expand_navigation": "Expand navigation",
......@@ -113,6 +114,7 @@
"instruction_begin": "Begin instruction",
"instruction_end": "End instruction",
"instructions": "Instructions",
"instructions_sent": "Instructions have been sent to your email address. Please, check your inbox.",
"invalid_fields": "Invalid values. Please, check fields introduced.",
"invalid_file_type": "Invalid file type",
"invisible": "Invisible. Clic for enable",
......@@ -145,6 +147,8 @@
"minutes": "minutes",
"month_totals": "Month totals",
"monthly":"Monthly",
"msg_change_password": "Please enter a new password for your account:",
"msg_request_change_password": "Enter your email to request for a password change. An e-mail will be sent to access password change form.",
"name": "Name",
"new_instruction": "New instruction",
"new_method": "New method",
......@@ -180,6 +184,7 @@
"own_pictos": "Your pictograms",
"pages": "Pages",
"password": "Password",
"password_changed": "Password changed sucessfully",
"password_confirm": "Repeat password",
"password_forgotten": "Have you forgotten your password?",
"password_match": "The passwords must match",
......@@ -213,6 +218,7 @@
"register": "Sign in",
"remember": "Remember me",
"reports": "Reports",
"request_change_password": "Request change password",
"room_changed": "A partner is offline. Session paused.",
"save": "Save",
"save_as_template": "Save as template",
......
......@@ -92,6 +92,7 @@
"error_downloading_offices": "Error al descargar las oficinas",
"error_fetching_students": "Error al cargar estudiantes",
"error_only_support_images": "Sólo se soportan imágenes (ficheros JPG, PNG o GIF)",
"error_on_request": "Se ha producido un error. Por favor, compruebe los valores introducidos.",
"error_loading_pictos": "Error cargando información de los pictos",
"February": "Febrero",
"feedback_picto": "Feedback al colocar un pictograma",
......@@ -113,6 +114,7 @@
"instruction_begin": "Primer intento",
"instruction_end": "Último intento",
"instructions": "Instrucciones",
"instructions_sent": "Se le han enviado instrucciones a su dirección de correo electrónico. Por favor, compruebe su buzón.",
"invalid_fields": "Valores inválidos. Compruebe los datos introducidos.",
"invalid_file_type": "Tipo de archivo no válido",
"invisible": "Invisible. Clic para activar",
......@@ -145,6 +147,8 @@
"minutes": "minutos",
"month_totals": "Totales mes",
"monthly":"Mensual",
"msg_change_password": "Por favor, introduzca la nueva clave para su cuenta:",
"msg_request_change_password": "Introduzca su correo electrónico para solicitar el cambio de clave. Recibirá un correo con la dirección de acceso al formulario de cambio de clave.",
"name": "Nombre",
"new_instruction": "Nueva instrucción",
"new_method": "Nuevo método",
......@@ -180,6 +184,7 @@
"own_pictos": "Propios",
"pages": "Páginas",
"password": "Contraseña",
"password_changed": "La clave ha sido modificada exitosamente.",
"password_confirm": "Repita la contraseña",
"password_forgotten": "¿Ha olvidado su contraseña?",
"password_match": "Las contraseñas deben coincidir",
......@@ -214,6 +219,7 @@
"register_button": "Registrar",
"remember": "No cerrar sesión",
"reports": "Informes",
"request_change_password": "Solicitar cambio de contraseña",
"room_changed":"Un participante abandonó la sesión. Sesión en pausa.",
"save": "Guardar",
"save_as_template": "Guardar como plantilla",
......
......@@ -61,13 +61,13 @@ dashboardApp.config(function ($stateProvider, $urlRouterProvider) {
templateUrl: 'modules/login/views/login.html',
controller: 'LoginCtrl'
})
.state('login_validate', {
url: '/login/:code/:email',
templateUrl: 'modules/login/views/login.html',
controller: 'LoginCtrl'
.state('request_change_password', {
url: '/changepass',
templateUrl: 'modules/login/views/login_setting_password.html',
controller: 'LoginSettingPasswordCtrl'
})
.state('login_tutor_validate', {
url: '/logintutor/:code/:email',
.state('change_password', {
url: '/changepass/:token',
templateUrl: 'modules/login/views/login_setting_password.html',
controller: 'LoginSettingPasswordCtrl'
})
......
......@@ -28,23 +28,6 @@ function LoginCtrl(
name : 'Pictogram'
};
// Validation of account
// if the code has been sent in the url "...app/login/code/email"
if ($stateParams.code && $stateParams.email) {
$http
.post(config.backend + '/sup/activate', $stateParams)
.success(function () {
$translate('account_activate').then(function (translation) {
ngToast.success({ content: translation });
});
})
.error(function () {
$translate('account_no_activate').then(function (translation) {
ngToast.danger({ content: translation });
});
});
}
// Corporate login, office code has been passed
if ($stateParams.office) {
$http
......
......@@ -3,46 +3,89 @@
//-----------------------------------
// Login Setting Password Controller
//-----------------------------------
dashboardControllers.controller('LoginSettingPasswordCtrl', function LoginSettingPasswordCtrl($scope, $http, $window, $translate, $location, config, $stateParams, ngToast) {
dashboardControllers.controller('LoginSettingPasswordCtrl', function LoginSettingPasswordCtrl(
$scope,
$http,
$window,
reCAPTCHA,
$translate,
$location,
config,
CONSTANTS,
$stateParams,
ngToast) {
$scope.login_setting_password = function () {
$scope.reset = function () {
$scope.email = '';
$scope.password = '';
$scope.password_confirm = '';
$scope.captcha_chgpass = '';
$scope.captcha_reqchgpass = '';
requestChangePasswordForm.$invalid = true;
changePasswordForm.$invalid = true;
};
// Validation of account
// if the code has been sent in the url "...app/login/code/email"
if ($stateParams.code && $stateParams.email) {
// Validate password match
if ($scope.password != $scope.password_confirm) {
$translate([
'validate_fail',
'password_match'
], function (translations) {
ngToast.danger({
content: [
translations.validate_fail,
translations.password_match
].join(': ')
});
$scope.reset();
reCAPTCHA.setPublicKey('6LdLjh0TAAAAANblo_KUGNnmRZuIetOkdjdhj1b6');
if ($stateParams.token)
$scope.show_change_form = true;
else
$scope.show_change_form = false;
/*
* Handles user submission of request for password change
*/
$scope.request_change_password = function () {
if (!$scope.requestChangePasswordForm.$valid)
return;
if ($scope.email) {
$http
.get(config.backend+'/sup/changepass/' + $scope.email)
.success(function(data, status, headers, config) {
$scope.reset();
ngToast.warning({ content: $translate.instant('instructions_sent') });
})
.error(function(data, status, headers, config) {
$scope.reset();
ngToast.danger({ content: $translate.instant('error_on_request') });
});
}
};
$scope.change_password = function () {
if ($stateParams.token) {
// Validate password match
if ($scope.password !== $scope.password_confirm) {
ngToast.danger({ content: $translate.instant('password_match') });
return;
}
if ($scope.password.length < CONSTANTS.password_minlength) {
ngToast.danger({ content: $translate.instant('password_short', {minlength: CONSTANTS.password_minlength}) });
return;
}
if (!$scope.changePasswordForm.$valid)
return;
var data = {
code: $stateParams.code,
email: $stateParams.email,
token: $stateParams.token,
password: $scope.password
};
$http
.post(config.backend+'/sup/activate', data)
.put(config.backend+'/sup/changepass', data)
.success(function(data, status, headers, config) {
$translate('validate_success').then(function (translation) {
ngToast.success({ content: translation });
});
$scope.reset();
ngToast.success({ content: $translate.instant('password_changed') });
})
.error(function(data, status, headers, config) {
$translate('validate_fail').then(function (translation) {
ngToast.danger({ content: translation });
});
$scope.reset();
ngToast.danger({ content: $translate.instant('error_on_request') });
});
}
};
......
......@@ -27,6 +27,7 @@ function SignInCtrl($scope,
password_confirm: '',
lang: 'es-es'
};
$scope.captcha = '';
};
reCAPTCHA.setPublicKey('6LdLjh0TAAAAANblo_KUGNnmRZuIetOkdjdhj1b6');
......@@ -51,8 +52,6 @@ function SignInCtrl($scope,
return;
}
$scope.captcha = '';
if (!$scope.signInForm.$valid)
return;
......
......@@ -37,6 +37,9 @@
<p class="text-center">
<a href="/app/#/signin" translate>create_an_account</a>
</p>
<p class="text-center">
<a href="/app/#/changepass" translate>password_forgotten</a>
</p>
</form>
</div>
<!-- Fin login -->
......
......@@ -8,18 +8,45 @@
<div id="login">
<!-- Logo Pictogram -->
<p class="text-center">
<img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" />
<a href="/app/#/login"><img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" /></a>
</p>
<div ng-show="{{ 'showlink' }}" class="text-center">
<div class="text-center">
<a href="/app/#/login" translate>click_login</a>
</div>
<!-- Formulario -->
<form ng-hide="{{ 'hideform' }}" name="loginSettingPasswordForm" ng-submit="login_setting_password()">
<!-- Request change password form -->
<form ng-hide="{{ 'show_change_form' }}" name="requestChangePasswordForm" ng-submit="request_change_password()">
<p class="text-left">
{{ 'msg_request_change_password' | translate}}
</p>
<div class="form-group">
<input type="email" class="form-control" id="email" placeholder="{{ 'your_email' | translate}}" required ng-model="email"/>
</div>
<div class="form-group" ng-if="!show_change_form">
<label>Captcha*</label>
<div re-captcha ng-model="captcha_reqchgpass"></div>
</div>
<p class="text-center">
<button type="submit" class="btn btn-primary" ng-disabled="requestChangePasswordForm.$invalid" translate>request_change_password</button>
</p>
</form>
<!-- Change password form -->
<form ng-show="{{ 'show_change_form' }}" name="changePasswordForm" ng-submit="change_password()">
<p class="text-left">
{{ 'msg_change_password' | translate}}
</p>
<div class="form-group">
<input type="password" class="form-control" id="login_password" placeholder="{{ 'password_type' | translate}}" required />
<input type="password" class="form-control" id="login_password" placeholder="{{ 'password_type' | translate}}" required ng-model="password"/>
</div>
<div class="form-group">
......@@ -28,8 +55,13 @@
<p class="color_red text_sm text-center" ng-show="password != password_confirm" translate>password_match</p>
<div class="form-group" ng-if="show_change_form">
<label>Captcha*</label>
<div re-captcha ng-model="captcha_chgpass"></div>
</div>
<p class="text-center">
<button type="submit" class="btn btn-primary" translate>send</button>
<button type="submit" class="btn btn-primary" ng-disabled="changePasswordForm.$invalid" translate>send</button>
</p>
</form>
......
......@@ -102,12 +102,12 @@ module.exports.routes = {
'GET /sup/:id/pic_categories/:id_cat': 'PictoController.categories',
'GET /sup/:id/pic_fromcategory/:id_cat': 'PictoController.fromcategory',
'GET /sup/email/:email': 'SupervisorController.getByEmail',
'GET /sup/changepass/:email': 'SupervisorController.request_change_password',
'PUT /sup/changepass': 'SupervisorController.change_password',
'PUT /sup/:id': 'SupervisorController.update',
'POST /sup': 'SupervisorController.create',
'POST /sup/login': 'SupervisorController.login',
'GET /sup/activate/:token': 'SupervisorController.activate',
'GET /sup/changepass': 'SupervisorController.request_change_password',
'GET /sup/changepass/:token': 'SupervisorController.change_password',
'POST /sup/upload': 'SupervisorController.upload',
'POST /sup/subscribe': 'SupervisorController.subscribe',
'POST /sup/unsubscribe': 'SupervisorController.unsubscribe',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment