license on create student added

parent 77d0cacf
...@@ -140,6 +140,7 @@ CREATE TABLE IF NOT EXISTS `office` ( ...@@ -140,6 +140,7 @@ CREATE TABLE IF NOT EXISTS `office` (
`name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
`logo_url` varchar(240) COLLATE utf8_unicode_ci NOT NULL, `logo_url` varchar(240) COLLATE utf8_unicode_ci NOT NULL,
`address` varchar(180) COLLATE utf8_unicode_ci NOT NULL, `address` varchar(180) COLLATE utf8_unicode_ci NOT NULL,
`postal_code` char(10) COLLATE utf8_unicode_ci NOT NULL,
`country` varchar(2) COLLATE utf8_unicode_ci NOT NULL, `country` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL, `lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`contact_person` varchar(80) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Contact person, main responsible', `contact_person` varchar(80) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Contact person, main responsible',
......
...@@ -13,7 +13,8 @@ INSERT IGNORE INTO `office` ( ...@@ -13,7 +13,8 @@ INSERT IGNORE INTO `office` (
`contact_person`, `contact_person`,
`email`, `email`,
`phone1`, `phone1`,
`lang` `lang`,
`postal_code`
) VALUES ( ) VALUES (
'Asociación Provincial de Autismo de Jaén', 'Asociación Provincial de Autismo de Jaén',
'Avd. de Andalucía, 92 - bajo, 23006 Jaén', 'Avd. de Andalucía, 92 - bajo, 23006 Jaén',
...@@ -21,7 +22,8 @@ INSERT IGNORE INTO `office` ( ...@@ -21,7 +22,8 @@ INSERT IGNORE INTO `office` (
'Belén Pérez Vílchez', 'Belén Pérez Vílchez',
'belen.perez@autismojaen.es', 'belen.perez@autismojaen.es',
'+34 953 236 158', '+34 953 236 158',
'es-es' 'es-es',
'23006'
); );
-- --
......
...@@ -14,7 +14,8 @@ INSERT INTO `office` ( ...@@ -14,7 +14,8 @@ INSERT INTO `office` (
`contact_person`, `contact_person`,
`email`, `email`,
`phone1`, `phone1`,
`lang` `lang`,
`postal_code`
) VALUES ( ) VALUES (
'Comunicación Aumentativa JAén (CAJA)', 'Comunicación Aumentativa JAén (CAJA)',
'Paraje Las Lagunillas, Ed A3, primera plata, 23071. Jaén', 'Paraje Las Lagunillas, Ed A3, primera plata, 23071. Jaén',
...@@ -22,7 +23,8 @@ INSERT INTO `office` ( ...@@ -22,7 +23,8 @@ INSERT INTO `office` (
'Fernando Martínez Santiago', 'Fernando Martínez Santiago',
'dofer@ujaen.es', 'dofer@ujaen.es',
'+34 953 21 28 88', '+34 953 21 28 88',
'es-es' 'es-es',
'23071'
); );
-- --
......
...@@ -5,7 +5,8 @@ INSERT IGNORE INTO `office` ( ...@@ -5,7 +5,8 @@ INSERT IGNORE INTO `office` (
`contact_person`, `contact_person`,
`email`, `email`,
`phone1`, `phone1`,
`lang` `lang`,
`postal_code`
) VALUES ( ) VALUES (
'Centro Destrezas', 'Centro Destrezas',
'Avd. Eduardo García Maroto, 22, 1º Centro - Jaén', 'Avd. Eduardo García Maroto, 22, 1º Centro - Jaén',
...@@ -13,7 +14,8 @@ INSERT IGNORE INTO `office` ( ...@@ -13,7 +14,8 @@ INSERT IGNORE INTO `office` (
'Centro Destrezas', 'Centro Destrezas',
'centrodestrezas@gmail.com', 'centrodestrezas@gmail.com',
'+34 953 043 508', '+34 953 043 508',
'es-es' 'es-es',
'23007'
); );
INSERT IGNORE INTO `supervisor` ( INSERT IGNORE INTO `supervisor` (
......
<<<<<<< HEAD
/* global Student, PictoCore, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails, /* global Student, PictoCore, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails,
Picto */ Picto */
...@@ -56,11 +55,14 @@ module.exports = { ...@@ -56,11 +55,14 @@ module.exports = {
if (bcrypt.compareSync(req.body.password, student.password)) { if (bcrypt.compareSync(req.body.password, student.password)) {
student.isStudent = true; student.isStudent = true;
student.license = student.license[0]; student.license = student.license[0];
res.ok({ if (!student.license || student.license.hasExpired()) {
sails.log.error(`Tried to login with non valid license ${req.body.username}`);
return res.badRequest("Student has an invalid license");
} else
return res.ok({
user: student, user: student,
token: sailsTokenAuth.issueToken(student, sails.config.jwt.expiresInMinutes), token: sailsTokenAuth.issueToken(student, sails.config.jwt.expiresInMinutes),
server_time: (new Date()) server_time: (new Date()).getTime()
.getTime()
}); });
} else { } else {
sails.log.error(`Invalid student login: user ${student.username}, password\ sails.log.error(`Invalid student login: user ${student.username}, password\
...@@ -127,7 +129,7 @@ module.exports = { ...@@ -127,7 +129,7 @@ module.exports = {
// requester has no relation // requester has no relation
student.supervision = -1; student.supervision = -1;
if (!stu_sup && req.token.office && student.office == req.token.office.id) if (!stu_sup && req.token.office && student.office == req.token.office.id && req.token.isSupAdmin)
student.supervision = 0; // requester is admin of the office student.supervision = 0; // requester is admin of the office
else if (stu_sup && !req.token.office) else if (stu_sup && !req.token.office)
student.supervision = 1; // requester is tutor of the studend student.supervision = 1; // requester is tutor of the studend
...@@ -149,10 +151,20 @@ module.exports = { ...@@ -149,10 +151,20 @@ module.exports = {
// //
create: function (req, res) { create: function (req, res) {
var params = req.params.all(); var params = req.params.all();
License.isActivable(params.license_number, function(err) {
if (err)
return res.serverError(err);
Student.create(params) Student.create(params)
.then(function(created) { .then(function(created) {
sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created)); sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created));
License.activate(params.license_number, created.id, function(err, license) {
if (err)
return res.serverError(err);
created = created.toObject();
created.license = license.toObject();
return res.ok(created); return res.ok(created);
});
}) })
.error(function(err) { .error(function(err) {
if (err.message.search("Maximum number of enrolments reached") > 0) { if (err.message.search("Maximum number of enrolments reached") > 0) {
...@@ -167,6 +179,7 @@ module.exports = { ...@@ -167,6 +179,7 @@ module.exports = {
return res.serverError(err.message); return res.serverError(err.message);
} }
}); });
});
}, },
/** /**
...@@ -177,18 +190,11 @@ module.exports = { ...@@ -177,18 +190,11 @@ module.exports = {
*/ */
delete: function (req, res) { delete: function (req, res) {
if (!req.params.id_stu) if (!req.params.id_stu)
return res.json(500, { return res.badRequest('No student defined');
error: 'No student defined'
});
Student.logical_delete(req.params.id_stu, function (err) { Student.logical_delete(req.params.id_stu, function (err) {
if (err) { if (err)
return res.json(500, { return res.serverError(err);
error: err return res.ok({result: 'deleted'});
});
}
return res.json({
result: 'Deleted'
});
}); });
}, },
...@@ -227,8 +233,14 @@ module.exports = { ...@@ -227,8 +233,14 @@ module.exports = {
// delete license attribute as this has been already handled // delete license attribute as this has been already handled
delete stu.license; delete stu.license;
stu.save().then(function (saved) { // delete username, as this should never be updated from requests
res.ok(saved); delete stu.username;
stu.save(function (err) {
if (err)
throw err;
res.ok(stu);
// Send websocket message // Send websocket message
sails.hooks.events.broadcastEvent( sails.hooks.events.broadcastEvent(
...@@ -236,9 +248,6 @@ module.exports = { ...@@ -236,9 +248,6 @@ module.exports = {
sails.hooks.events.updateStudent(stu), sails.hooks.events.updateStudent(stu),
(req.isSocket) ? req.socket : undefined (req.isSocket) ? req.socket : undefined
); );
})
.catch(function(err) {
res.severError();
}); });
}) })
.catch(function (err) { .catch(function (err) {
......
...@@ -462,7 +462,7 @@ module.exports = { ...@@ -462,7 +462,7 @@ module.exports = {
} }
Supervisor.students(req.params.id, function (err, stus) { Supervisor.students(req.params.id, function (err, stus) {
if (err) throw err; if (err) throw err;
return res.json(stus); return res.ok(stus);
}); });
}, },
......
...@@ -52,6 +52,9 @@ module.exports = { ...@@ -52,6 +52,9 @@ module.exports = {
var l = this.toObject(); var l = this.toObject();
delete l.id; delete l.id;
return l; return l;
},
hasExpired: function () {
return (new Date(this.expiration_ts) - new Date() < 0);
} }
}, },
/** /**
...@@ -69,9 +72,9 @@ module.exports = { ...@@ -69,9 +72,9 @@ module.exports = {
License.findOne({ number: number }) License.findOne({ number: number })
.then((l) => { .then((l) => {
if (!l) if (!l)
throw new Error("Invalid license"); throw new Error("Invalid license: " + number);
if (l.activation_ts) if (l.activation_ts)
throw new Error("The license is already active"); throw new Error("License in use");
// License ok, check student // License ok, check student
Student.findOne(id_stu) Student.findOne(id_stu)
...@@ -113,5 +116,21 @@ module.exports = { ...@@ -113,5 +116,21 @@ module.exports = {
.catch((err) => { .catch((err) => {
callback(err, null); callback(err, null);
}); });
},
/**
* Determines whether a license is activable (available) or not
* Callback function gets instantiated error if not available
*/
isActivable: function(number, cb) {
License.findOne({number: number})
.then ((l) => {
if (!l)
throw new Error('Invalid license');
if (l.activation_ts)
throw new Error('License in use');
cb();
})
.catch((err) => {cb(err)});
} }
} }
...@@ -114,6 +114,7 @@ module.exports = { ...@@ -114,6 +114,7 @@ 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)
student.license = student.license[0] ? student.license[0] : null; student.license = student.license[0] ? student.license[0] : null;
student.attributes = Student.getValidAttributes(student.attributes); student.attributes = Student.getValidAttributes(student.attributes);
delete student.password; delete student.password;
...@@ -244,6 +245,7 @@ module.exports = { ...@@ -244,6 +245,7 @@ module.exports = {
beforeCreate: function (attrs, next) { beforeCreate: function (attrs, next) {
attrs.attributes = Student.getValidAttributes(attrs.attributes); attrs.attributes = Student.getValidAttributes(attrs.attributes);
attrs.password = bcrypt.hashSync(attrs.password, bcrypt.genSaltSync()); attrs.password = bcrypt.hashSync(attrs.password, bcrypt.genSaltSync());
attrs.pic = "defaultAvatar.jpg";
next(); next();
}, },
...@@ -255,7 +257,6 @@ module.exports = { ...@@ -255,7 +257,6 @@ module.exports = {
* to the function if necesary) * to the function if necesary)
*/ */
beforeUpdate: function (attrs, next) { beforeUpdate: function (attrs, next) {
delete attrs.username;
attrs.attributes = Student.getValidAttributes(attrs.attributes); attrs.attributes = Student.getValidAttributes(attrs.attributes);
if (attrs.password) { if (attrs.password) {
sails.log.debug('password changed'); sails.log.debug('password changed');
...@@ -512,13 +513,14 @@ module.exports = { ...@@ -512,13 +513,14 @@ module.exports = {
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)
throw err; return cb(new Error("Unable to remove student"));
Student.update(id_stu,
student.office = null; {
student.save(function(err, saved) { username: Math.floor((Math.random() * 100000000) + 1) + "_" + student.username,
if (err) return cb(err); id_off: null
return cb(); })
}); .then((updated) => {cb()})
.catch((err) => {cb(err)});
}); });
} }
}; };
...@@ -209,6 +209,7 @@ module.exports = { ...@@ -209,6 +209,7 @@ module.exports = {
}, },
students: function(id, callback) { students: function(id, callback) {
var l = []; var l = [];
Supervisor.findOne(id) Supervisor.findOne(id)
.populate('office') .populate('office')
...@@ -236,23 +237,22 @@ module.exports = { ...@@ -236,23 +237,22 @@ module.exports = {
if (stuSup.student.office == null) if (stuSup.student.office == null)
next_cb(); next_cb();
var student = stuSup.student; // set current method and instruction if any
student.supervision = sup.office ? 2 : 1; Student.findOne(stuSup.student.id)
.populate('lastInstruction')
// set current methdo and instruction if any .populate('license')
student.current_method = "no_method"; .then(function (s) {
student.current_instruction = "no_instruction"; s.current_method = s.lastInstruction[0] ? s.lastInstruction[0].met_name : "no_method";
VStuLastInstruction.findOne({student: student.id}) s.current_instruction = s.lastInstruction[0] ? s.lastInstruction[0].ins_name : "no_instruction";
.then(function (stu_last_inst) { if (typeof(s.license[0]) != 'undefined') {
if (stu_last_inst) { s.licenseIsValid = new Date(s.license[0].expiration_ts) - new Date() > 0 ? true : false;
student.current_method = stu_last_inst.met_name; s.license = s.license[0];
student.current_instruction = stu_last_inst.ins_name; } else {
s.licenseIsValid = false;
s.license = null;
} }
l.push(student); s.supervision = sup.office ? 2 : 1; // if Supervisor has office, then is a therapist (2), a tutor (1) otherwise
next_cb(); l.push(s);
})
.error(err => {
l.push(student);
next_cb(); next_cb();
}); });
}, },
...@@ -261,12 +261,21 @@ module.exports = { ...@@ -261,12 +261,21 @@ module.exports = {
if (sup.office && sup.office.admin == sup.id) { if (sup.office && sup.office.admin == sup.id) {
var officeStudents; var officeStudents;
Student.find({ office: sup.office.id }).populate('lastInstruction') Student.find({ office: sup.office.id })
.populate('lastInstruction')
.populate('license')
.then(function (officeStudents) { .then(function (officeStudents) {
officeStudents = officeStudents.map((student) => { officeStudents = officeStudents.map((student) => {
student.supervision = student.supervision || 0; student.supervision = 0;
student.current_method = student.lastInstruction[0] ? student.lastInstruction[0].met_name : "no_method"; student.current_method = student.lastInstruction[0] ? student.lastInstruction[0].met_name : "no_method";
student.current_instruction = student.lastInstruction[0] ? student.lastInstruction[0].ins_name : "no_instruction"; student.current_instruction = student.lastInstruction[0] ? student.lastInstruction[0].ins_name : "no_instruction";
if (typeof(student.license[0]) != 'undefined') {
student.licenseIsValid = new Date(student.license[0].expiration_ts) - new Date() > 0 ? true : false;
student.license = student.license[0];
} else {
student.licenseIsValid = false;
student.license = null;
}
return student; return student;
}); });
l = l.concat(officeStudents); l = l.concat(officeStudents);
......
/* global sails, Student */
module.exports = function isSupervisorOfStudentOrIsSupAdmin(req, res, next) {
const supervisorId = req.token.id;
const studentId = req.params.id_stu;
if (!studentId || !supervisorId) {
sails.log.error('This request needs an id_stu parameter and a authenticated supervisor');
res.json(401, { error: 'Access denied' });
} else {
Student.findOne(studentId)
.then(function (s) {
if (s.office == req.token.office.id && req.token.isSupAdmin) {
next();
}
else {
Student.supervisors(studentId, function (err, sups) {
const studentSupervisorsIds = sups.map((studentSupervisor) => studentSupervisor.id);
if (err || studentSupervisorsIds.length === 0) {
sails.log.error(`Student ${studentId} has no supervisor assigned`);
res.json(401, { error: 'Access denied' });
} else if (studentSupervisorsIds.indexOf(supervisorId) < 0) {
sails.log.error(`Supervisor ${supervisorId} is not assigned to Student ${studentId}`);
sails.log.debug(`Student supervisors: ${studentSupervisorsIds}`);
res.json(401, { error: 'Access denied' });
} else {
sails.log.debug(`Supervisor ${supervisorId} is assigned to Student ${studentId}`);
next();
}
});
}
});
}
};
...@@ -24,7 +24,7 @@ module.exports = function serverError (data, options) { ...@@ -24,7 +24,7 @@ module.exports = function serverError (data, options) {
// Log error to console // Log error to console
if (data !== undefined) { if (data !== undefined) {
sails.log.error('Sending 500 ("Server Error") response: \n',data); sails.log.error('Sending 500 ("Server Error") response: \n', JSON.stringify(data));
} }
else sails.log.error('Sending empty 500 ("Server Error") response'); else sails.log.error('Sending empty 500 ("Server Error") response');
...@@ -74,4 +74,3 @@ module.exports = function serverError (data, options) { ...@@ -74,4 +74,3 @@ module.exports = function serverError (data, options) {
}); });
}; };
...@@ -139,6 +139,7 @@ ...@@ -139,6 +139,7 @@
"license_already_activated": "License already activated", "license_already_activated": "License already activated",
"license_created": "License created", "license_created": "License created",
"license_expires": "License expires on ", "license_expires": "License expires on ",
"license_expired": "License expired on ",
"license_invalid": "Invalid license number", "license_invalid": "Invalid license number",
"licenses_left": "{{number}} licenses left", "licenses_left": "{{number}} licenses left",
"license_missing": "Account without license", "license_missing": "Account without license",
...@@ -293,12 +294,12 @@ ...@@ -293,12 +294,12 @@
"supervisor_not_updated": "Supervisor not updated", "supervisor_not_updated": "Supervisor not updated",
"supervisor_note": "If the parent aren't going to register in the platform, the administrator can use the notes field to store their information.", "supervisor_note": "If the parent aren't going to register in the platform, the administrator can use the notes field to store their information.",
"supervisor_updated": "Supervisor updated", "supervisor_updated": "Supervisor updated",
"supervisors": "Therapist", "supervisors": "Supervisors",
"supervisors_setup": "Supervisors",
"surname": "Surname", "surname": "Surname",
"tag_deleted": "Tag deleted", "tag_deleted": "Tag deleted",
"tape_background": "Tape background", "tape_background": "Tape background",
"template_deleted": "Template deleted", "template_deleted": "Template deleted",
"therapists": "Therapists",
"time_hours": "Time: {{hours}} hours", "time_hours": "Time: {{hours}} hours",
"time_instruction_method": "Time instructions of method", "time_instruction_method": "Time instructions of method",
"time_sessions_total": "Total sessions time", "time_sessions_total": "Total sessions time",
......
...@@ -139,6 +139,7 @@ ...@@ -139,6 +139,7 @@
"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 expira el ", "license_expires": "La licencia expira el ",
"license_expired": "La licencia expiró el ",
"license_created": "Licencia creada", "license_created": "Licencia creada",
"license_invalid": "Licencia inválida", "license_invalid": "Licencia inválida",
"license_number": "Número de licencia", "license_number": "Número de licencia",
...@@ -294,8 +295,8 @@ ...@@ -294,8 +295,8 @@
"supervisor_not_updated": "El supervisor no se ha podido actualizar", "supervisor_not_updated": "El supervisor no se ha podido actualizar",
"supervisor_note": "Si los padres no se van a dar de alta en la plataforma nunca, el administrador puede anotar la información de contacto en el campo notas.", "supervisor_note": "Si los padres no se van a dar de alta en la plataforma nunca, el administrador puede anotar la información de contacto en el campo notas.",
"supervisor_updated": "Supervisor actualizado", "supervisor_updated": "Supervisor actualizado",
"supervisors": "Terapeutas", "therapists": "Terapeutas",
"supervisors_setup": "Supervisores", "supervisors": "Supervisores",
"surname": "Apellidos", "surname": "Apellidos",
"tag_deleted": "Etiqueta borrada", "tag_deleted": "Etiqueta borrada",
"tape_background": "Fondo de la cinta", "tape_background": "Fondo de la cinta",
......
...@@ -125,10 +125,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl( ...@@ -125,10 +125,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
$scope.formUser.username = data.username; $scope.formUser.username = data.username;
$scope.formUser.license_number = data.license ? data.license.number : ''; $scope.formUser.license_number = data.license ? data.license.number : '';
$scope.studentData.license = data.license ? data.license : null; $scope.studentData.license = data.license ? data.license : null;
if (data.license) { $scope.updateLicenseExpiration();
moment.locale($translate.use().substr(0, 2));
$scope.expiration_date = moment($scope.studentData.license.expiration_ts).format('L');
}
// websocket emit update action // websocket emit update action
delete data.license; delete data.license;
...@@ -141,7 +138,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl( ...@@ -141,7 +138,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
console.log(err); console.log(err);
if (err.message.search('nvalid license')) if (err.message.search('nvalid license'))
ngToast.danger({ content: $translate.instant('license_invalid') }); ngToast.danger({ content: $translate.instant('license_invalid') });
else if (err.message.search('is already active')) else if (err.message.search('in use'))
ngToast.danger({ content: $translate.instant('license_already_activated') }); ngToast.danger({ content: $translate.instant('license_already_activated') });
else else
ngToast.danger({ content: $translate.instant('student_not_updated') }); ngToast.danger({ content: $translate.instant('student_not_updated') });
......
...@@ -77,6 +77,15 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl( ...@@ -77,6 +77,15 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
}); });
}); });
$scope.updateLicenseExpiration = function () {
if (!$scope.studentData.license)
return;
$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');
};
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// //
// Load student account information // Load student account information
...@@ -103,6 +112,8 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl( ...@@ -103,6 +112,8 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
$scope.studentData.current_instruction = data.current_instruction; $scope.studentData.current_instruction = data.current_instruction;
$scope.studentData.supervision = data.supervision; // supervision level on student: 0->admin, 1->tutor, 2->therapist $scope.studentData.supervision = data.supervision; // supervision level on student: 0->admin, 1->tutor, 2->therapist
$scope.studentData.license = data.license; $scope.studentData.license = data.license;
$scope.updateLicenseExpiration();
// Setup section: Fill formUser (data able to be modified) from studentData parent object // Setup section: Fill formUser (data able to be modified) from studentData parent object
// It must go here to assign the values when studentData is recovered // It must go here to assign the values when studentData is recovered
...@@ -117,8 +128,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl( ...@@ -117,8 +128,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
$scope.formUser.notes = $scope.studentData.notes; $scope.formUser.notes = $scope.studentData.notes;
if ($scope.studentData.license) { if ($scope.studentData.license) {
$scope.formUser.license_number = $scope.studentData.license.number; $scope.formUser.license_number = $scope.studentData.license.number;
moment.locale($translate.use().substr(0, 2));
$scope.expiration_date = moment($scope.studentData.license.expiration_ts).format('L');
} }
// Subscribe to student's socket room // Subscribe to student's socket room
......
...@@ -37,11 +37,14 @@ ...@@ -37,11 +37,14 @@
<div class="form-group"> <div class="form-group">
<input type="text" id="setup_license" mask="9999-9999-9999-9999" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formUser.license_number" required> <input type="text" id="setup_license" mask="9999-9999-9999-9999" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formUser.license_number" required>
<br/> <br/>
<span ng-show="studentData.license" class="text-info"> <span ng-show="studentData.license && !studentData.license_expired" class="text-info">
({{ 'license_expires' | translate }} {{ expiration_date }}) ({{ 'license_expires' | translate }} {{ studentData.expiration_date }})
</span>
<span ng-show="studentData.license && studentData.license_expired" class="text-danger">
({{ 'license_expired' | translate }} {{ studentData.expiration_date }})
</span> </span>
<span ng-show="!studentData.license" class="text-danger"> <span ng-show="!studentData.license" class="text-danger">
{{ 'license_missing' | translate }} ({{ 'license_missing' | translate }})
</span> </span>
</div> </div>
</fieldset> </fieldset>
...@@ -352,11 +355,11 @@ ...@@ -352,11 +355,11 @@
<h3>{{ 'supervisors' | translate }}</h3> <h3>{{ 'supervisors' | translate }}</h3>
<!-- Supervisores (terapeutas) del alumno --> <!-- Supervisores (terapeutas) del alumno -->
<div id="student_sups" ng-if="studentData.supervision != 1"> <div id="student_sups" ng-if="studentData.supervision != 1">
<legend translate>supervisors_setup</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"> <div class="input-group" ng-if="user.isSupAdmin">
<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">
...@@ -381,7 +384,7 @@ ...@@ -381,7 +384,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-click="delete_sup(sup.id)" class="delete_sup" title="{{ 'unlink' | translate}}"> <a ng-if="user.isSupAdmin" 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>
...@@ -396,7 +399,7 @@ ...@@ -396,7 +399,7 @@
<!-- 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"> <div class="input-group" ng-if="user.isSupAdmin">
<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">
...@@ -422,7 +425,7 @@ ...@@ -422,7 +425,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-click="delete_tutor(tutor.id)" class="delete_tutor" title="{{ 'unlink' | translate}}"> <a ng-if="user.isSupAdmin" 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>
......
...@@ -20,8 +20,8 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -20,8 +20,8 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
name: '', name: '',
surname: '', surname: '',
birthdate: '', birthdate: '',
country: '', country: 'ES',
gender: 'F', gender: 'M',
lang: 'es-es', lang: 'es-es',
notes: '', notes: '',
pic: 'defaultAvatar.jpg', pic: 'defaultAvatar.jpg',
...@@ -74,13 +74,14 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -74,13 +74,14 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
name: '', name: '',
surname: '', surname: '',
birthdate: '', birthdate: '',
country: '', country: 'ES',
gender: 'F', gender: 'M',
lang: 'es-es', lang: 'es-es',
notes: '', notes: '',
office: $scope.user.office || { name: '' }, office: $scope.user.office || { name: '' },
current_method: 'no_method', current_method: 'no_method',
current_instruction: 'no_instruction' current_instruction: 'no_instruction',
license_number: ''
}; };
// Hide the form // Hide the form
...@@ -114,33 +115,24 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -114,33 +115,24 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
data.current_method = $translate.instant('no_method'); data.current_method = $translate.instant('no_method');
data.current_instruction = $translate.instant('no_instruction'); data.current_instruction = $translate.instant('no_instruction');
// Add to the list of students in view
$scope.students.push(data); $scope.students.push(data);
// Delete the fields of the form to avoid data binding
// between the new element created and the form fields
$scope.resetForm(); $scope.resetForm();
// Hide the add form to new adding
$scope.hidestudentadd = true; $scope.hidestudentadd = true;
// Update counters
$scope.user.office.currentStudents += 1;
$scope.num_licenses_left -= 1;
}) })
.error(function (err) { .error(function (err) {
var errorMessage = 'student_not_added'; var errorMessage = 'student_not_added';
console.log(err); if (err.message && err.message.search('nvalid license') > 0)
if (typeof err == "string" && err.search("Maximum number of enrolments reached") > 0) errorMessage = 'license_invalid';
else if (err.message && err.message.search('in use') > 0)
errorMessage = 'license_already_activated';
else if (typeof err == "string" && err.search("Maximum number of enrolments reached") > 0)
errorMessage = 'max_licenses_reached'; errorMessage = 'max_licenses_reached';
if (typeof err == "string" && err.search("already exists") > 0) else if (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';
ngToast.danger({ content: $translate.instant(errorMessage) }); ngToast.danger({ content: $translate.instant(errorMessage) });
$scope.hidestudentadd = true;
}); });
}; };
...@@ -148,8 +140,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -148,8 +140,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
* Delete Student * Delete Student
*/ */
$scope.delete_student = function (student) { $scope.delete_student = function (student) {
$translate('confirmation').then(t => { if ($window.confirm($translate.instant('confirmation'))) {
if ($window.confirm(t))
$http.delete(config.backend + '/stu/' + student.id) $http.delete(config.backend + '/stu/' + student.id)
.success(function () { .success(function () {
var i; var i;
...@@ -158,22 +149,16 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -158,22 +149,16 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$scope.students.splice(i, 1); $scope.students.splice(i, 1);
} }
} }
$translate('student_deleted').then(function (translation) { ngToast.success({ content: $translate.instant('student_deleted') });
ngToast.success({ content: translation });
});
IOService.post('/stu/unsubscribe', { IOService.post('/stu/unsubscribe', {
action: 'unsubscribe' action: 'unsubscribe'
}); });
// Update counters
$scope.user.office.currentStudents -= 1;
$scope.num_licenses_left += 1;
}) })
.error(function () { .error(function () {
ngToast.danger({ content: $translate.instant('student_not_deleted') }); ngToast.danger({ content: $translate.instant('student_not_deleted') });
}); });
}); }
}; };
// When a new student is added to the supervisor, we should update // When a new student is added to the supervisor, we should update
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
<!-- Fin .panel-body --> <!-- Fin .panel-body -->
<!-- Table --> <!-- Table -->
<div ng-show="students.length == 0">
{{ no_students_for_user | translate }}
</div>
<table id="table_students" class="table table-hover"> <table id="table_students" class="table table-hover">
<tr ng-repeat="student in students | filter:search_students | orderBy: ['surname', 'name']"> <tr ng-repeat="student in students | filter:search_students | orderBy: ['surname', 'name']">
<td> <td>
...@@ -36,6 +39,9 @@ ...@@ -36,6 +39,9 @@
</div> </div>
</td> </td>
<td> <td>
<span ng-show="!student.licenseIsValid" class="license-warning text-danger glyphicon glyphicon-warning-sign" aria-hidden="true" popover="{{ 'license_invalid' | translate}}" popover-trigger="mouseenter"></span>
</td>
<td>
<h4>{{student.surname}}, {{student.name}}</h4> <h4>{{student.surname}}, {{student.name}}</h4>
</td> </td>
<td> <td>
...@@ -43,7 +49,6 @@ ...@@ -43,7 +49,6 @@
</td> </td>
<td> <!-- BUTTONS --> <td> <!-- BUTTONS -->
<a class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/collections" alt="{{ 'collections' | translate}}" popover="{{ 'collections' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision != 0"><span class="glyphicon glyphicon-th" aria-hidden="true"></span></a> <a class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/collections" alt="{{ 'collections' | translate}}" popover="{{ 'collections' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision != 0"><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.supervision == 0"><span class="glyphicon glyphicon-th" style="color: #bbb" aria-hidden="true"></span></span> <span class="btn btn-default btn-lg" role="button" alt="{{ 'collections' | translate}}" popover="{{ 'collections' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision == 0"><span class="glyphicon glyphicon-th" style="color: #bbb" aria-hidden="true"></span></span>
...@@ -65,7 +70,7 @@ ...@@ -65,7 +70,7 @@
</td> <!-- /BUTTONS --> </td> <!-- /BUTTONS -->
<td> <td>
<a ng-click="delete_student(student)" class="delete_stu" title="{{ 'delete' | translate}}"> <a ng-if="user.isSupAdmin" ng-click="delete_student(student)" class="delete_stu" title="{{ 'delete' | 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>
</td> </td>
......
...@@ -18,6 +18,22 @@ ...@@ -18,6 +18,22 @@
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" ng-model="formdatastudent.password_confirm" /> <input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" ng-model="formdatastudent.password_confirm" />
</div> </div>
<div class="form-group">
{{ 'language' | translate }}: <select class="form-control" name="student_language" id="student_language" ng-model="formdatastudent.lang">
<option value="es-es" selected>Español</option>
<option value="en-us">English</option>
</select>
</div>
<div class="form-group">
<input type="text" id="student_license" mask="9999-9999-9999-9999" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formdatastudent.license_number" required>
</div>
</div>
<div class="col-sm-6">
<legend translate>personal_data</legend> <legend translate>personal_data</legend>
<div class="form-group"> <div class="form-group">
...@@ -28,6 +44,9 @@ ...@@ -28,6 +44,9 @@
<input type="text" class="form-control" id="student_surname" placeholder="{{ 'surname' | translate }}" required ng-model="formdatastudent.surname" /> <input type="text" class="form-control" id="student_surname" placeholder="{{ 'surname' | translate }}" required ng-model="formdatastudent.surname" />
</div> </div>
<div class="row">
<div class="col-sm-6">
<div class="form-group"> <div class="form-group">
<p class="input-group"> <p class="input-group">
<input type="text" class="form-control" datepicker-popup="{{ 'day_format' | translate }}" ng-model="formdatastudent.birthdate" placeholder="{{ 'birthdate' | translate }}" is-open="opened_cal_student" close-text="{{'close' | translate}}" required /> <input type="text" class="form-control" datepicker-popup="{{ 'day_format' | translate }}" ng-model="formdatastudent.birthdate" placeholder="{{ 'birthdate' | translate }}" is-open="opened_cal_student" close-text="{{'close' | translate}}" required />
...@@ -36,16 +55,20 @@ ...@@ -36,16 +55,20 @@
</span> </span>
</p> </p>
</div> </div>
</div>
<div class="col-sm-6">
<div class="form-group"> <div class="form-group">
<select class="form-control" name="student_gender" id="student_gender" ng-model="formdatastudent.gender" required> <select class="form-control" name="student_gender" id="student_gender" ng-model="formdatastudent.gender" required>
<option value="F" selected translate>woman</option> <option value="F" selected translate>woman</option>
<option value="M" translate>man</option> <option value="M" translate>man</option>
</select> </select>
</div> </div>
</div>
</div>
<div class="form-group"> <div class="form-group">
<legend translate>country</legend> <span translate>country</span>:
<select class="form-control" name="student_country" id="student_country" ng-model="formdatastudent.country" required> <select class="form-control" name="student_country" id="student_country" ng-model="formdatastudent.country" required>
<option value="ES" selected>España</option> <option value="ES" selected>España</option>
<option value="US">United States</option> <option value="US">United States</option>
...@@ -53,26 +76,7 @@ ...@@ -53,26 +76,7 @@
<option value="IE">Ireland</option> <option value="IE">Ireland</option>
</select> </select>
</div> </div>
</fieldset>
</div>
<div class="col-sm-6">
<fieldset>
<legend translate>language</legend>
<div class="form-group">
<select class="form-control" name="student_language" id="student_language" ng-model="formdatastudent.lang">
<option value="es-es" selected>Español</option>
<option value="en-us">English</option>
</select>
</div>
</fieldset>
<fieldset>
<legend translate>notes</legend>
<div class="form-group">
<textarea class="form-control" name="student_notes" id="student_notes" ng-model="formdatastudent.notes" rows="5"></textarea>
</div>
</fieldset>
</div> </div>
</div> </div>
<!-- Fin de row --> <!-- Fin de row -->
......
...@@ -774,7 +774,7 @@ img.profile{ ...@@ -774,7 +774,7 @@ img.profile{
margin-top: 4px; margin-top: 4px;
} }
.delete_stu{ .delete_stu, .license-warning{
font-size: 24px; font-size: 24px;
margin-top: 10px; margin-top: 10px;
} }
......
...@@ -83,12 +83,12 @@ module.exports.policies = { ...@@ -83,12 +83,12 @@ module.exports.policies = {
StudentController: { StudentController: {
eternal: true, eternal: true,
getInfo: ['tokenAuth'], getInfo: ['tokenAuth', 'isSupervisorOfStudentOrIsSupAdmin'],
supervisors: ['tokenAuth'], supervisors: ['tokenAuth'],
therapists: ['tokenAuth'], therapists: ['tokenAuth'],
tutors: ['tokenAuth'], tutors: ['tokenAuth'],
link_supervisor: ['tokenAuth'], link_supervisor: ['tokenAuth', 'isSupAdmin'],
pictos: ['tokenAuth'], pictos: ['tokenAuth', 'isSupervisorOfStudent'],
methods: ['tokenAuth'], methods: ['tokenAuth'],
lasttries: ['tokenAuth'], lasttries: ['tokenAuth'],
tries: ['tokenAuth'], tries: ['tokenAuth'],
...@@ -98,7 +98,7 @@ module.exports.policies = { ...@@ -98,7 +98,7 @@ module.exports.policies = {
update_picto: ['tokenAuth', 'isSupervisorOfStudent'], update_picto: ['tokenAuth', 'isSupervisorOfStudent'],
update_legend: ['tokenAuth'], update_legend: ['tokenAuth'],
login: true, login: true,
create: ['tokenAuth'], create: ['tokenAuth', 'isSupAdmin'],
upload: ['tokenAuth'], upload: ['tokenAuth'],
add_picto: ['tokenAuth', 'isSupervisorOfStudent'], add_picto: ['tokenAuth', 'isSupervisorOfStudent'],
subscribe: ['tokenAuth'], subscribe: ['tokenAuth'],
...@@ -107,8 +107,8 @@ module.exports.policies = { ...@@ -107,8 +107,8 @@ module.exports.policies = {
action: true, action: true,
config: true, config: true,
actions_batch: ['tokenAuth'], actions_batch: ['tokenAuth'],
delete: ['tokenAuth'], delete: ['tokenAuth', 'isSupAdmin'],
unlink_supervisor: ['tokenAuth'], unlink_supervisor: ['tokenAuth', 'isSupAdmin'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent'] delete_picto: ['tokenAuth', 'isSupervisorOfStudent']
}, },
......
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