students signup ready

parent fe86a2d6
...@@ -84,27 +84,26 @@ END;; ...@@ -84,27 +84,26 @@ END;;
-- Integrity rule 3: office.current_enrolments and supervisor assigments updating. -- Integrity rule 3: office.current_enrolments and supervisor assigments updating.
DROP TRIGGER IF EXISTS TRG_MODIFY_STUDENT_ENROLMENTS; 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 # Changes
#Database changes # Database changes
#Para actualizar instalaciones antiguas ejecutar en vagrant/roles/database/files
# mysql -u root -p pictodb < upgrade.sql Para actualizar instalaciones antiguas ejecutar en vagrant/roles/database/files
mysql -u root -p pictodb < upgrade.sql
Relanzar trigger-enrolments-integrity-constraints
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
Picto */ Picto */
/** /**
/* StudentController /* StudentController
* *
* @description :: Server-side logic for managing students * @description :: Server-side logic for managing students
* @help :: See http://links.sailsjs.org/docs/controllers * @help :: See http://links.sailsjs.org/docs/controllers
*/ */
module.exports = { module.exports = {
...@@ -61,7 +61,7 @@ module.exports = { ...@@ -61,7 +61,7 @@ module.exports = {
if (bcrypt.compareSync(req.body.password, student.password)) { if (bcrypt.compareSync(req.body.password, student.password)) {
student.isStudent = true; student.isStudent = true;
if (!student.license || !student.license[0]) { if (!student.license || !student.license[0]) {
sails.log.error(`Tried to login with non valid license ${req.body.username}`); sails.log.error('Tried to login with non valid license ${req.body.username}');
res.unauthorized("Student has an invalid license"); res.unauthorized("Student has an invalid license");
} else { } else {
var hasExpired = student.license[0].hasExpired(); var hasExpired = student.license[0].hasExpired();
...@@ -75,17 +75,16 @@ module.exports = { ...@@ -75,17 +75,16 @@ module.exports = {
}); });
} }
} else { } else {
sails.log.error(`Invalid student login: user ${student.username}, password\ sails.log.error('Invalid student login: user ${student.username}, password "${req.body.password}"');
"${req.body.password}"`);
res.unauthorized("Invalid username/password"); res.unauthorized("Invalid username/password");
} }
} else { } else {
sails.log.error(`Tried to login as non-existing student ${req.body.username}`); sails.log.error('Tried to login as non-existing student ${req.body.username}');
res.notFound("Student not found"); res.notFound("Student not found");
} }
}) })
.catch(function (err) { .catch(function (err) {
sails.log.error(`Error getting student ${req.body.username} for login: ` + err); sails.log.error('Error getting student ${req.body.username} for login: ' + err);
res.serverError("Error when connecting to database"); res.serverError("Error when connecting to database");
}); });
}, },
...@@ -148,30 +147,15 @@ module.exports = { ...@@ -148,30 +147,15 @@ module.exports = {
.then(function (stu_sup) { .then(function (stu_sup) {
return stu_sup; return stu_sup;
}) })
.error(err => {throw err}); .catch(function (err) { throw err });
return [student, stu_sup]; return [student, stu_sup];
}) })
.spread(function (student, stu_sup) { .spread(function (student, stu_sup) {
// requester has no relation
student.supervision = -1;
if (!stu_sup && req.token.office && student.office == req.token.office.id && req.token.isSupAdmin)
student.supervision = 0; // requester is admin of the office
else if (stu_sup && !req.token.office)
student.supervision = 1; // requester is tutor of the studend
else if (stu_sup && req.token.office)
student.supervision = 2; // requester is supervisor of student
else if (req.token.isStudent && req.token.id == student.id)
student.supervision = 3 // requester is the student himself
if (student.supervision == -1) // should not hace access!!!
return res.forbidden("Access to this student should not be granted to you");
// Promisify asynchronous call to Student.supervisors // Promisify asynchronous call to Student.supervisors
var supervisors = new Promise(function(resolve, reject) { var supervisors = new Promise(function (resolve, reject) {
Student.supervisors(student.id, (err, ss) => { Student.supervisors(student.id, function (err, ss) {
if (err) return reject(err); if (err) return reject(err);
return resolve(ss); return resolve(ss);
}); });
...@@ -179,10 +163,9 @@ module.exports = { ...@@ -179,10 +163,9 @@ module.exports = {
return [student, supervisors]; return [student, supervisors];
}) })
.spread((student, supervisors) => { .spread(function (student, supervisors) {
student = student.toJSON();
student.supervisors = supervisors; student.supervisors = supervisors;
console.log(JSON.stringify(supervisors));
console.log(JSON.stringify(student.supervisors));
return res.ok(student); return res.ok(student);
}) })
.catch(function (err) { .catch(function (err) {
...@@ -209,10 +192,11 @@ module.exports = { ...@@ -209,10 +192,11 @@ module.exports = {
// License number, if passed is used, otherwise, a trial one is generated // License number, if passed is used, otherwise, a trial one is generated
// //
new Promise(function(resolve, reject) { new Promise(function(resolve, reject) {
if (params.license) if (params.license_number)
resolve(params.license); resolve(params.license_number);
else { else {
License.newTrial(params.id_sup, function(license, err) { License.newTrial(params.id_sup, function(err, license) {
console.log(license.number);
if (err) if (err)
reject(err); reject(err);
else else
...@@ -220,12 +204,13 @@ module.exports = { ...@@ -220,12 +204,13 @@ module.exports = {
}); });
} }
}) })
.then((license) => { .then((license_number) => {
// Check license // Check license
License.isActivable(params.license, function(err) { License.isActivable(license_number, function(err) {
if (err) if (err) {
return res.serverError(err); return res.badRequest(err.message);
}
// Create student // Create student
Student.create(params) Student.create(params)
...@@ -233,22 +218,29 @@ module.exports = { ...@@ -233,22 +218,29 @@ module.exports = {
sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created)); sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created));
// Activate license // Activate license
License.activate(params.license, created.id, function(err, license) { License.activate(license_number, created.id, function(err, license) {
if (err) if (err) {
return res.serverError(err); Student.destroy({id: created.id});
return res.badRequest(err);
}
created = created.toJSON(); created = created.toJSON();
created.license = license.toObject(); created.license = license.toObject();
// Link to supervisor // Link to supervisor
StuSup.create({id_stu: created.id, id_sup: params.id_sup}) StuSup.create({student: created.id, supervisor: params.id_sup})
.then((stu_sup) => { .then((stu_sup) => {
if (!stu_sup) if (!stu_sup) {
throw new Error("Unable to link to supervisor"); Student.destroy({id: created.id});
return res.serverError("Unable to link to supervisor");
}
return res.ok(created); return res.ok(created);
}) })
.catch((err) => {throw err}); .catch((err) => {
}) Student.destroy({id: created.id});
.catch((err) => {throw err}); throw err
});
});
}) })
.catch(function(err) { .catch(function(err) {
sails.log.debug(err.message); sails.log.debug(err.message);
...@@ -256,7 +248,7 @@ module.exports = { ...@@ -256,7 +248,7 @@ module.exports = {
}); });
}); });
}) })
.catch((err) => {res.serverError()}; .catch((err) => {res.serverError(err)});
}, },
/** /**
...@@ -463,83 +455,85 @@ module.exports = { ...@@ -463,83 +455,85 @@ module.exports = {
if (!params.id_sup || !params.id_stu && !params.license) if (!params.id_sup || !params.id_stu && !params.license)
return res.badRequest("Invalid params"); return res.badRequest("Invalid params");
var stu, stuSup;
// //
// Get student ID either because we got it or through a license // Get student ID either because we got it or through a license
// As it can be resolved through two possibilities, better to user promises! // As it can be resolved through two possibilities, better to use promises!
// //
new Promise(funcion(resolve, reject) { var getStudent = new Promise(function(resolve, reject) {
if (!params.id_stu && params.license) { if (!params.id_stu && params.license) {
// get student, license attribute will be completed // get student, license attribute will be completed
License.getStudent(params.license, function(err, stu) { License.getStudent(params.license, function(err, s) {
if (err) if (err)
reject(err); reject(err);
else else
resolve(stu); resolve(s);
}); });
} else } else
Student.findOne(params.id_stu) Student.findOne(params.id_stu)
.populate('license') .populate('license')
.then((stu) => { .then((s) => {
if (!stu) if (!s)
throw new Error("Student not found"); throw new Error("Student not found");
resolve(stu); resolve(s);
}) })
.catch((err) => {reject(err)}); .catch((err) => {reject(err)});
}) });
.then((stu) => {
getStudent
.then((s) => {
stu = s;
// //
// Let's check it is not already linked // Let's check it is not already linked
// //
StuSup.findOne({ student: stu.id, supervisor: params.id_sup }) return StuSup.findOne({ student: stu.id, supervisor: params.id_sup });
.then((stuSup) => { })
// It was already there! .then((ss) => {
if (stuSup)
throw new Error("Already linked"); if (ss)
throw new Error('Student already linked');
//
// Non existing relation, let's create it! return StuSup.create({
// student: stu.id,
else { supervisor: params.id_sup
});
StuSup.create({ })
student: id_stu, .then((ss) => {
supervisor: params.id_sup if (!ss)
}) throw new Error('stusup not created');
.then(function (stuSup) {
if (!stuSup) stuSup = ss;
throw new Error('stusup not created');
//
// // Send sockets messages
// Send sockets messages //
// const socketToOmit = (req.isSocket) ? req.socket : undefined;
const socketToOmit = (req.isSocket) ? req.socket : undefined; const linkSupervisorToStudentEvent = sails.hooks.events.linkSupervisorToStudent(
const linkSupervisorToStudentEvent = sails.hooks.events.linkSupervisorToStudent( stuSup.supervisor,
stuSup.supervisor, stuSup.student
stuSup.student );
); sails.hooks.events.broadcastEvent(
sails.hooks.rooms.supervisor(stuSup.supervisor),
sails.hooks.events.broadcastEvent( linkSupervisorToStudentEvent,
sails.hooks.rooms.supervisor(stuSup.supervisor), socketToOmit
linkSupervisorToStudentEvent, );
socketToOmit sails.hooks.events.broadcastEvent(
); sails.hooks.rooms.student(stuSup.student),
sails.hooks.events.broadcastEvent( linkSupervisorToStudentEvent,
sails.hooks.rooms.student(stuSup.student), socketToOmit
linkSupervisorToStudentEvent, );
socketToOmit
); //
// Done!
// //
// Done! return res.ok(stu);
//
return res.ok(stu);
}
})
.catch((err) => {throw err});
}) })
.catch((err) => { .catch((err) => {
res.serverError(err); console.log("Error " + err.message);
return res.serverError(err);
}); });
}, },
...@@ -1066,7 +1060,7 @@ module.exports = { ...@@ -1066,7 +1060,7 @@ module.exports = {
}) })
.then((student) => { .then((student) => {
if (!student) { if (!student) {
sails.log.error(`Student ${params.id_stu} not found`); sails.log.error('Student ${params.id_stu} not found');
throw new Error("Student not found"); throw new Error("Student not found");
} }
...@@ -1079,7 +1073,7 @@ module.exports = { ...@@ -1079,7 +1073,7 @@ module.exports = {
}) })
.spread((picto, student) => { .spread((picto, student) => {
if (!picto) { if (!picto) {
sails.log.error(`Picto ${params.id_picto} not found`); sails.log.error('Picto ${params.id_picto} not found');
throw new Error("Picto not found"); throw new Error("Picto not found");
} }
......
...@@ -387,7 +387,6 @@ module.exports = { ...@@ -387,7 +387,6 @@ module.exports = {
delete supervisor.password; delete supervisor.password;
if (req.body.password && req.body.password.length > 0) if (req.body.password && req.body.password.length > 0)
supervisor.password = req.body.password; supervisor.password = req.body.password;
console.log(supervisor.password);
supervisor.name = req.body.name || supervisor.name; supervisor.name = req.body.name || supervisor.name;
supervisor.surname = req.body.surname || supervisor.surname; supervisor.surname = req.body.surname || supervisor.surname;
supervisor.gender = req.body.gender || supervisor.gender; supervisor.gender = req.body.gender || supervisor.gender;
......
...@@ -69,18 +69,21 @@ module.exports = { ...@@ -69,18 +69,21 @@ module.exports = {
/** /**
Class methods Class methods
*/ */
hasExpired: function (license) {
return (new Date(license.expiration_ts) - new Date() < 0);
},
/** /**
* Generates a new trial license * Generates a new trial license
* @param {ID} id_sup ID of the supervisor who creates the 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) { newTrial: function(id_sup, callback) {
var now = new Date(); var now = new Date();
License.genLicenseNumber(function(number) { License.genLicenseNumber(function(number) {
if (!number) if (!number)
callback(null, new Error("Unable to generate new license")); callback(new Error("Unable to generate new license"), null);
License.create({ License.create({
type: 'trial', type: 'trial',
...@@ -90,10 +93,10 @@ module.exports = { ...@@ -90,10 +93,10 @@ module.exports = {
}) })
.then((l) => { .then((l) => {
if (!l) throw new Error("Unable to create license"); if (!l) throw new Error("Unable to create license");
callback(l, null); callback(null, l);
}) })
.catch((err) => { .catch((err) => {
callback(null, err); callback(err, null);
}); });
}); });
}, },
...@@ -136,7 +139,7 @@ module.exports = { ...@@ -136,7 +139,7 @@ module.exports = {
callback(license); callback(license);
} }
); );
} },
/** /**
...@@ -148,14 +151,16 @@ module.exports = { ...@@ -148,14 +151,16 @@ module.exports = {
getStudent: function(number, callback) { getStudent: function(number, callback) {
License.findOne({ number: number }) License.findOne({ number: number })
.then((l) => { .then((l) => {
if (!l || !l.activation_ts || !l.id_stu) if (!l || !l.activation_ts || !l.student)
throw new Error("Invalid license: " + number); throw new Error("Invalid license: " + number);
// License ok, check student // License ok, check student
Student.findOne(l.id_stu) Student.findOne(l.student)
.then((s) => { .then((s) => {
if (!s) if (!s)
throw new Error("Student not found"); throw new Error("Student not found");
// convert model to normal object to be able to add attributes
s = s.toJSON();
s.license = l; s.license = l;
callback(null, s); callback(null, s);
}) })
...@@ -176,6 +181,10 @@ module.exports = { ...@@ -176,6 +181,10 @@ module.exports = {
@param {function} callback Callback function with prototype: function(err, license) @param {function} callback Callback function with prototype: function(err, license)
*/ */
activate: function(number, id_stu, callback) { activate: function(number, id_stu, callback) {
if (!number || number.length < 16)
callback(new Error("Invalid license number"));
// Check license // Check license
License.findOne({ number: number }) License.findOne({ number: number })
.then((l) => { .then((l) => {
...@@ -231,6 +240,7 @@ module.exports = { ...@@ -231,6 +240,7 @@ module.exports = {
* Callback function gets instantiated error if not available * Callback function gets instantiated error if not available
*/ */
isActivable: function(number, cb) { isActivable: function(number, cb) {
License.findOne({number: number}) License.findOne({number: number})
.then ((l) => { .then ((l) => {
if (!l) if (!l)
......
...@@ -109,8 +109,12 @@ module.exports = { ...@@ -109,8 +109,12 @@ module.exports = {
toJSON: function () { toJSON: function () {
var student = this.toObject(); var student = this.toObject();
student.pic = sails.config.pictogram.urls.getStudentAvatarUrl(student.pic); 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 = 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); student.attributes = Student.getValidAttributes(student.attributes);
delete student.password; delete student.password;
return student; return student;
...@@ -294,7 +298,8 @@ module.exports = { ...@@ -294,7 +298,8 @@ module.exports = {
if (!stuSups || stuSups.length == 0) if (!stuSups || stuSups.length == 0)
return callback(null, []); 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); return callback(null, sups);
}); });
}, },
...@@ -302,7 +307,6 @@ module.exports = { ...@@ -302,7 +307,6 @@ module.exports = {
// //
// Class method for getting the list of therapists associated to a given // Class method for getting the list of therapists associated to a given
// student // student
// NOTE: A therapist is a supervisor assigned to an office
therapists: function(id_stu, callback) { therapists: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) { StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = []; var l = [];
...@@ -310,18 +314,8 @@ module.exports = { ...@@ -310,18 +314,8 @@ module.exports = {
if (err || !stuSups || stuSups.length == 0) if (err || !stuSups || stuSups.length == 0)
return callback(err, l); return callback(err, l);
async.eachSeries(stuSups, var sups = _.compact(stuSups).filter((st) => {st.supervisor && st.supervisor.role == 'therapist'});
function(stuSup, next) { return callback(null, sups);
// 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);
}
);
}); });
}, },
...@@ -329,7 +323,6 @@ module.exports = { ...@@ -329,7 +323,6 @@ module.exports = {
// //
// Class method for getting the list of tutors associated to a given // Class method for getting the list of tutors associated to a given
// student // student
// NOTE: A tutor is a supervisor not assigned to any office
tutors: function(id_stu, callback) { tutors: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) { StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = []; var l = [];
...@@ -337,18 +330,8 @@ module.exports = { ...@@ -337,18 +330,8 @@ module.exports = {
if (err || !stuSups || stuSups.length == 0) if (err || !stuSups || stuSups.length == 0)
return callback(err, l); return callback(err, l);
async.eachSeries(stuSups, var sups = _.compact(stuSups).filter((st) => {st.supervisor && st.supervisor.role == 'tutor'});
function(stuSup, next) { return callback(null, sups);
// 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);
}
);
}); });
}, },
...@@ -525,7 +508,10 @@ module.exports = { ...@@ -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) { logical_delete: function(id_stu, cb) {
Student.findOne(id_stu).exec(function(err, student) { Student.findOne(id_stu).exec(function(err, student) {
if (err || !student) if (err || !student)
...@@ -533,7 +519,6 @@ module.exports = { ...@@ -533,7 +519,6 @@ module.exports = {
Student.update(id_stu, Student.update(id_stu,
{ {
username: Math.floor((Math.random() * 100000000) + 1) + "_" + student.username, username: Math.floor((Math.random() * 100000000) + 1) + "_" + student.username,
id_off: null
}) })
.then((updated) => { .then((updated) => {
License.destroy({id_stu: id_stu}).exec(cb); License.destroy({id_stu: id_stu}).exec(cb);
......
...@@ -138,7 +138,6 @@ module.exports = { ...@@ -138,7 +138,6 @@ module.exports = {
// //
beforeCreate: function (attrs, next) { beforeCreate: function (attrs, next) {
var async = require('async'); var async = require('async');
console.log("-->\n" + JSON.stringify(attrs));
async.series( async.series(
[ [
function (cb) { function (cb) {
...@@ -241,31 +240,30 @@ module.exports = { ...@@ -241,31 +240,30 @@ module.exports = {
}) })
.spread(function (sup, stuSups) { .spread(function (sup, stuSups) {
async.eachSeries(stuSups, function(stuSup, next_cb) { 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 // set current method and instruction if any
Student.findOne(stuSup.student.id) Student.findOne(stuSup.student.id)
.populate('lastInstruction') .populate('lastInstruction')
.populate('license') .populate('license')
.then(function (s) { .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_method = s.lastInstruction[0] ? s.lastInstruction[0].met_name : "no_method";
s.current_instruction = s.lastInstruction[0] ? s.lastInstruction[0].ins_name : "no_instruction"; s.current_instruction = s.lastInstruction[0] ? s.lastInstruction[0].ins_name : "no_instruction";
if (typeof(s.license[0]) != 'undefined') { if (!s.license)
s.licenseIsValid = new Date(s.license[0].expiration_ts) - new Date() > 0 ? true : false; return next_cb();
s.license = s.license[0];
} else { //
s.licenseIsValid = false; // El alumno tiene licencia, es válida y no es de prueba
s.license = null; //
} if (s.license.isValid || s.license.isOfficial)
s.supervision = sup.office ? 2 : 1; // if Supervisor has office, then is a therapist (2), a tutor (1) otherwise l.push(s);
l.push(s);
next_cb(); next_cb();
}); });
}, },
function (err) { function (err) {
callback(err, l); callback(err, l);
}); });
}) })
.catch((err) => { .catch((err) => {
......
...@@ -17,7 +17,7 @@ module.exports = function isStudentOrSupervisorOfStudent (req, res, next) { ...@@ -17,7 +17,7 @@ module.exports = function isStudentOrSupervisorOfStudent (req, res, next) {
return res.json(401, {error: "This student has no supervisors associated"}); return res.json(401, {error: "This student has no supervisors associated"});
// if supervisor is not in the list of supervisors // 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'}); return res.json(401, {error: 'Access denied 3'});
// Finally, if the user has a clean record, we'll call the `next()` function // 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) { ...@@ -5,17 +5,22 @@ module.exports = function isSupervisorOfStudent(req, res, next) {
if (!req.params.id_stu || !req.token.id) if (!req.params.id_stu || !req.token.id)
return res.json(401, {error: 'Access denied'}); return res.json(401, {error: 'Access denied'});
// Get list of supervisors for the student
Student.supervisors(req.params.id_stu, function(err, sups) { Student.supervisors(req.params.id_stu, function(err, sups) {
if (err || !sups || sups.length == 0) if (err)
return res.json(401, {error: "This student has no supervisors associated"}); 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) // if supervisor is not in the list of supervisors
return next(); // Is Supervisor of Student 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"}); // 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
.catch((err) => { next();
return res.json(401, {error: "Student not found"}); });
});
}; };
...@@ -27,7 +27,7 @@ module.exports = function badRequest(data, options) { ...@@ -27,7 +27,7 @@ module.exports = function badRequest(data, options) {
// Log error to console // Log error to console
if (data !== undefined) { 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'); else sails.log.verbose('Sending 400 ("Bad Request") response');
......
{ {
"account": "Account", "account": "Account",
"account_activate": "The account has been activated", "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_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_therapist": "Manage pictograms, devices, record supervised sessions and get progress reports.",
"account_desc_tutor": "Configure your child's pictograms and his/her communication device.", "account_desc_tutor": "Configure your child's pictograms and his/her communication device.",
...@@ -188,6 +189,7 @@ ...@@ -188,6 +189,7 @@
"keep_strip_and_deliveries": "Keep strip and allow several deliveries", "keep_strip_and_deliveries": "Keep strip and allow several deliveries",
"keep_strip_and_one_delivery": "Keep strip and allow only one delivery", "keep_strip_and_one_delivery": "Keep strip and allow only one delivery",
"language": "Language", "language": "Language",
"language_change_warning": "Your preferred language has been changed. Session restarting is recommended.",
"large": "Large", "large": "Large",
"large_picto": "Large pictograms", "large_picto": "Large pictograms",
"last_session": "Last session", "last_session": "Last session",
...@@ -201,9 +203,12 @@ ...@@ -201,9 +203,12 @@
"licenses": "Licenses", "licenses": "Licenses",
"license_already_activated": "License already activated", "license_already_activated": "License already activated",
"license_created": "License created", "license_created": "License created",
"license_expires": "PRO license expires on ", "license_expired_official": "PRO license expired. To maintain access to therapeutical functionalities you can",
"license_expired": "PRO license expired, 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_expired_renew": "renew it",
"license_expires_official": "PRO license expires on ",
"license_expires_trial": "Trial license expires on ",
"license_invalid": "Invalid license number", "license_invalid": "Invalid license number",
"license_missing": "Account without PRO license", "license_missing": "Account without PRO license",
"license_number": "License number", "license_number": "License number",
...@@ -438,6 +443,7 @@ ...@@ -438,6 +443,7 @@
"tpl_date_frame": "de {{ begin | date:'dd-MM-yyyy' }} a {{ end | date:'dd-MM-yyyy' }}", "tpl_date_frame": "de {{ begin | date:'dd-MM-yyyy' }} a {{ end | date:'dd-MM-yyyy' }}",
"tpl_day": "{{ day | date:'yyyy-MM-dd' }}", "tpl_day": "{{ day | date:'yyyy-MM-dd' }}",
"tpl_hours_frame": "from {{ begin | date:'HH:mm:ss' }} to {{ end | date:'HH:mm:ss' }}", "tpl_hours_frame": "from {{ begin | date:'HH:mm:ss' }} to {{ end | date:'HH:mm:ss' }}",
"trial_license": "Trial license",
"tries": "Tries", "tries": "Tries",
"tries_done": "Tries done", "tries_done": "Tries done",
"tries_length": "Tries length", "tries_length": "Tries length",
......
{ {
"account": "Cuenta", "account": "Cuenta",
"account_activate": "La cuenta ha sido activada", "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_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_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.", "account_desc_therapist": "Gestione pictogramas, dispositivos, grabe sesiones de terapia y obtenga estadísticas de progreso.",
...@@ -188,6 +189,7 @@ ...@@ -188,6 +189,7 @@
"keep_strip_and_deliveries": "Mantener cinta y permitir varias entregas", "keep_strip_and_deliveries": "Mantener cinta y permitir varias entregas",
"keep_strip_and_one_delivery": "Mantener cinta y permitir sólo una entrega", "keep_strip_and_one_delivery": "Mantener cinta y permitir sólo una entrega",
"language": "Idioma", "language": "Idioma",
"language_change_warning": "Ha cambiado el idioma. Se recomienda reiniciar sesión.",
"large": "Grande", "large": "Grande",
"large_picto": "Pictogramas grandes", "large_picto": "Pictogramas grandes",
"last_session": "Última sesión", "last_session": "Última sesión",
...@@ -201,10 +203,13 @@ ...@@ -201,10 +203,13 @@
"licenses": "Licencias", "licenses": "Licencias",
"licenses_left": "{{number}} licencias disponibles", "licenses_left": "{{number}} licencias disponibles",
"license_already_activated": "Licencia ya activada previamente", "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_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_invalid": "Licencia inválida",
"license_number": "Número de licencia", "license_number": "Número de licencia",
"license_pro": "Licencia Pictogram PRO", "license_pro": "Licencia Pictogram PRO",
...@@ -438,6 +443,7 @@ ...@@ -438,6 +443,7 @@
"tpl_date_frame": "de {{ begin | date:'dd-MM-yyyy' }} a {{ end | date:'dd-MM-yyyy' }}", "tpl_date_frame": "de {{ begin | date:'dd-MM-yyyy' }} a {{ end | date:'dd-MM-yyyy' }}",
"tpl_day": "{{ day | 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' }}", "tpl_hours_frame": "de {{ begin | date:'HH:mm:ss' }} a {{ end | date:'HH:mm:ss' }}",
"trial_license": "Licencia de prueba",
"tries": "Ensayos", "tries": "Ensayos",
"tries_done": "Ensayos realizados", "tries_done": "Ensayos realizados",
"tries_length": "Duración ensayos", "tries_length": "Duración ensayos",
......
...@@ -32,10 +32,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl( ...@@ -32,10 +32,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
number: '' number: ''
}, },
license_expired: false, license_expired: false,
office: {
id: '',
name: ''
},
stuSup: [], stuSup: [],
pcb_count: 0, pcb_count: 0,
pdb_count: 1 pdb_count: 1
...@@ -84,7 +80,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl( ...@@ -84,7 +80,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
$scope.studentData.license_expired = new Date($scope.studentData.license.expiration_ts) - new Date() < 0; $scope.studentData.license_expired = new Date($scope.studentData.license.expiration_ts) - new Date() < 0;
moment.locale($translate.use().substr(0, 2)); moment.locale($translate.use().substr(0, 2));
$scope.studentData.expiration_date = moment($scope.studentData.license.expiration_ts).format('L'); $scope.studentData.expiration_date = moment($scope.studentData.license.expiration_ts).format('L');
console.log("updateLicenseExpiration");
}; };
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
...@@ -105,8 +100,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl( ...@@ -105,8 +100,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
$scope.studentData.gender = data.gender; $scope.studentData.gender = data.gender;
$scope.studentData.lang = data.lang; $scope.studentData.lang = data.lang;
$scope.studentData.notes = data.notes; $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.stuSup = data.stuSup;
$scope.studentData.attributes = data.attributes; $scope.studentData.attributes = data.attributes;
$scope.studentData.current_method = data.current_method; $scope.studentData.current_method = data.current_method;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<button class="btn btn-default" btn-radio="'device'" ng-model="section"> <button class="btn btn-default" btn-radio="'device'" ng-model="section">
<i class="fa fa-tablet" aria-hidden="true"></i> {{ 'device' | translate }} <i class="fa fa-tablet" aria-hidden="true"></i> {{ 'device' | translate }}
</button> </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 }} <i class="fa fa-users" aria-hidden="true"></i> {{ 'supervisors' | translate }}
</button> </button>
</div> </div>
...@@ -51,25 +51,42 @@ ...@@ -51,25 +51,42 @@
<label translate>license_number</label> <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> <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 --> <!-- With official license -->
<div ng-show="studentData.license && !studentData.license_expired" class="alert alert-info" role="alert"> <div ng-show="studentData.license && studentData.license.isValid && studentData.license.isOfficial" class="alert alert-info" role="alert">
<div class="row"> <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"> <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> </div>
</div> </div>
<!-- License expired --> <!-- With trial license -->
<div ng-show="studentData.license && studentData.license_expired" class="alert alert-warning" role="alert"> <div ng-show="studentData.license && studentData.license.isValid && studentData.license.isTrial" class="alert alert-info" role="alert">
<div class="row"> <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"> <div class="col-xs-10">
<h4 class="alert-heading"> {{ 'license_expired' | translate }} </h4> {{ 'license_expires_trial' | translate }} <b>{{ studentData.expiration_date }}</b>
<p> </div>
<a href="http://pictogramweb.com/caracteristicas-de-pictogram/">{{ 'license_expired_renew' | translate }}</a> </div>
</p> </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> </div>
</div> </div>
...@@ -312,14 +329,14 @@ ...@@ -312,14 +329,14 @@
<div id="supervisors_section" ng-show="section == 'supervisors'"> <div id="supervisors_section" ng-show="section == 'supervisors'">
<div class="row"> <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 --> <!-- Supervisores (terapeutas) del alumno -->
<div id="student_sups"> <div id="student_sups">
<legend translate>therapists</legend> <legend translate>therapists</legend>
<!-- Buscador de supervisores --> <!-- Buscador de supervisores -->
<p> <p>
<form role="search" ng-submit="search_sup()"> <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> <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"> <div class="input-group-btn">
<button class="btn btn-default" type="submit"> <button class="btn btn-default" type="submit">
...@@ -344,7 +361,7 @@ ...@@ -344,7 +361,7 @@
<!-- Imagen de perfil del supervisor --> <!-- Imagen de perfil del supervisor -->
<img ng-src="{{sup.pic}}" class="profile" alt="" title="" /> <img ng-src="{{sup.pic}}" class="profile" alt="" title="" />
{{sup.name}} {{sup.surname}} {{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> <span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a> </a>
</li> </li>
...@@ -356,12 +373,12 @@ ...@@ -356,12 +373,12 @@
<div class="col-md-5"> <div class="col-md-5">
<!-- Tutores (Padres) --> <!-- Tutores (Padres) -->
<div id="student_tutors" ng-if="studentData.supervision != 1"> <div id="student_tutors" ng-if="user.isOffice">
<legend translate>tutors</legend> <legend translate>tutors</legend>
<!-- Buscador de tutores --> <!-- Buscador de tutores -->
<p> <p>
<form role="search" ng-submit="search_tutor()"> <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> <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"> <div class="input-group-btn">
<button class="btn btn-default" type="submit"> <button class="btn btn-default" type="submit">
...@@ -387,7 +404,7 @@ ...@@ -387,7 +404,7 @@
<!-- Imagen de perfil del tutor --> <!-- Imagen de perfil del tutor -->
<img ng-src="{{tutor.pic}}" class="profile" alt="" title="" /> <img ng-src="{{tutor.pic}}" class="profile" alt="" title="" />
{{tutor.name}} {{tutor.surname}} {{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> <span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a> </a>
</li> </li>
......
...@@ -14,7 +14,8 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -14,7 +14,8 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$translate, $translate,
ngToast, ngToast,
$timeout, $timeout,
IOService) { IOService,
CONSTANTS) {
// Flags for showing buttons according to role // Flags for showing buttons according to role
...@@ -24,9 +25,12 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -24,9 +25,12 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
// Create new account // Create new account
// -------------------------------------------------------- // --------------------------------------------------------
$scope.minlength = CONSTANTS.password_minlength;
var formdata_empty = { var formdata_empty = {
username: '', username: '',
password: '', password: '',
password_confirm: '',
name: $translate.instant('name'), name: $translate.instant('name'),
surname: $translate.instant('surname'), surname: $translate.instant('surname'),
birthdate: Date(), birthdate: Date(),
...@@ -37,7 +41,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -37,7 +41,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
current_method: 'no_method', current_method: 'no_method',
current_instruction: 'no_instruction', current_instruction: 'no_instruction',
license_number: null, license_number: null,
id_sup: -1 id_sup: $scope.user.id
}; };
// Hide new student form // Hide new student form
...@@ -96,10 +100,10 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -96,10 +100,10 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
/** /**
* Add existing account * Add existing account
*/ */
function addExisting () { $scope.addExisting = function () {
// Send link call to server // 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) { .success(function (data) {
ngToast.success({ content: $translate.instant('student_added') }); ngToast.success({ content: $translate.instant('student_added') });
...@@ -117,12 +121,12 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -117,12 +121,12 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
errorMessage = 'license_invalid'; errorMessage = 'license_invalid';
else if (err.message && err.message.search('in use') > 0) else if (err.message && err.message.search('in use') > 0)
errorMessage = 'license_already_activated'; 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'; errorMessage = 'student_already_linked';
else if (err && err.status === 400) else if (err && err.status === 400)
errorMessage = 'invalid_fields'; errorMessage = 'invalid_fields';
ngToast.danger({ content: $translate.instant(errorMessage) }); ngToast.danger($translate.instant(errorMessage));
}); });
} }
...@@ -130,22 +134,19 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -130,22 +134,19 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
/** /**
* Add new account * Add new account
*/ */
function addNew(type) { $scope.addNew = function (type) {
// set language according to interface settings // set language according to interface settings
$scope.formdata.lang = $translate.use(); $scope.formdata.lang = $translate.use();
// Validate password match // Validate password match
if (student.password_confirm.length && student.password !== student.password_confirm) { if ($scope.formdata.password_confirm.length && $scope.formdata.password !== $scope.formdata.password_confirm) {
ngToast.danger({ content: $translate.instant('password_match') }); ngToast.danger($translate.instant('password_match'));
return; 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 // Send creating call to server
$http.post(config.backend + apicall, $scope.formdata) $http.post(config.backend + '/stu', $scope.formdata)
.success(function (data) { .success(function (data) {
ngToast.success({ content: $translate.instant('student_added') }); ngToast.success({ content: $translate.instant('student_added') });
...@@ -159,12 +160,14 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -159,12 +160,14 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$scope.slide.rightTo('confirmation'); $scope.slide.rightTo('confirmation');
}) })
.error(function (err) { .error(function (err) {
console.log(typeof err);
console.log(err);
var errorMessage = 'student_not_added'; 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'; 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'; 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'; errorMessage = 'student_already_exists';
else if (err && err.status === 400) else if (err && err.status === 400)
errorMessage = 'invalid_fields'; errorMessage = 'invalid_fields';
......
...@@ -39,8 +39,9 @@ ...@@ -39,8 +39,9 @@
</div> </div>
</td> </td>
<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.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.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.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>
<td> <td>
<h4>{{student.surname}}, {{student.name}}</h4> <h4>{{student.surname}}, {{student.name}}</h4>
...@@ -52,45 +53,50 @@ ...@@ -52,45 +53,50 @@
<a <a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/collections" 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> <span class="glyphicon glyphicon-th" aria-hidden="true"></span>
</a> </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 <a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/instructions" 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> <span class="glyphicon glyphicon-tasks" aria-hidden="true"></span>
</a> </a>
<span <span
class="btn btn-default btn-lg" role="button" 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 class="glyphicon glyphicon-tasks" aria-hidden="true" style="color: #bbb" ></span>
</span> </span>
<a <a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/session" 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> <span class="glyphicon glyphicon-transfer" aria-hidden="true"></span>
</a> </a>
<span <span
class="btn btn-default btn-lg" role="button" 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 class="glyphicon glyphicon-transfer" aria-hidden="true" style="color: #bbb"></span>
</span> </span>
<a <a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/reports" 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> <i class="fa fa-bar-chart" aria-hidden="true"></i>
</a> </a>
<span class="btn btn-default btn-lg" role="button" <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> <i class="fa fa-bar-chart" aria-hidden="true" style="color: #bbb"></i>
</span> </span>
<a <a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/setup" 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> <span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
</a> </a>
......
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
<div class="col-xs-9"></div> <div class="col-xs-9"></div>
</div> </div>
<form name="AddStudentForm" role="form" ng-submit="add_student()" ng-controller="StudentAddCtrl">
<div class="switch-panel-body height400" ng-switch="slide.state"> <div class="switch-panel-body height400" ng-switch="slide.state">
<!-- <!--
...@@ -96,11 +94,11 @@ ...@@ -96,11 +94,11 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate>password</label> <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> <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>
<div class="form-group"> <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> <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>
<div class="form-group"> <div class="form-group">
...@@ -140,11 +138,11 @@ ...@@ -140,11 +138,11 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate>password</label> <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> <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>
<div class="form-group"> <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> <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>
</div> </div>
...@@ -167,7 +165,7 @@ ...@@ -167,7 +165,7 @@
--> -->
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="confirmation"> <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> <p translate>student_account_confirm</p>
<br> <br>
<img src="img/child.png"/> <img src="img/child.png"/>
...@@ -176,6 +174,4 @@ ...@@ -176,6 +174,4 @@
</div> </div>
</form>
<hr /> <hr />
...@@ -8,6 +8,7 @@ dashboardControllers.controller('TranslateController', function( ...@@ -8,6 +8,7 @@ dashboardControllers.controller('TranslateController', function(
$scope, $scope,
$window, $window,
$http, $http,
$timeout,
config, config,
ngToast, ngToast,
vcRecaptchaService vcRecaptchaService
...@@ -44,7 +45,7 @@ dashboardControllers.controller('TranslateController', function( ...@@ -44,7 +45,7 @@ dashboardControllers.controller('TranslateController', function(
//Server PUT //Server PUT
$http.put(config.backend + '/sup/' + $scope.user.id, { "lang": langKey }) $http.put(config.backend + '/sup/' + $scope.user.id, { "lang": langKey })
.success(function (data) { .success(function (data) {
ngToast.success({ content: $translate.instant('data_saved') }); ngToast.success({ content: $translate.instant('language_change_warning') });
console.log("OK: Update supervisor language"); console.log("OK: Update supervisor language");
}) })
.error(function () { .error(function () {
...@@ -63,7 +64,5 @@ dashboardControllers.controller('TranslateController', function( ...@@ -63,7 +64,5 @@ dashboardControllers.controller('TranslateController', function(
vcRecaptchaService.useLang(0, langKey.substr(0,2)); vcRecaptchaService.useLang(0, langKey.substr(0,2));
} catch (err) {} } catch (err) {}
// Reload page
$window.location.reload();
}; };
}); });
...@@ -83,13 +83,13 @@ module.exports.policies = { ...@@ -83,13 +83,13 @@ module.exports.policies = {
}, },
SceneController:{ SceneController:{
create: ['tokenAuth', 'isSupervisorOfStudent'], create: ['tokenAuth', 'isSupervisorOfStudent'],
update: ['tokenAuth', 'isSupervisorOfStudent'], update: ['tokenAuth', 'isSupervisorOfStudent'],
destroy: ['tokenAuth', 'isSupervisorOfStudent'], destroy: ['tokenAuth', 'isSupervisorOfStudent'],
duplicate: ['tokenAuth', 'isSupervisorOfStudent'], duplicate: ['tokenAuth', 'isSupervisorOfStudent'],
getScene: ['tokenAuth'], getScene: ['tokenAuth'],
getStudentScenes: ['tokenAuth'], getStudentScenes: ['tokenAuth'],
scene: true scene: true
}, },
ServerController: { ServerController: {
...@@ -103,7 +103,7 @@ module.exports.policies = { ...@@ -103,7 +103,7 @@ module.exports.policies = {
supervisors: ['tokenAuth'], supervisors: ['tokenAuth'],
therapists: ['tokenAuth'], therapists: ['tokenAuth'],
tutors: ['tokenAuth'], tutors: ['tokenAuth'],
link_supervisor: ['tokenAuth', 'isOffice'], link_supervisor: ['tokenAuth'],
pictos: ['tokenAuth'], pictos: ['tokenAuth'],
methods: ['tokenAuth'], methods: ['tokenAuth'],
lasttries: ['tokenAuth'], lasttries: ['tokenAuth'],
...@@ -115,7 +115,7 @@ module.exports.policies = { ...@@ -115,7 +115,7 @@ module.exports.policies = {
update_legend: ['tokenAuth'], update_legend: ['tokenAuth'],
update_category: ['tokenAuth', 'isSupervisorOfStudent'], update_category: ['tokenAuth', 'isSupervisorOfStudent'],
login: true, login: true,
create: ['tokenAuth', 'isOffice'], create: ['tokenAuth'],
upload: ['tokenAuth'], upload: ['tokenAuth'],
upload_sound: ['tokenAuth'], upload_sound: ['tokenAuth'],
add_picto: ['tokenAuth', 'isSupervisorOfStudent'], add_picto: ['tokenAuth', 'isSupervisorOfStudent'],
...@@ -125,8 +125,8 @@ module.exports.policies = { ...@@ -125,8 +125,8 @@ module.exports.policies = {
action: true, action: true,
config: true, config: true,
actions_batch: ['tokenAuth'], actions_batch: ['tokenAuth'],
delete: ['tokenAuth', 'isOffice'], delete: ['tokenAuth', 'isAdmin'],
unlink_supervisor: ['tokenAuth', 'isOffice'], unlink_supervisor: ['tokenAuth', 'isSupervisorOfStudent'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent'], delete_picto: ['tokenAuth', 'isSupervisorOfStudent'],
getActiveScene: ['tokenAuth'], getActiveScene: ['tokenAuth'],
getScenes: ['tokenAuth'], getScenes: ['tokenAuth'],
......
...@@ -89,8 +89,8 @@ module.exports.routes = { ...@@ -89,8 +89,8 @@ module.exports.routes = {
'GET /stu/:id_stu/supervisors': 'StudentController.supervisors', 'GET /stu/:id_stu/supervisors': 'StudentController.supervisors',
'GET /stu/:id_stu/therapists': 'StudentController.therapists', 'GET /stu/:id_stu/therapists': 'StudentController.therapists',
'GET /stu/:id_stu/tutors': 'StudentController.tutors', '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/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/pictos': 'StudentController.pictos',
'GET /stu/:id_stu/activeScene': 'StudentController.getActiveScene', 'GET /stu/:id_stu/activeScene': 'StudentController.getActiveScene',
'GET /stu/:id_stu/scenes': 'StudentController.getScenes', 'GET /stu/:id_stu/scenes': 'StudentController.getScenes',
...@@ -108,7 +108,6 @@ module.exports.routes = { ...@@ -108,7 +108,6 @@ module.exports.routes = {
'PUT /stu/:id_stu/activeScene/:id_scene': 'StudentController.updateActiveScene', 'PUT /stu/:id_stu/activeScene/:id_scene': 'StudentController.updateActiveScene',
'POST /stu/login': 'StudentController.login', 'POST /stu/login': 'StudentController.login',
'POST /stu': 'StudentController.create', 'POST /stu': 'StudentController.create',
'POST /stu/license': 'StudentController.createTest',
'POST /stu/upload': 'StudentController.upload', 'POST /stu/upload': 'StudentController.upload',
'POST /stu/:id_stu/upload_sound/:id_picto': 'StudentController.upload_sound', 'POST /stu/:id_stu/upload_sound/:id_picto': 'StudentController.upload_sound',
'POST /stu/:id_stu/picto/:id_picto': 'StudentController.add_picto', '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