students signup ready

parent fe86a2d6
......@@ -84,27 +84,26 @@ END;;
-- Integrity rule 3: office.current_enrolments and supervisor assigments updating.
DROP TRIGGER IF EXISTS TRG_MODIFY_STUDENT_ENROLMENTS;
CREATE TRIGGER TRG_MODIFY_STUDENT_ENROLMENTS
AFTER UPDATE ON student
FOR EACH ROW
thisTrigger: BEGIN
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_UPDATE_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
IF NOT (old.id_off<=>new.id_off) THEN
IF (old.id_off IS NOT NULL) THEN
DELETE
stu_sup
FROM
stu_sup INNER JOIN supervisor ON (stu_sup.id_sup=supervisor.id)
WHERE
id_stu=new.id AND old.id_off=supervisor.id_off;
END IF;
END IF;
END;;
DELIMITER ;
-- CREATE TRIGGER TRG_MODIFY_STUDENT_ENROLMENTS
-- AFTER UPDATE ON student
-- FOR EACH ROW
-- thisTrigger: BEGIN
-- IF ((@TRIGGER_CHECKS = FALSE)
-- OR (@TRIGGER_AFTER_UPDATE_CHECKS = FALSE))
-- AND (USER() = 'root@localhost')
-- THEN
-- LEAVE thisTrigger;
-- END IF;
--
-- IF NOT (old.id_off<=>new.id_off) THEN
-- IF (old.id_off IS NOT NULL) THEN
-- DELETE
-- stu_sup
-- FROM
-- stu_sup INNER JOIN supervisor ON (stu_sup.id_sup=supervisor.id)
-- WHERE
-- id_stu=new.id AND old.id_off=supervisor.id_off;
-- END IF;
-- END IF;
-- END;;
# Changes
#Database changes
#Para actualizar instalaciones antiguas ejecutar en vagrant/roles/database/files
# mysql -u root -p pictodb < upgrade.sql
# Database changes
Para actualizar instalaciones antiguas ejecutar en vagrant/roles/database/files
mysql -u root -p pictodb < upgrade.sql
Relanzar trigger-enrolments-integrity-constraints
......@@ -387,7 +387,6 @@ module.exports = {
delete supervisor.password;
if (req.body.password && req.body.password.length > 0)
supervisor.password = req.body.password;
console.log(supervisor.password);
supervisor.name = req.body.name || supervisor.name;
supervisor.surname = req.body.surname || supervisor.surname;
supervisor.gender = req.body.gender || supervisor.gender;
......
......@@ -69,18 +69,21 @@ module.exports = {
/**
Class methods
*/
hasExpired: function (license) {
return (new Date(license.expiration_ts) - new Date() < 0);
},
/**
* Generates a new trial license
* @param {ID} id_sup ID of the supervisor who creates the license
* @param {function} callback Callback function: license, err
* @param {function} callback Callback function: (err, license)
*/
newTrial: function(id_sup, callback) {
var now = new Date();
License.genLicenseNumber(function(number) {
if (!number)
callback(null, new Error("Unable to generate new license"));
callback(new Error("Unable to generate new license"), null);
License.create({
type: 'trial',
......@@ -90,10 +93,10 @@ module.exports = {
})
.then((l) => {
if (!l) throw new Error("Unable to create license");
callback(l, null);
callback(null, l);
})
.catch((err) => {
callback(null, err);
callback(err, null);
});
});
},
......@@ -136,7 +139,7 @@ module.exports = {
callback(license);
}
);
}
},
/**
......@@ -148,14 +151,16 @@ module.exports = {
getStudent: function(number, callback) {
License.findOne({ number: number })
.then((l) => {
if (!l || !l.activation_ts || !l.id_stu)
if (!l || !l.activation_ts || !l.student)
throw new Error("Invalid license: " + number);
// License ok, check student
Student.findOne(l.id_stu)
Student.findOne(l.student)
.then((s) => {
if (!s)
throw new Error("Student not found");
// convert model to normal object to be able to add attributes
s = s.toJSON();
s.license = l;
callback(null, s);
})
......@@ -176,6 +181,10 @@ module.exports = {
@param {function} callback Callback function with prototype: function(err, license)
*/
activate: function(number, id_stu, callback) {
if (!number || number.length < 16)
callback(new Error("Invalid license number"));
// Check license
License.findOne({ number: number })
.then((l) => {
......@@ -231,6 +240,7 @@ module.exports = {
* Callback function gets instantiated error if not available
*/
isActivable: function(number, cb) {
License.findOne({number: number})
.then ((l) => {
if (!l)
......
......@@ -109,8 +109,12 @@ module.exports = {
toJSON: function () {
var student = this.toObject();
student.pic = sails.config.pictogram.urls.getStudentAvatarUrl(student.pic);
if (student.license)
if (student.license) {
student.license = student.license[0] ? student.license[0] : null;
student.license.isValid = !License.hasExpired(student.license);
student.license.isTrial = student.license.type == 'trial';
student.license.isOfficial = student.license.type == 'official';
}
student.attributes = Student.getValidAttributes(student.attributes);
delete student.password;
return student;
......@@ -294,7 +298,8 @@ module.exports = {
if (!stuSups || stuSups.length == 0)
return callback(null, []);
var sups = stuSups.map((st) => {return st.supervisor});
// filter null entries and map them to the supervisor object
var sups = _.compact(stuSups).map((st) => {return st.supervisor});
return callback(null, sups);
});
},
......@@ -302,7 +307,6 @@ module.exports = {
//
// Class method for getting the list of therapists associated to a given
// student
// NOTE: A therapist is a supervisor assigned to an office
therapists: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
......@@ -310,18 +314,8 @@ module.exports = {
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
async.eachSeries(stuSups,
function(stuSup, next) {
// stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor
if (stuSup.supervisor && stuSup.supervisor.office && stuSup.supervisor.id > 0) {
l.push(stuSup.supervisor);
}
next();
},
function (err) {
return callback(err, l);
}
);
var sups = _.compact(stuSups).filter((st) => {st.supervisor && st.supervisor.role == 'therapist'});
return callback(null, sups);
});
},
......@@ -329,7 +323,6 @@ module.exports = {
//
// Class method for getting the list of tutors associated to a given
// student
// NOTE: A tutor is a supervisor not assigned to any office
tutors: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
......@@ -337,18 +330,8 @@ module.exports = {
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
async.eachSeries(stuSups,
function(stuSup, next) {
// stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor
if (stuSup.supervisor && !stuSup.supervisor.office && stuSup.supervisor.id > 0) {
l.push(stuSup.supervisor);
}
next();
},
function (err) {
return callback(err, l);
}
);
var sups = _.compact(stuSups).filter((st) => {st.supervisor && st.supervisor.role == 'tutor'});
return callback(null, sups);
});
},
......@@ -525,7 +508,10 @@ module.exports = {
});
},
// Removes logically a student
/**
* Removes logically a student
* The user name is set with a random prefix and the license is removed
*/
logical_delete: function(id_stu, cb) {
Student.findOne(id_stu).exec(function(err, student) {
if (err || !student)
......@@ -533,7 +519,6 @@ module.exports = {
Student.update(id_stu,
{
username: Math.floor((Math.random() * 100000000) + 1) + "_" + student.username,
id_off: null
})
.then((updated) => {
License.destroy({id_stu: id_stu}).exec(cb);
......
......@@ -138,7 +138,6 @@ module.exports = {
//
beforeCreate: function (attrs, next) {
var async = require('async');
console.log("-->\n" + JSON.stringify(attrs));
async.series(
[
function (cb) {
......@@ -241,31 +240,30 @@ module.exports = {
})
.spread(function (sup, stuSups) {
async.eachSeries(stuSups, function(stuSup, next_cb) {
// Filter logically deleted students
if (stuSup.student.office == null)
return next_cb();
// set current method and instruction if any
Student.findOne(stuSup.student.id)
.populate('lastInstruction')
.populate('license')
.then(function (s) {
if (!s)
return next_cb();
s = s.toJSON();
s.current_method = s.lastInstruction[0] ? s.lastInstruction[0].met_name : "no_method";
s.current_instruction = s.lastInstruction[0] ? s.lastInstruction[0].ins_name : "no_instruction";
if (typeof(s.license[0]) != 'undefined') {
s.licenseIsValid = new Date(s.license[0].expiration_ts) - new Date() > 0 ? true : false;
s.license = s.license[0];
} else {
s.licenseIsValid = false;
s.license = null;
}
s.supervision = sup.office ? 2 : 1; // if Supervisor has office, then is a therapist (2), a tutor (1) otherwise
l.push(s);
if (!s.license)
return next_cb();
//
// El alumno tiene licencia, es válida y no es de prueba
//
if (s.license.isValid || s.license.isOfficial)
l.push(s);
next_cb();
});
},
function (err) {
callback(err, l);
callback(err, l);
});
})
.catch((err) => {
......
......@@ -17,7 +17,7 @@ module.exports = function isStudentOrSupervisorOfStudent (req, res, next) {
return res.json(401, {error: "This student has no supervisors associated"});
// if supervisor is not in the list of supervisors
if (sups.map(function(e) {return e.id}).indexOf(req.token.id) < 0)
if (_.compact(sups).map(function(e) {return e.id}).indexOf(req.token.id) < 0)
return res.json(401, {error: 'Access denied 3'});
// Finally, if the user has a clean record, we'll call the `next()` function
......
......@@ -5,17 +5,22 @@ module.exports = function isSupervisorOfStudent(req, res, next) {
if (!req.params.id_stu || !req.token.id)
return res.json(401, {error: 'Access denied'});
// Get list of supervisors for the student
Student.supervisors(req.params.id_stu, function(err, sups) {
if (err || !sups || sups.length == 0)
return res.json(401, {error: "This student has no supervisors associated"});
if (err)
return res.json(401, {error: err});
if (!sups || sups.length == 0)
return res.json(401, {error: "This student has no supervisors associated"});
if (sups.map(function(e) {return e.id}).indexOf(req.token.id) >= 0)
return next(); // Is Supervisor of Student
// if supervisor is not in the list of supervisors
if (_.compact(sups).map(function(e) {return e.id}).indexOf(req.token.id) < 0)
return res.json(401, {error: 'Access denied 3'});
return res.json(401, {error: "No valid credentials"});
})
.catch((err) => {
return res.json(401, {error: "Student not found"});
});
// Finally, if the user has a clean record, we'll call the `next()` function
// to let them through to the next policy or our controller
next();
});
};
......@@ -27,7 +27,7 @@ module.exports = function badRequest(data, options) {
// Log error to console
if (data !== undefined) {
sails.log.verbose('Sending 400 ("Bad Request") response: \n',data);
sails.log.verbose('Sending 400 ("Bad Request") response: \n', data);
}
else sails.log.verbose('Sending 400 ("Bad Request") response');
......
{
"account": "Account",
"account_activate": "The account has been activated",
"account_available": "Account available",
"account_desc_office": "Manage students, intervention teams along with all therapist related functionalities.",
"account_desc_therapist": "Manage pictograms, devices, record supervised sessions and get progress reports.",
"account_desc_tutor": "Configure your child's pictograms and his/her communication device.",
......@@ -188,6 +189,7 @@
"keep_strip_and_deliveries": "Keep strip and allow several deliveries",
"keep_strip_and_one_delivery": "Keep strip and allow only one delivery",
"language": "Language",
"language_change_warning": "Your preferred language has been changed. Session restarting is recommended.",
"large": "Large",
"large_picto": "Large pictograms",
"last_session": "Last session",
......@@ -201,9 +203,12 @@
"licenses": "Licenses",
"license_already_activated": "License already activated",
"license_created": "License created",
"license_expires": "PRO license expires on ",
"license_expired": "PRO license expired, you can",
"license_expired_official": "PRO license expired. To maintain access to therapeutical functionalities you can",
"license_expired_trial": "Trial license expired. To keep the account you should",
"license_expired_buy": "buy one",
"license_expired_renew": "renew it",
"license_expires_official": "PRO license expires on ",
"license_expires_trial": "Trial license expires on ",
"license_invalid": "Invalid license number",
"license_missing": "Account without PRO license",
"license_number": "License number",
......@@ -438,6 +443,7 @@
"tpl_date_frame": "de {{ begin | date:'dd-MM-yyyy' }} a {{ end | date:'dd-MM-yyyy' }}",
"tpl_day": "{{ day | date:'yyyy-MM-dd' }}",
"tpl_hours_frame": "from {{ begin | date:'HH:mm:ss' }} to {{ end | date:'HH:mm:ss' }}",
"trial_license": "Trial license",
"tries": "Tries",
"tries_done": "Tries done",
"tries_length": "Tries length",
......
{
"account": "Cuenta",
"account_activate": "La cuenta ha sido activada",
"account_available": "Cuenta disponible",
"account_desc_office": "Gestione alumnos y equipos de intervención, además de todas las funcionalidades propias de un terapeuta.",
"account_desc_tutor": "Gestione los pictogramas de su hijo o hija y configure su dispositivo de comunicación.",
"account_desc_therapist": "Gestione pictogramas, dispositivos, grabe sesiones de terapia y obtenga estadísticas de progreso.",
......@@ -188,6 +189,7 @@
"keep_strip_and_deliveries": "Mantener cinta y permitir varias entregas",
"keep_strip_and_one_delivery": "Mantener cinta y permitir sólo una entrega",
"language": "Idioma",
"language_change_warning": "Ha cambiado el idioma. Se recomienda reiniciar sesión.",
"large": "Grande",
"large_picto": "Pictogramas grandes",
"last_session": "Última sesión",
......@@ -201,10 +203,13 @@
"licenses": "Licencias",
"licenses_left": "{{number}} licencias disponibles",
"license_already_activated": "Licencia ya activada previamente",
"license_expires": "La licencia PRO expira el ",
"license_expired": "La licencia PRO expiró, puede",
"license_expired_renew": "renovarla",
"license_created": "Licencia creada",
"license_expired_official": "La licencia PRO expiró. Para mantener acceso a funcionalidades terapéuticas puede",
"license_expired_trial": "La licencia de prueba expiró. Para mantener la cuenta debería",
"license_expired_buy": "adquirir una",
"license_expired_renew": "renovarla",
"license_expires_official": "La licencia PRO finaliza el ",
"license_expires_trial": "La licencia de prueba finaliza el ",
"license_invalid": "Licencia inválida",
"license_number": "Número de licencia",
"license_pro": "Licencia Pictogram PRO",
......@@ -438,6 +443,7 @@
"tpl_date_frame": "de {{ begin | date:'dd-MM-yyyy' }} a {{ end | date:'dd-MM-yyyy' }}",
"tpl_day": "{{ day | date:'dd-MM-yyyy' }}",
"tpl_hours_frame": "de {{ begin | date:'HH:mm:ss' }} a {{ end | date:'HH:mm:ss' }}",
"trial_license": "Licencia de prueba",
"tries": "Ensayos",
"tries_done": "Ensayos realizados",
"tries_length": "Duración ensayos",
......
......@@ -32,10 +32,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
number: ''
},
license_expired: false,
office: {
id: '',
name: ''
},
stuSup: [],
pcb_count: 0,
pdb_count: 1
......@@ -84,7 +80,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
$scope.studentData.license_expired = new Date($scope.studentData.license.expiration_ts) - new Date() < 0;
moment.locale($translate.use().substr(0, 2));
$scope.studentData.expiration_date = moment($scope.studentData.license.expiration_ts).format('L');
console.log("updateLicenseExpiration");
};
// ----------------------------------------------------------------------
......@@ -105,8 +100,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
$scope.studentData.gender = data.gender;
$scope.studentData.lang = data.lang;
$scope.studentData.notes = data.notes;
$scope.studentData.office.id = data.office.id;
$scope.studentData.office.name = data.office.name;
$scope.studentData.stuSup = data.stuSup;
$scope.studentData.attributes = data.attributes;
$scope.studentData.current_method = data.current_method;
......
......@@ -8,7 +8,7 @@
<button class="btn btn-default" btn-radio="'device'" ng-model="section">
<i class="fa fa-tablet" aria-hidden="true"></i> {{ 'device' | translate }}
</button>
<button class="btn btn-default" btn-radio="'supervisors'" ng-model="section">
<button class="btn btn-default" btn-radio="'supervisors'" ng-model="section" ng-if="user.isOffice">
<i class="fa fa-users" aria-hidden="true"></i> {{ 'supervisors' | translate }}
</button>
</div>
......@@ -51,25 +51,42 @@
<label translate>license_number</label>
<input type="text" id="setup_license" class="form-control" mask="wwww-wwww-wwww-wwww" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formUser.license_number" required>
<!-- With license -->
<div ng-show="studentData.license && !studentData.license_expired" class="alert alert-info" role="alert">
<!-- With official license -->
<div ng-show="studentData.license && studentData.license.isValid && studentData.license.isOfficial" class="alert alert-info" role="alert">
<div class="row">
<div class="col-xs-2"><i class="fa fa-info-circle fa-lg" aria-hidden="true"></i></div>
<div class="col-xs-2"><i class="fa fa-certificate fa-lg" aria-hidden="true"></i></div>
<div class="col-xs-10">
{{ 'license_expires' | translate }} <b>{{ studentData.expiration_date }}</b>
{{ 'license_expires_official' | translate }} <b>{{ studentData.expiration_date }}</b>
</div>
</div>
</div>
<!-- License expired -->
<div ng-show="studentData.license && studentData.license_expired" class="alert alert-warning" role="alert">
<!-- With trial license -->
<div ng-show="studentData.license && studentData.license.isValid && studentData.license.isTrial" class="alert alert-info" role="alert">
<div class="row">
<div class="col-xs-2"><i class="fa fa-exclamation-circle fa-lg" aria-hidden="true"></i></div>
<div class="col-xs-2"><i class="fa fa-flask fa-lg" aria-hidden="true"></i></div>
<div class="col-xs-10">
<h4 class="alert-heading"> {{ 'license_expired' | translate }} </h4>
<p>
<a href="http://pictogramweb.com/caracteristicas-de-pictogram/">{{ 'license_expired_renew' | translate }}</a>
</p>
{{ 'license_expires_trial' | translate }} <b>{{ studentData.expiration_date }}</b>
</div>
</div>
</div>
<!-- Official license expired -->
<div ng-show="studentData.license && !studentData.license.isValid && studentData.license.isOfficial" class="alert alert-warning" role="alert">
<div class="row">
<div class="col-xs-2"><i class="fa fa-certificate fa-lg text-danger" aria-hidden="true"></i></div>
<div class="col-xs-10">
{{ 'license_expired_official' | translate }} <a href="http://pictogramweb.com/caracteristicas-de-pictogram/">{{ 'license_expired_renew' | translate }}</a>
</div>
</div>
</div>
<!-- Trial license expired -->
<div ng-show="studentData.license && !studentData.license.isValid && studentData.license.isTrial" class="alert alert-warning" role="alert">
<div class="row">
<div class="col-xs-2"><i class="fa fa-flask fa-lg text-danger" aria-hidden="true"></i></div>
<div class="col-xs-10">
{{ 'license_expired_trial' | translate }} <a href="http://pictogramweb.com/caracteristicas-de-pictogram/">{{ 'license_expired_buy' | translate }}</a>
</div>
</div>
</div>
......@@ -312,14 +329,14 @@
<div id="supervisors_section" ng-show="section == 'supervisors'">
<div class="row">
<div class="col-md-5" ng-if="studentData.supervision != 1">
<div class="col-md-5" ng-if="user.isOffice">
<!-- Supervisores (terapeutas) del alumno -->
<div id="student_sups">
<legend translate>therapists</legend>
<!-- Buscador de supervisores -->
<p>
<form role="search" ng-submit="search_sup()">
<div class="input-group" ng-if="user.isSupAdmin">
<div class="input-group">
<input type="email" class="form-control" placeholder="{{ 'search_sup_email' | translate }}" name="email_sup" id="email_sup" ng-model="supsForm.email_sup" required>
<div class="input-group-btn">
<button class="btn btn-default" type="submit">
......@@ -344,7 +361,7 @@
<!-- Imagen de perfil del supervisor -->
<img ng-src="{{sup.pic}}" class="profile" alt="" title="" />
{{sup.name}} {{sup.surname}}
<a ng-if="user.isSupAdmin" ng-click="delete_sup(sup.id)" class="delete_sup" title="{{ 'unlink' | translate}}">
<a ng-click="delete_sup(sup.id)" class="delete_sup" title="{{ 'unlink' | translate}}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</li>
......@@ -356,12 +373,12 @@
<div class="col-md-5">
<!-- Tutores (Padres) -->
<div id="student_tutors" ng-if="studentData.supervision != 1">
<div id="student_tutors" ng-if="user.isOffice">
<legend translate>tutors</legend>
<!-- Buscador de tutores -->
<p>
<form role="search" ng-submit="search_tutor()">
<div class="input-group" ng-if="user.isSupAdmin">
<div class="input-group">
<input type="email" class="form-control" placeholder="{{ 'search_tutor_email' | translate }}" name="email_tutor" id="email_tutor" ng-model="supsForm.email_tutor" required>
<div class="input-group-btn">
<button class="btn btn-default" type="submit">
......@@ -387,7 +404,7 @@
<!-- Imagen de perfil del tutor -->
<img ng-src="{{tutor.pic}}" class="profile" alt="" title="" />
{{tutor.name}} {{tutor.surname}}
<a ng-if="user.isSupAdmin" ng-click="delete_tutor(tutor.id)" class="delete_tutor" title="{{ 'unlink' | translate}}">
<a ng-click="delete_tutor(tutor.id)" class="delete_tutor" title="{{ 'unlink' | translate}}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</li>
......
......@@ -14,7 +14,8 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$translate,
ngToast,
$timeout,
IOService) {
IOService,
CONSTANTS) {
// Flags for showing buttons according to role
......@@ -24,9 +25,12 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
// Create new account
// --------------------------------------------------------
$scope.minlength = CONSTANTS.password_minlength;
var formdata_empty = {
username: '',
password: '',
password_confirm: '',
name: $translate.instant('name'),
surname: $translate.instant('surname'),
birthdate: Date(),
......@@ -37,7 +41,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
current_method: 'no_method',
current_instruction: 'no_instruction',
license_number: null,
id_sup: -1
id_sup: $scope.user.id
};
// Hide new student form
......@@ -96,10 +100,10 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
/**
* Add existing account
*/
function addExisting () {
$scope.addExisting = function () {
// Send link call to server
$http.post(config.backend + '/stu/license/id_sup/' + $scope.user.id, {license: $scope.formdata.license})
$http.post(config.backend + '/stu/license/sup/' + $scope.user.id, {license: $scope.formdata.license_number})
.success(function (data) {
ngToast.success({ content: $translate.instant('student_added') });
......@@ -117,12 +121,12 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
errorMessage = 'license_invalid';
else if (err.message && err.message.search('in use') > 0)
errorMessage = 'license_already_activated';
else if (typeof err == "string" && err.search("lready linked") > 0)
else if (err.message && err.message.search("lready linked") > 0)
errorMessage = 'student_already_linked';
else if (err && err.status === 400)
errorMessage = 'invalid_fields';
ngToast.danger({ content: $translate.instant(errorMessage) });
ngToast.danger($translate.instant(errorMessage));
});
}
......@@ -130,22 +134,19 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
/**
* Add new account
*/
function addNew(type) {
$scope.addNew = function (type) {
// set language according to interface settings
$scope.formdata.lang = $translate.use();
// Validate password match
if (student.password_confirm.length && student.password !== student.password_confirm) {
ngToast.danger({ content: $translate.instant('password_match') });
if ($scope.formdata.password_confirm.length && $scope.formdata.password !== $scope.formdata.password_confirm) {
ngToast.danger($translate.instant('password_match'));
return;
}
// Select API call according to type of account to create: office or test
var apicall = type == 'test' ? '/stu/test' : '/stu';
// Send creating call to server
$http.post(config.backend + apicall, $scope.formdata)
$http.post(config.backend + '/stu', $scope.formdata)
.success(function (data) {
ngToast.success({ content: $translate.instant('student_added') });
......@@ -159,12 +160,14 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$scope.slide.rightTo('confirmation');
})
.error(function (err) {
console.log(typeof err);
console.log(err);
var errorMessage = 'student_not_added';
if (err.message && err.message.search('nvalid license') > 0)
if (err.message && err.message.search('nvalid license') > 0 || typeof err == "string" && err.search('nvalid license') > 0)
errorMessage = 'license_invalid';
else if (err.message && err.message.search('in use') > 0)
else if (err.message && err.message.search('in use') > 0 || typeof err == "string" && err.search('in use') > 0)
errorMessage = 'license_already_activated';
else if (typeof err == "string" && err.search("already exists") > 0)
else if (err.message && err.message.search('already exists') > 0 || typeof err == "string" && err.search("already exists") > 0)
errorMessage = 'student_already_exists';
else if (err && err.status === 400)
errorMessage = 'invalid_fields';
......
......@@ -39,8 +39,9 @@
</div>
</td>
<td>
<i ng-show="!student.licenseIsValid" class="fa fa-exclamation-circle fa-lg text-danger license-warning" aria-hidden="true" popover="{{ 'license_missing' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="student.licenseIsValid" class="fa fa-certificate fa-lg text-primary license-warning" aria-hidden="true" popover="{{ 'license_pro' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="student.license.isValid && !student.license.isTrial" class="fa fa-certificate fa-lg text-primary license-warning" aria-hidden="true" popover="{{ 'license_pro' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="student.license.isTrial && student.license.isValid" class="fa fa-flask fa-lg text-warning license-warning" aria-hidden="true" popover="{{ 'trial_license' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="!student.license.isValid" class="fa fa-exclamation-circle fa-lg text-danger license-warning" aria-hidden="true" popover="{{ 'license_missing' | translate}}" popover-trigger="mouseenter"></i>
</td>
<td>
<h4>{{student.surname}}, {{student.name}}</h4>
......@@ -52,45 +53,50 @@
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/collections"
alt="{{ 'collections' | translate}}" popover="{{ 'collections' | translate}}" popover-trigger="mouseenter">
alt="{{ 'collections' | translate }}" popover="{{ 'collections' | translate }}" popover-trigger="mouseenter" ng-if="student.license.isValid">
<span class="glyphicon glyphicon-th" aria-hidden="true"></span>
</a>
<span
class="btn btn-default btn-lg" role="button"
alt="{{ 'collections' | translate }}" popover="{{ 'collections' | translate }}" popover-trigger="mouseenter" ng-if="!student.license.isValid">
<span class="glyphicon glyphicon-th" aria-hidden="true" style="color: #bbb" ></span>
</span>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/instructions"
alt="{{ 'instructions' | translate}}" popover="{{ 'instructions' | translate}}" popover-trigger="mouseenter" ng-if="!user.isTutor">
alt="{{ 'instructions' | translate }}" popover="{{ 'instructions' | translate }}" popover-trigger="mouseenter" ng-if="!user.isTutor && student.license.isValid">
<span class="glyphicon glyphicon-tasks" aria-hidden="true"></span>
</a>
<span
class="btn btn-default btn-lg" role="button"
alt="{{ 'instructions' | translate}}" popover="{{ 'instructions' | translate}}" popover-trigger="mouseenter" ng-if="user.isTutor">
alt="{{ 'instructions' | translate }}" popover="{{ 'instructions' | translate }}" popover-trigger="mouseenter" ng-if="user.isTutor || !student.license.isValid">
<span class="glyphicon glyphicon-tasks" aria-hidden="true" style="color: #bbb" ></span>
</span>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/session"
alt="{{ 'session' | translate}}" popover="{{ 'session' | translate}}" popover-trigger="mouseenter" ng-if="!user.isTutor">
alt="{{ 'session' | translate }}" popover="{{ 'session' | translate }}" popover-trigger="mouseenter" ng-if="!user.isTutor && student.license.isValid">
<span class="glyphicon glyphicon-transfer" aria-hidden="true"></span>
</a>
<span
class="btn btn-default btn-lg" role="button"
alt="{{ 'session' | translate}}" popover="{{ 'session' | translate}}" popover-trigger="mouseenter" ng-if="user.isTutor">
alt="{{ 'session' | translate }}" popover="{{ 'session' | translate }}" popover-trigger="mouseenter" ng-if="user.isTutor || !student.license.isValid">
<span class="glyphicon glyphicon-transfer" aria-hidden="true" style="color: #bbb"></span>
</span>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/reports"
alt="{{ 'reports' | translate}}" popover="{{ 'reports' | translate}}" popover-trigger="mouseenter" ng-if="!user.isTutor">
alt="{{ 'reports' | translate }}" popover="{{ 'reports' | translate }}" popover-trigger="mouseenter" ng-if="!user.isTutor && student.license.isValid">
<i class="fa fa-bar-chart" aria-hidden="true"></i>
</a>
<span class="btn btn-default btn-lg" role="button"
alt="{{ 'reports' | translate}}" popover="{{ 'reports' | translate}}" popover-trigger="mouseenter" ng-if="user.isTutor">
alt="{{ 'reports' | translate }}" popover="{{ 'reports' | translate }}" popover-trigger="mouseenter" ng-if="user.isTutor || !student.license.isValid">
<i class="fa fa-bar-chart" aria-hidden="true" style="color: #bbb"></i>
</span>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/setup"
alt="{{ 'setup' | translate}}" popover="{{ 'setup' | translate}}" popover-trigger="mouseenter">
alt="{{ 'setup' | translate }}" popover="{{ 'setup' | translate}}" popover-trigger="mouseenter">
<span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
</a>
......
......@@ -9,8 +9,6 @@
<div class="col-xs-9"></div>
</div>
<form name="AddStudentForm" role="form" ng-submit="add_student()" ng-controller="StudentAddCtrl">
<div class="switch-panel-body height400" ng-switch="slide.state">
<!--
......@@ -96,11 +94,11 @@
</div>
<div class="form-group">
<label translate>password</label>
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" ng-model="formdata.password" required />
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" name="password" ng-model="formdata.password" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.new.password.$dirty && forms.new.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" ng-model="formdata.password_confirm" required />
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" ng-model="formdata.password_confirm" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.new.password.$dirty && forms.new.password_confirm.$dirty" translate>password_match</span>
</div>
<div class="form-group">
......@@ -140,11 +138,11 @@
</div>
<div class="form-group">
<label translate>password</label>
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" ng-model="formdata.password" required />
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" name="password" ng-model="formdata.password" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.test.password.$dirty && forms.test.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" ng-model="formdata.password_confirm" required />
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" ng-model="formdata.password_confirm" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.test.password.$dirty && forms.test.password_confirm.$dirty" translate>password_match</span>
</div>
</div>
......@@ -167,7 +165,7 @@
-->
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="confirmation">
<h2>{{ 'user_created' | translate }} </h2>
<h2>{{ 'account_available' | translate }} </h2>
<p translate>student_account_confirm</p>
<br>
<img src="img/child.png"/>
......@@ -176,6 +174,4 @@
</div>
</form>
<hr />
......@@ -8,6 +8,7 @@ dashboardControllers.controller('TranslateController', function(
$scope,
$window,
$http,
$timeout,
config,
ngToast,
vcRecaptchaService
......@@ -44,7 +45,7 @@ dashboardControllers.controller('TranslateController', function(
//Server PUT
$http.put(config.backend + '/sup/' + $scope.user.id, { "lang": langKey })
.success(function (data) {
ngToast.success({ content: $translate.instant('data_saved') });
ngToast.success({ content: $translate.instant('language_change_warning') });
console.log("OK: Update supervisor language");
})
.error(function () {
......@@ -63,7 +64,5 @@ dashboardControllers.controller('TranslateController', function(
vcRecaptchaService.useLang(0, langKey.substr(0,2));
} catch (err) {}
// Reload page
$window.location.reload();
};
});
......@@ -83,13 +83,13 @@ module.exports.policies = {
},
SceneController:{
create: ['tokenAuth', 'isSupervisorOfStudent'],
update: ['tokenAuth', 'isSupervisorOfStudent'],
destroy: ['tokenAuth', 'isSupervisorOfStudent'],
duplicate: ['tokenAuth', 'isSupervisorOfStudent'],
getScene: ['tokenAuth'],
getStudentScenes: ['tokenAuth'],
scene: true
create: ['tokenAuth', 'isSupervisorOfStudent'],
update: ['tokenAuth', 'isSupervisorOfStudent'],
destroy: ['tokenAuth', 'isSupervisorOfStudent'],
duplicate: ['tokenAuth', 'isSupervisorOfStudent'],
getScene: ['tokenAuth'],
getStudentScenes: ['tokenAuth'],
scene: true
},
ServerController: {
......@@ -103,7 +103,7 @@ module.exports.policies = {
supervisors: ['tokenAuth'],
therapists: ['tokenAuth'],
tutors: ['tokenAuth'],
link_supervisor: ['tokenAuth', 'isOffice'],
link_supervisor: ['tokenAuth'],
pictos: ['tokenAuth'],
methods: ['tokenAuth'],
lasttries: ['tokenAuth'],
......@@ -115,7 +115,7 @@ module.exports.policies = {
update_legend: ['tokenAuth'],
update_category: ['tokenAuth', 'isSupervisorOfStudent'],
login: true,
create: ['tokenAuth', 'isOffice'],
create: ['tokenAuth'],
upload: ['tokenAuth'],
upload_sound: ['tokenAuth'],
add_picto: ['tokenAuth', 'isSupervisorOfStudent'],
......@@ -125,8 +125,8 @@ module.exports.policies = {
action: true,
config: true,
actions_batch: ['tokenAuth'],
delete: ['tokenAuth', 'isOffice'],
unlink_supervisor: ['tokenAuth', 'isOffice'],
delete: ['tokenAuth', 'isAdmin'],
unlink_supervisor: ['tokenAuth', 'isSupervisorOfStudent'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent'],
getActiveScene: ['tokenAuth'],
getScenes: ['tokenAuth'],
......
......@@ -89,8 +89,8 @@ module.exports.routes = {
'GET /stu/:id_stu/supervisors': 'StudentController.supervisors',
'GET /stu/:id_stu/therapists': 'StudentController.therapists',
'GET /stu/:id_stu/tutors': 'StudentController.tutors',
'POST /stu/:id_stu/sup/:id_sup': 'StudentController.link_supervisor',
'POST /stu/license/sup/:id_sup': "StudentController.link_supervisor",
'POST /stu/:id_stu/sup/:id_sup': 'StudentController.link_supervisor',
'GET /stu/:id_stu/pictos': 'StudentController.pictos',
'GET /stu/:id_stu/activeScene': 'StudentController.getActiveScene',
'GET /stu/:id_stu/scenes': 'StudentController.getScenes',
......@@ -108,7 +108,6 @@ module.exports.routes = {
'PUT /stu/:id_stu/activeScene/:id_scene': 'StudentController.updateActiveScene',
'POST /stu/login': 'StudentController.login',
'POST /stu': 'StudentController.create',
'POST /stu/license': 'StudentController.createTest',
'POST /stu/upload': 'StudentController.upload',
'POST /stu/:id_stu/upload_sound/:id_picto': 'StudentController.upload_sound',
'POST /stu/:id_stu/picto/:id_picto': 'StudentController.add_picto',
......
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