Commit 5413736a by Fernando Martínez Santiago

Merge branch 'develop' of http://scm.ujaen.es/softuno/pictogram into develop

parents 6b6c2ff8 51c69a8d
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<item name="darkpurple" type="color">#FF9933CC</item> <item name="darkpurple" type="color">#FF9933CC</item>
<item name="darkgreen" type="color">#669900</item> <item name="darkgreen" type="color">#669900</item>
<item name="darkorange" type="color">#FFFF8800</item> <item name="darkorange" type="color">#FFFF8800</item>
<item name="darkred" type="color">#FFCC0000</item> <item name="darkred" type="color">#cc0000</item>
<integer-array name="androidcolors"> <integer-array name="androidcolors">
<item>@color/blue</item> <item>@color/blue</item>
......
...@@ -3,12 +3,15 @@ package com.yottacode.pictogram.tabletlibrary.gui; ...@@ -3,12 +3,15 @@ package com.yottacode.pictogram.tabletlibrary.gui;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.Window; import android.view.Window;
import android.view.WindowManager;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout;
import com.yottacode.pictogram.dao.UserLogin; import com.yottacode.pictogram.dao.UserLogin;
import com.yottacode.pictogram.tabletlibrary.R; import com.yottacode.pictogram.tabletlibrary.R;
...@@ -52,7 +55,8 @@ public class SerialActivity extends Activity { ...@@ -52,7 +55,8 @@ public class SerialActivity extends Activity {
requestWindowFeature(Window.FEATURE_NO_TITLE); requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_serial); setContentView(R.layout.activity_serial);
//Initial keyboard hide
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
final EditText mSerialViewMail = (EditText) findViewById(R.id.serialmail); final EditText mSerialViewMail = (EditText) findViewById(R.id.serialmail);
final EditText mSerialViewPass = (EditText) findViewById(R.id.serialpass); final EditText mSerialViewPass = (EditText) findViewById(R.id.serialpass);
...@@ -65,6 +69,29 @@ public class SerialActivity extends Activity { ...@@ -65,6 +69,29 @@ public class SerialActivity extends Activity {
mSerialViewMail.setText(username); mSerialViewMail.setText(username);
mSerialViewPass.setText(password); mSerialViewPass.setText(password);
final LinearLayout stuList = (LinearLayout) findViewById(R.id.stuLay);
final LinearLayout supList = (LinearLayout) findViewById(R.id.supLay);
mSerialViewMail.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view,boolean hasFocus) {
if(hasFocus){
stuList.setVisibility(View.INVISIBLE);
supList.setVisibility(View.INVISIBLE);
}
}
});
mSerialViewPass.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view,boolean hasFocus) {
if(hasFocus){
stuList.setVisibility(View.INVISIBLE);
supList.setVisibility(View.INVISIBLE);
}
}
});
// Escribo el último valor indicado de username // Escribo el último valor indicado de username
......
...@@ -10,17 +10,15 @@ ...@@ -10,17 +10,15 @@
android:paddingTop="@dimen/activity_vertical_margin" android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".gui.SerialActivity"> tools:context=".gui.SerialActivity">
<EditText <ImageView
android:id="@+id/serialmail" android:layout_width="200px"
android:layout_width="400px" android:layout_height="120px"
android:layout_height="wrap_content" android:layout_marginLeft="30px"
android:hint="@string/prompt_serial_mail" android:orientation="horizontal"
android:imeActionId="@+id/login" android:src="@drawable/pictogram_logo"
android:imeOptions="actionUnspecified" android:id="@+id/imageView"
android:inputType="text" android:layout_alignParentTop="true"
android:maxLines="1" android:layout_toEndOf="@+id/serialmail" />
android:singleLine="true"
android:layout_alignParentTop="true" />
<EditText <EditText
android:id="@+id/serialpass" android:id="@+id/serialpass"
...@@ -34,28 +32,91 @@ ...@@ -34,28 +32,91 @@
android:maxLines="1" android:maxLines="1"
android:singleLine="true" android:singleLine="true"
android:layout_below="@+id/serialmail" android:layout_below="@+id/serialmail"
/> android:layout_toStartOf="@+id/imageView" />
<Button <Button
android:id="@+id/entrar_button" style="?android:textAppearanceSmall" android:id="@+id/entrar_button" style="?android:textAppearanceSmall"
android:layout_width="400px" android:layout_width="400px"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="11dp"
android:text="@string/action_entrar" android:text="@string/action_entrar"
android:textStyle="bold" android:textStyle="bold"
android:layout_below="@+id/serialpass"/> android:layout_below="@+id/serialpass"
android:layout_alignStart="@+id/serialpass" />
<ImageView <View
android:layout_width="200px" android:layout_width="match_parent"
android:layout_height="120px" android:layout_height="1dp"
android:layout_marginLeft="30px" android:background="@android:color/darker_gray"
android:orientation="horizontal" android:layout_below="@+id/entrar_button"
android:src="@drawable/pictogram_logo" android:layout_alignParentEnd="true"
android:layout_centerHorizontal="true" android:layout_marginEnd="18dp" />
android:id="@+id/imageView"
android:layout_toRightOf="@+id/serialmail" <EditText
android:layout_alignParentTop="true"/> android:id="@+id/serialmail"
android:layout_width="400px"
android:layout_height="wrap_content"
android:hint="@string/prompt_serial_mail"
android:imeActionId="@+id/login"
android:imeOptions="actionUnspecified"
android:inputType="text"
android:maxLines="1"
android:layout_marginStart="212dp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
<LinearLayout
android:orientation="vertical"
android:background="@color/blue"
android:layout_height="350px"
android:layout_width="400px"
android:layout_alignParentBottom="true"
android:layout_alignStart="@+id/entrar_button"
android:layout_marginStart="270dp"
android:id="@+id/supLay">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/labelSup"
tools:text="Supervisores"
android:text="@string/supervisores"
android:textAppearance="@style/TextAppearance.AppCompat"
android:textAlignment="center"
android:textSize="18sp" />
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/supList" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_height="350px"
android:layout_marginStart="67dp"
android:background="@color/darkred"
android:layout_width="400px"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:id="@+id/stuLay">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/labelStu"
tools:text="Alumnos"
android:text="@string/alumnos"
android:textAppearance="@style/TextAppearance.AppCompat"
android:textAlignment="center"
android:textSize="18sp" />
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/stuList" />
</LinearLayout>
</RelativeLayout> </RelativeLayout>
......
<resources> <resources>
<string name="app_name">com.yottacode.pictogram.Tablet</string> <string name="app_name">com.yottacode.pictogram.Tablet</string>
<string name="alumnos">Alumnos</string>
<string name="supervisores">Supervisores</string>
<item name="maxInTape" type="integer">8</item> <item name="maxInTape" type="integer">8</item>
<item name="maxInTape_big" type="integer">6</item> <item name="maxInTape_big" type="integer">6</item>
......
/* global Student, PictoCore, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails, /* global Student, PictoCore, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails,
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 = {
// dummy function to test timeouts // dummy function to test timeouts
eternal: function (req, res) { eternal: function (req, res) {
setTimeout(function(){return;}, 1000*60*6); setTimeout(function(){return;}, 1000*60*6);
}, },
/** /**
* Login in the server as student, getting a toker for interacting with the platform * Login in the server as student, getting a toker for interacting with the platform
* @param {request} req * @param {request} req
* { * {
* username: 'johnydoe', * username: 'johnydoe',
* password: '12312' * password: '12312'
* } * }
* @param {response} res * @param {response} res
* { * {
* user: { * user: {
* id: 12, * id: 12,
* office: 1234, * office: 1234,
* username: 'johnydoe', * username: 'johnydoe',
* name: 'Johny', * name: 'Johny',
* surname: 'Doe', * surname: 'Doe',
* birthdate: '2009-12-10T00:00:00.000Z', * birthdate: '2009-12-10T00:00:00.000Z',
* gender: 'F', * gender: 'F',
* country: 'ES', * country: 'ES',
* pic: 'avatar/nice/url.jpg', * pic: 'avatar/nice/url.jpg',
* notes: null, * notes: null,
* lang: 'en-en', * lang: 'en-en',
* iat: 123512, * iat: 123512,
* exp: 1231292, * exp: 1231292,
* attributes: { @see Student.getValidAttributes() } * attributes: { @see Student.getValidAttributes() }
* }, * },
* token: '... asd90jkas ...', * token: '... asd90jkas ...',
* server_time: 123912932312 * server_time: 123912932312
* } * }
*/ */
login: function (req, res) { login: function (req, res) {
var bcrypt = require('bcrypt-nodejs'); var bcrypt = require('bcrypt-nodejs');
Student.findOne({ Student.findOne({
username: req.body.username username: req.body.username
}) })
.then(function (student) { .then(function (student) {
if (student) { if (student) {
if (bcrypt.compareSync(req.body.password, student.password)) { if (bcrypt.compareSync(req.body.password, student.password)) {
student.isStudent = true; student.isStudent = true;
res.ok({ 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\
"${req.body.password}"`); "${req.body.password}"`);
res.badRequest(); res.badRequest();
} }
} 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.badRequest(); res.badRequest();
} }
}) })
.catch(function () { .catch(function () {
sails.log.error(`Error getting student ${req.body.username} for login`); sails.log.error(`Error getting student ${req.body.username} for login`);
res.serverError(); res.serverError();
}); });
}, },
/** /**
* Get a student by id * Get a student by id
* @param {request} req {} (with studentId specified as url parameters) * @param {request} req {} (with studentId specified as url parameters)
* @param {response} res * @param {response} res
* { * {
* id: 12, * id: 12,
* office: 1234, * office: 1234,
* username: 'johnydoe', * username: 'johnydoe',
* name: 'Johny', * name: 'Johny',
* surname: 'Doe', * surname: 'Doe',
* birthdate: '2009-12-10T00:00:00.000Z', * birthdate: '2009-12-10T00:00:00.000Z',
* gender: 'F', * gender: 'F',
* country: 'ES', * country: 'ES',
* pic: 'avatar/nice/url.jpg', * pic: 'avatar/nice/url.jpg',
* notes: null, * notes: null,
* lang: 'en-en', * lang: 'en-en',
* iat: 123512, * iat: 123512,
* exp: 1231292, * exp: 1231292,
* attributes: { @see Student.getValidAttributes() }, * attributes: { @see Student.getValidAttributes() },
* current_method: 'Do Things', // May be null * current_method: 'Do Things', // May be null
* current_instruction: 'Do Stuff', // May be null * current_instruction: 'Do Stuff', // May be null
* supervision: 0|1|2, // supervision level according to requester 0 -> office admin, 1 -> tutor, 2 -> therapist * supervision: 0|1|2, // supervision level according to requester 0 -> office admin, 1 -> tutor, 2 -> therapist
* } * }
*/ */
getInfo: function (req, res) { getInfo: function (req, res) {
Student.findOne({id: req.params.id_stu}).populate('lastInstruction') Student.findOne({id: req.params.id_stu}).populate('lastInstruction')
.then(function (student) { .then(function (student) {
if (!student) if (!student)
throw new Error("student not found"); throw new Error("student not found");
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";
// recover last instruction to complete student info // recover last instruction to complete student info
var stu_last_inst = VStuLastInstruction.findOne({student: student.id}) var stu_last_inst = VStuLastInstruction.findOne({student: student.id})
.then(function (stu_last_inst) { .then(function (stu_last_inst) {
return stu_last_inst; return stu_last_inst;
}) })
.error(err => {throw err}); .error(err => {throw err});
// determine supervision level of the requester on the student // determine supervision level of the requester on the student
var stu_sup = StuSup.findOne({id_stu: student.id, id_sup: req.token.id}) var stu_sup = StuSup.findOne({id_stu: student.id, id_sup: req.token.id})
.then(function (stu_sup) { .then(function (stu_sup) {
return stu_sup; return stu_sup;
}) })
.error(err => {throw err}); .error(err => {throw err});
return [student, stu_last_inst, stu_sup]; return [student, stu_last_inst, stu_sup];
}) })
.spread(function (student, stu_last_inst, stu_sup) { .spread(function (student, stu_last_inst, stu_sup) {
if (stu_last_inst) { if (stu_last_inst) {
student.current_method = stu_last_inst.met_name; student.current_method = stu_last_inst.met_name;
student.current_instruction = stu_last_inst.ins_name; student.current_instruction = stu_last_inst.ins_name;
} }
// 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)
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
else if (stu_sup && req.token.office && student.office == req.token.office.id) else if (stu_sup && req.token.office && student.office == req.token.office.id)
student.supervision = 2; // requester is supervisor of student student.supervision = 2; // requester is supervisor of student
if (student.supervision == -1) // should not hace access!!! if (student.supervision == -1) // should not hace access!!!
return res.forbidden("Access to this student should not be granted to you"); return res.forbidden("Access to this student should not be granted to you");
return res.ok(student); return res.ok(student);
}) })
.catch(function (err) { .catch(function (err) {
return res.notFound(err); return res.notFound(err);
}); });
}, },
// //
// Adds a new student into the database // Adds a new student into the database
// //
create: function (req, res) { create: function (req, res) {
var params = req.params.all(); var params = req.params.all();
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));
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) {
// This is a MySQL error triggered by TRG_NEW_STUDENT_MAXENROLMENTS trigger // This is a MySQL error triggered by TRG_NEW_STUDENT_MAXENROLMENTS trigger
// (see triggers-enroments-integrity-constraints.sql) // (see triggers-enroments-integrity-constraints.sql)
// As the format is not that of a normal error, we just get message // As the format is not that of a normal error, we just get message
sails.log.debug(err.message); sails.log.debug(err.message);
return res.serverError(err.message); return res.serverError(err.message);
} }
else { else {
sails.log.debug(err.message); sails.log.debug(err.message);
return res.serverError(err.message); return res.serverError(err.message);
} }
}); });
}, },
/** /**
* Deletes an existing student by removing him/her from his/her office * Deletes an existing student by removing him/her from his/her office
* and all his supervisors. * and all his supervisors.
* @param {request} req {} (with id_stu as url parameter) * @param {request} req {} (with id_stu as url parameter)
* @param {response} res {} * @param {response} res {}
*/ */
delete: function (req, res) { delete: function (req, res) {
if (!req.params.id_stu) if (!req.params.id_stu)
return res.json(500, { return res.json(500, {
error: '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.json(500, {
error: err error: err
}); });
} }
return res.json({ return res.json({
result: 'Deleted' result: 'Deleted'
}); });
}); });
}, },
// //
// Updates student information // Updates student information
// //
update: function (req, res) { update: function (req, res) {
if (!req.params.id_stu) { if (!req.params.id_stu) {
res.badRequest(); res.badRequest();
} }
Student.findOne(req.params.id_stu).then(function(stu) { Student.findOne(req.params.id_stu).then(function(stu) {
var k; var k;
// copy attributes // copy attributes
for (k in req.body) stu[k] = req.body[k]; for (k in req.body) stu[k] = req.body[k];
if (!req.body.password) // to avoid change password when no one is provided if (!req.body.password) // to avoid change password when no one is provided
delete stu.password; delete stu.password;
stu.save().then(function (saved) { stu.save().then(function (saved) {
res.ok(stu); res.ok(stu);
// Send websocket message // Send websocket message
sails.hooks.events.broadcastEvent( sails.hooks.events.broadcastEvent(
sails.hooks.rooms.student(stu.id), sails.hooks.rooms.student(stu.id),
sails.hooks.events.updateStudent(stu), sails.hooks.events.updateStudent(stu),
(req.isSocket) ? req.socket : undefined (req.isSocket) ? req.socket : undefined
); );
}) })
.catch(function(err) { .catch(function(err) {
res.severError(); res.severError();
}); });
}) })
.catch(function (err) { .catch(function (err) {
res.notFound(); res.notFound();
}); });
}, },
/** /**
* Return all existing supervisor and therapist from a given student * Return all existing supervisor and therapist from a given student
* @param {request} req {} (with studentId as url parameter) * @param {request} req {} (with studentId as url parameter)
* @param {response} res * @param {response} res
* [ * [
* { * {
* id: supervisorId, * id: supervisorId,
* name: 'John', * name: 'John',
* surname: 'Doe', * surname: 'Doe',
* gender: 'M/F', * gender: 'M/F',
* pic: 'supervisor/avatar.jpg', * pic: 'supervisor/avatar.jpg',
* address: 'My Adress, n1', * address: 'My Adress, n1',
* country: 'ES', * country: 'ES',
* email: 'john@doe.es', * email: 'john@doe.es',
* phone: '+123123123', * phone: '+123123123',
* lang: 'es-es', * lang: 'es-es',
* active: true, * active: true,
* ttsEngine: 'IVONA-Text', * ttsEngine: 'IVONA-Text',
* office: officeId * office: officeId
* }, * },
* ... * ...
* ] * ]
*/ */
supervisors: function (req, res) { supervisors: function (req, res) {
if (!req.params.id_stu) { if (!req.params.id_stu) {
return res.json(500, { return res.json(500, {
error: 'No student defined' error: 'No student defined'
}); });
} }
Student.supervisors(req.params.id_stu, function (err, sups) { Student.supervisors(req.params.id_stu, function (err, sups) {
if (err) throw err; if (err) throw err;
return res.json(sups); return res.json(sups);
}); });
}, },
/** /**
* Return all existing therapists from a given student * Return all existing therapists from a given student
* @param {request} req {} (with studentId as url parameter) * @param {request} req {} (with studentId as url parameter)
* @param {response} res * @param {response} res
* [ * [
* { * {
* id: therapistId, * id: therapistId,
* name: 'John', * name: 'John',
* surname: 'Doe', * surname: 'Doe',
* gender: 'M/F', * gender: 'M/F',
* pic: 'supervisor/avatar.jpg', * pic: 'supervisor/avatar.jpg',
* address: 'My Address, n1', * address: 'My Address, n1',
* country: 'ES', * country: 'ES',
* email: 'john@doe.es', * email: 'john@doe.es',
* phone: '+123123123', * phone: '+123123123',
* lang: 'es-es', * lang: 'es-es',
* active: true, * active: true,
* ttsEngine: 'IVONA-Text', * ttsEngine: 'IVONA-Text',
* office: officeId * office: officeId
* }, * },
* ... * ...
* ] * ]
*/ */
therapists: function (req, res) { therapists: function (req, res) {
if (!req.params.id_stu) { if (!req.params.id_stu) {
return res.json(500, { return res.json(500, {
error: 'No student defined' error: 'No student defined'
}); });
} }
Student.therapists(req.params.id_stu, function (err, sups) { Student.therapists(req.params.id_stu, function (err, sups) {
if (err) throw err; if (err) throw err;
return res.json(sups); return res.json(sups);
}); });
}, },
/** /**
* Return all existing tutors from a given student * Return all existing tutors from a given student
* @param {request} req {} (with studentId as url parameter) * @param {request} req {} (with studentId as url parameter)
* @param {response} res * @param {response} res
* [ * [
* { * {
* id: tutorId, * id: tutorId,
* name: 'John', * name: 'John',
* surname: 'Doe', * surname: 'Doe',
* gender: 'M/F', * gender: 'M/F',
* pic: 'supervisor/avatar.jpg', * pic: 'supervisor/avatar.jpg',
* address: 'My Address, n1', * address: 'My Address, n1',
* country: 'ES', * country: 'ES',
* email: 'john@doe.es', * email: 'john@doe.es',
* phone: '+123123123', * phone: '+123123123',
* lang: 'es-es', * lang: 'es-es',
* active: true, * active: true,
* ttsEngine: 'IVONA-Text', * ttsEngine: 'IVONA-Text',
* office: officeId * office: officeId
* }, * },
* ... * ...
* ] * ]
*/ */
tutors: function (req, res) { tutors: function (req, res) {
if (!req.params.id_stu) { if (!req.params.id_stu) {
return res.json(500, { return res.json(500, {
error: 'No student defined' error: 'No student defined'
}); });
} }
Student.tutors(req.params.id_stu, function (err, sups) { Student.tutors(req.params.id_stu, function (err, sups) {
if (err) throw err; if (err) throw err;
return res.json(sups); return res.json(sups);
}); });
}, },
/** /**
* Creates a relation between the student and a given supervisor. * Creates a relation between the student and a given supervisor.
* It broadcasts the event linkSupervisorToStudent to both the student room * It broadcasts the event linkSupervisorToStudent to both the student room
* and the supervisor room. * and the supervisor room.
* @param {request} { (with id_stu and id_sup as url parameters) * @param {request} { (with id_stu and id_sup as url parameters)
* asTherapist: true/false (optional) // assigns supervisor to student's office is true, set id_off to null otherwise * asTherapist: true/false (optional) // assigns supervisor to student's office is true, set id_off to null otherwise
* } * }
* @param {response} {} * @param {response} {}
*/ */
link_supervisor: function (req, res) { link_supervisor: function (req, res) {
StuSup.create({ StuSup.create({
student: req.param('id_stu'), student: req.param('id_stu'),
supervisor: req.param('id_sup') supervisor: req.param('id_sup')
}) })
.then(function (stuSup) { .then(function (stuSup) {
if (!stuSup) if (!stuSup)
throw new Error('stusup not created'); throw new Error('stusup not created');
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.events.broadcastEvent(
sails.hooks.rooms.supervisor(stuSup.supervisor), sails.hooks.rooms.supervisor(stuSup.supervisor),
linkSupervisorToStudentEvent, linkSupervisorToStudentEvent,
socketToOmit socketToOmit
); );
sails.hooks.events.broadcastEvent( sails.hooks.events.broadcastEvent(
sails.hooks.rooms.student(stuSup.student), sails.hooks.rooms.student(stuSup.student),
linkSupervisorToStudentEvent, linkSupervisorToStudentEvent,
socketToOmit socketToOmit
); );
return stuSup; return stuSup;
}) })
.catch((err) => { .catch((err) => {
StuSup.findOne({ student: req.param('id_stu'), supervisor: req.param('id_sup') }) StuSup.findOne({ student: req.param('id_stu'), supervisor: req.param('id_sup') })
.then((stuSup) => { .then((stuSup) => {
// It was already there! // It was already there!
if (stuSup) if (stuSup)
return stuSup; return stuSup;
else else
throw err; throw err;
}); });
}) })
.then((stuSup) => { .then((stuSup) => {
// update supervisor office if it is linked as therapist // update supervisor office if it is linked as therapist
Supervisor.findOne({id: req.param('id_sup')}) Supervisor.findOne({id: req.param('id_sup')})
.then((sup) => { .then((sup) => {
if (sup) { if (sup) {
Student.findOne({id: req.param('id_stu')}) Student.findOne({id: req.param('id_stu')})
.then((stu) => { .then((stu) => {
if (stu) { if (stu) {
if (req.body.asTherapist) if (req.body.asTherapist)
sup.office = stu.office; sup.office = stu.office;
else else
sup.office = null; sup.office = null;
delete sup.password; delete sup.password;
sup.save(); sup.save();
} }
}); });
} }
}); });
return res.ok(); return res.ok();
}) })
.catch((err) => { .catch((err) => {
return res.serverError("Error: " + err); return res.serverError("Error: " + err);
}); });
}, },
/** /**
* Destroys a relation (drama queen) between the student and a given supervisor. * Destroys a relation (drama queen) between the student and a given supervisor.
* It broadcasts the even unlinkSupervisorFromStudent to both the student room * It broadcasts the even unlinkSupervisorFromStudent to both the student room
* and the supervisor room. * and the supervisor room.
* @param {request} {} (with studentId and supervisorId as url parameters) * @param {request} {} (with studentId and supervisorId as url parameters)
* @param {response} {} * @param {response} {}
*/ */
unlink_supervisor: function (req, res) { unlink_supervisor: function (req, res) {
StuSup.findOne({ StuSup.findOne({
student: req.param('id_stu'), student: req.param('id_stu'),
supervisor: req.param('id_sup') supervisor: req.param('id_sup')
}) })
.then((stuSup) => { .then((stuSup) => {
if (!stuSup) if (!stuSup)
throw new Error("student and supervisor are not linked"); throw new Error("student and supervisor are not linked");
stuSup.destroy(); stuSup.destroy();
const socketToOmit = req.isSocket ? req.socket : undefined; const socketToOmit = req.isSocket ? req.socket : undefined;
const unlinkSupervisorFromStudentEvent = sails.hooks.events.unlinkSupervisorFromStudent( const unlinkSupervisorFromStudentEvent = sails.hooks.events.unlinkSupervisorFromStudent(
stuSup.student, stuSup.student,
stuSup.supervisor stuSup.supervisor
); );
sails.hooks.events.broadcastEvent( sails.hooks.events.broadcastEvent(
sails.hooks.rooms.supervisor(stuSup.supervisor), sails.hooks.rooms.supervisor(stuSup.supervisor),
unlinkSupervisorFromStudentEvent, unlinkSupervisorFromStudentEvent,
socketToOmit socketToOmit
); );
sails.hooks.events.broadcastEvent( sails.hooks.events.broadcastEvent(
sails.hooks.rooms.student(stuSup.student), sails.hooks.rooms.student(stuSup.student),
unlinkSupervisorFromStudentEvent, unlinkSupervisorFromStudentEvent,
socketToOmit socketToOmit
); );
return res.ok(); return res.ok();
}) })
.catch((err) => { .catch((err) => {
res.serverError("Error unliking student: " + err); res.serverError("Error unliking student: " + err);
}); });
}, },
/** /**
* Get all methods from a given student (with their instructions) * Get all methods from a given student (with their instructions)
* @param {request} req {} (with studentId as url parameter) * @param {request} req {} (with studentId as url parameter)
* @param {response} res * @param {response} res
* [ * [
* { * {
* id: methodId, * id: methodId,
* student: studentId, * student: studentId,
* name: 'Method Name', * name: 'Method Name',
* description: 'Method description', * description: 'Method description',
* registration: null, * registration: null,
* notes: 'Method notes', * notes: 'Method notes',
* last_ins: instructionId // Last instruccion executed, * last_ins: instructionId // Last instruccion executed,
* instructions: [ * instructions: [
* { * {
* id: instructionId, * id: instructionId,
* name: 'Instruction Name', * name: 'Instruction Name',
* objective: 'Instruction Objective', * objective: 'Instruction Objective',
* status: 'instruction-status', * status: 'instruction-status',
* begin: '2015-07-14T07:23:03.000Z', * begin: '2015-07-14T07:23:03.000Z',
* end: '2015-07-14T07:28:03.000Z', * end: '2015-07-14T07:28:03.000Z',
* method: methodId * method: methodId
* }, * },
* ... * ...
* ] * ]
* }, * },
* ... * ...
* ] * ]
*/ */
methods: function (req, res) { methods: function (req, res) {
var params = req.allParams(); var params = req.allParams();
Method.find({ Method.find({
student: params.id_stu student: params.id_stu
}) })
.populate('instructions') .populate('instructions')
.exec(function (err, methods) { .exec(function (err, methods) {
if (err) if (err)
return res.json(500, { return res.json(500, {
error: err error: err
}); });
if (!methods || methods.length == 0) if (!methods || methods.length == 0)
return res.json([]); // Return an empty array return res.json([]); // Return an empty array
if (methods) { if (methods) {
var l_met = []; var l_met = [];
async.eachSeries(methods, function (m, callback1) { async.eachSeries(methods, function (m, callback1) {
var l_ins = []; var l_ins = [];
var last_ins = null; var last_ins = null;
var last_time = 0; var last_time = 0;
sails.log.debug('Loop methods: ' + m.name); sails.log.debug('Loop methods: ' + m.name);
async.eachSeries(m.instructions, function (ins, callback2) { async.eachSeries(m.instructions, function (ins, callback2) {
sails.log.debug('Loop instructions: ' + ins.name); sails.log.debug('Loop instructions: ' + ins.name);
Instruction.findOne({ Instruction.findOne({
id: ins.id id: ins.id
}) })
.populate('workingSessions', { .populate('workingSessions', {
sort: 'begin DESC' sort: 'begin DESC'
}) })
.exec(function (err, instruction) { .exec(function (err, instruction) {
if (err) { if (err) {
sails.log.debug('Error in method ' + m.name); sails.log.debug('Error in method ' + m.name);
} }
if (!instruction || !instruction.workingSessions || instruction.workingSessions if (!instruction || !instruction.workingSessions || instruction.workingSessions
.length == 0) { .length == 0) {
sails.log.debug('No working sessions found for instruction ' + sails.log.debug('No working sessions found for instruction ' +
instruction.id); instruction.id);
} else { } else {
var last = instruction.workingSessions.length - 1; var last = instruction.workingSessions.length - 1;
instruction.begin = instruction.workingSessions[last].end; instruction.begin = instruction.workingSessions[last].end;
instruction.end = instruction.workingSessions[0].end; instruction.end = instruction.workingSessions[0].end;
if (instruction.end > last_time) { if (instruction.end > last_time) {
last_ins = instruction.id; last_ins = instruction.id;
last_time = instruction.end; last_time = instruction.end;
} }
} }
// Add instruction to list (with or without tries) // Add instruction to list (with or without tries)
l_ins.push(instruction); l_ins.push(instruction);
callback2(); callback2();
}); });
// Finish function when each callback is done // Finish function when each callback is done
// Optionaly it can be passed and err parameter // Optionaly it can be passed and err parameter
}, function (err) { }, function (err) {
if (err) { if (err) {
// One of the iterations produced an error. // One of the iterations produced an error.
// All processing will now stop. // All processing will now stop.
return res.json(500, { return res.json(500, {
error: 'Error looping in tries: ' + err error: 'Error looping in tries: ' + err
}); });
} }
m.instructions = l_ins; m.instructions = l_ins;
m.last_ins = last_ins; m.last_ins = last_ins;
l_met.push(m); l_met.push(m);
callback1(); callback1();
}); });
// Finish function when each callback is done // Finish function when each callback is done
// Optionaly it can be passed and err parameter // Optionaly it can be passed and err parameter
}, function (err) { }, function (err) {
if (err) { if (err) {
// One of the iterations produced an error. // One of the iterations produced an error.
// All processing will now stop. // All processing will now stop.
return res.json(500, { return res.json(500, {
error: 'Error looping in method instructions: ' + err error: 'Error looping in method instructions: ' + err
}); });
} else { } else {
// All end ok // All end ok
//Assing the built list //Assing the built list
return res.json(l_met); return res.json(l_met);
} }
}); });
} }
}); });
}, },
// read action // read action
// get tries of the last working session // get tries of the last working session
// //
lasttries: function (req, res) { lasttries: function (req, res) {
var params = req.allParams(); var params = req.allParams();
//Student.findOne({ id: params.id_stu }).populate('workingSessions') //Student.findOne({ id: params.id_stu }).populate('workingSessions')
VStuLastInstruction.findOne({ VStuLastInstruction.findOne({
where: { where: {
student: params.id_stu student: params.id_stu
} }
}) })
.exec(function (err, ws) { .exec(function (err, ws) {
if (err) { if (err) {
sails.log.debug('Finding student working sessions: ' + err); sails.log.debug('Finding student working sessions: ' + err);
return res.json(500, { return res.json(500, {
error: 'No student last working session found' error: 'No student last working session found'
}); });
} }
if (!ws || ws.length == 0) { if (!ws || ws.length == 0) {
return res.json([]); // Return an empty array of last tries return res.json([]); // Return an empty array of last tries
} }
if (ws) { if (ws) {
// Find the tries of this working session populating actions // Find the tries of this working session populating actions
sails.log.debug('Find WS ' + JSON.stringify(ws)); sails.log.debug('Find WS ' + JSON.stringify(ws));
Try.find({ Try.find({
workingSession: ws.workingSession workingSession: ws.workingSession
}) })
.populate('actions', { .populate('actions', {
//supervisor: null //recovering supervisor actions, too //supervisor: null //recovering supervisor actions, too
}) })
.exec(function (err, tries) { .exec(function (err, tries) {
if (err) { if (err) {
return res.json(500, { return res.json(500, {
error: 'No student last tries found' error: 'No student last tries found'
}); });
} }
if (!tries || tries.length == 0) { if (!tries || tries.length == 0) {
return res.json([]); // Return an empty array of tries return res.json([]); // Return an empty array of tries
} }
if (tries) { if (tries) {
// A list for one element: The last working session // A list for one element: The last working session
var l_ws = []; var l_ws = [];
l_ws.push({ l_ws.push({
'id': ws.workingSession, 'id': ws.workingSession,
'student': ws.student, 'student': ws.student,
'begin': ws.ws_begin, 'begin': ws.ws_begin,
'end': ws.ws_end, 'end': ws.ws_end,
'description': ws.ws_description, 'description': ws.ws_description,
'tries': tries 'tries': tries
}); });
return res.json(l_ws); return res.json(l_ws);
} }
}); });
} }
}); });
}, },
/** /**
* Return all tries from a student * Return all tries from a student
* @param {request} req {} (width studentId as url parameter) * @param {request} req {} (width studentId as url parameter)
* @param {response} res * @param {response} res
* { * {
"methods": [ "methods": [
{ {
"student": 24, "student": 24,
"id": 1, "id": 1,
"name": "Test Method", "name": "Test Method",
"description": null, "description": null,
"registration": null, "registration": null,
"notes": null "notes": null
"instructions": [ "instructions": [
{ {
"id": 1, "id": 1,
"name": "Test Instruction", "name": "Test Instruction",
"objective": null, "objective": null,
"status": "started", "status": "started",
"begin": null, "begin": null,
"end": null, "end": null,
"method": 1, "method": 1,
"working_sessions": [ "working_sessions": [
{ {
"id": 3, "id": 3,
"begin": "2016-09-09T08:26:24.500Z", "begin": "2016-09-09T08:26:24.500Z",
"end": "2016-08-28T23:36:35.000Z", "end": "2016-08-28T23:36:35.000Z",
"current": null, "current": null,
"description": "", "description": "",
"supervisor": 23, "supervisor": 23,
"instruction": 1 "instruction": 1
"tries": [ "tries": [
{ {
"actions": [], "actions": [],
"id": 1, "id": 1,
"begin": "2016-08-28T23:36:35.474Z", "begin": "2016-08-28T23:36:35.474Z",
"end": "2016-08-28T23:36:44.000Z", "end": "2016-08-28T23:36:44.000Z",
"result": null, "result": null,
"description": null, "description": null,
"workingSession": 3 "workingSession": 3
}, },
{ {
"actions": [], "actions": [],
"id": 2, "id": 2,
"begin": "2016-08-28T23:36:44.050Z", "begin": "2016-08-28T23:36:44.050Z",
"end": "2016-08-29T01:36:51.710Z", "end": "2016-08-29T01:36:51.710Z",
"result": "SUCCESS", "result": "SUCCESS",
"description": null, "description": null,
"workingSession": 3 "workingSession": 3
}, },
{ {
"actions": [], "actions": [],
"id": 3, "id": 3,
"begin": "2016-08-28T23:36:51.942Z", "begin": "2016-08-28T23:36:51.942Z",
"end": "2016-08-28T23:36:53.000Z", "end": "2016-08-28T23:36:53.000Z",
"result": "DISCARDED", "result": "DISCARDED",
"description": null, "description": null,
"workingSession": 3 "workingSession": 3
}, },
{ {
"actions": [], "actions": [],
"id": 4, "id": 4,
"begin": "2016-08-28T23:36:53.877Z", "begin": "2016-08-28T23:36:53.877Z",
"end": "2016-08-28T23:37:13.000Z", "end": "2016-08-28T23:37:13.000Z",
"result": "SPONTANEOUS SUCCESS", "result": "SPONTANEOUS SUCCESS",
"description": null, "description": null,
"workingSession": 3 "workingSession": 3
} }
] ]
} }
} }
] ]
} }
] ]
} }
*/ */
tries: function (req, res) { tries: function (req, res) {
if (!req.params.id_stu) if (!req.params.id_stu)
return res.badRequest("Student not defined"); return res.badRequest("Student not defined");
Student.tries(req.params.id_stu, function (err, l_met) { Student.tries(req.params.id_stu, function (err, l_met) {
if (err) return res.serverError(err); if (err) return res.serverError(err);
return res.ok(l_met); return res.ok(l_met);
}); });
}, },
/** /**
* Get all pictos from a given student * Get all pictos from a given student
* @param {request} req {} (with studentId as url parameter) * @param {request} req {} (with studentId as url parameter)
* @param {response} res * @param {response} res
* [ * [
* { * {
* id: student-picto ID, * id: student-picto ID,
* picto: { * picto: {
* id: pictoId, * id: pictoId,
* uri: 'uri/to/picto.png', * uri: 'uri/to/picto.png',
* category: pictoCategoryId, * category: pictoCategoryId,
* source: 1 @TODO Other sources * source: 1 @TODO Other sources
* owner: supervisorId or null * owner: supervisorId or null
* }, * },
* expression: { * expression: {
* id: expressionId, * id: expressionId,
* lang: 'es-es', * lang: 'es-es',
* text: 'Picto Expression', * text: 'Picto Expression',
* picto: pictoId * picto: pictoId
* }, * },
* attributes: { @see StuPicto.getValidAttributes() } * attributes: { @see StuPicto.getValidAttributes() }
* }, * },
* ... * ...
* ] * ]
*/ */
pictos: function (req, res) { pictos: function (req, res) {
if (!req.params.id_stu) { if (!req.params.id_stu) {
return res.json(500, { return res.json(500, {
error: 'No student defined' error: 'No student defined'
}); });
} }
sails.log.debug('Pictos requested for student ' + req.params.id_stu); sails.log.debug('Pictos requested for student ' + req.params.id_stu);
Student.pictos(req.params.id_stu, function (err, pictos) { Student.pictos(req.params.id_stu, function (err, pictos) {
if (err) if (err)
return res.serverError("Error obtaining pictos: "+ err); return res.serverError("Error obtaining pictos: "+ err);
return res.ok(pictos); return res.ok(pictos);
}); });
}, },
// //
// Returns all working sessions for the given student // Returns all working sessions for the given student
// //
ws: function (req, res) { ws: function (req, res) {
if (!req.params.id_stu) { if (!req.params.id_stu) {
return res.json(500, { return res.json(500, {
error: 'No student defined' error: 'No student defined'
}); });
} }
sails.log.debug('Working Sessions requested for student ' + req.params.id_stu); sails.log.debug('Working Sessions requested for student ' + req.params.id_stu);
Student.findOne(req.params.id_stu) Student.findOne(req.params.id_stu)
.populate('workingSessions') .populate('workingSessions')
.exec(function (err, stu) { .exec(function (err, stu) {
if (err) if (err)
return res.json(500, { return res.json(500, {
error: err error: err
}); });
if (!stu || !stu.workingSessions || stu.workingSessions.length == 0) if (!stu || !stu.workingSessions || stu.workingSessions.length == 0)
return res.json([]); // Return an empty array return res.json([]); // Return an empty array
else else
return res.json(stu.workingSessions); return res.json(stu.workingSessions);
}); });
}, },
/** /**
* Add an existing picto to the student's collection * Add an existing picto to the student's collection
* @param {request} req (with studentId and pictoId as url parameter) * @param {request} req (with studentId and pictoId as url parameter)
* { * {
* attributes: { @see StuPicto.getValidAttributes() } * attributes: { @see StuPicto.getValidAttributes() }
* } * }
* @param {response} res * @param {response} res
* { * {
* id: stuPictoId (association betweet student and picto) * id: stuPictoId (association betweet student and picto)
* student: studentId (speficied as url parameter) * student: studentId (speficied as url parameter)
* picto: { @see Picto model} * picto: { @see Picto model}
* attributes: { @see StuPicto.getValidAttributes() } * attributes: { @see StuPicto.getValidAttributes() }
* expression: { @see Picto model } * expression: { @see Picto model }
* } * }
*/ */
add_picto: function (req, res) { add_picto: function (req, res) {
var params = req.allParams(); var params = req.allParams();
Student.findOne({ id: params.id_stu }) Student.findOne({ id: params.id_stu })
.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");
} }
return [ return [
Picto.findOne({ id: params.id_picto }) Picto.findOne({ id: params.id_picto })
.populate('expressions', {lang: student.lang}) .populate('expressions', {lang: student.lang})
, ,
student student
]; ];
}) })
.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");
} }
return [ return [
StuPicto.create({ StuPicto.create({
student: student.id, student: student.id,
picto: picto.id, picto: picto.id,
attributes: params.attributes attributes: params.attributes
}) })
, ,
picto picto
]; ];
}) })
.spread((stuPicto, picto) => { .spread((stuPicto, picto) => {
if (!stuPicto) if (!stuPicto)
throw new Error("stu_picto not created"); throw new Error("stu_picto not created");
sails.log.debug("->>" + JSON.stringify(picto)); sails.log.debug("->>" + JSON.stringify(picto));
return res.ok({ return res.ok({
id: stuPicto.id, id: stuPicto.id,
student: params.id_stu, student: params.id_stu,
attributes: stuPicto.attributes, attributes: stuPicto.attributes,
picto: picto, picto: picto,
expression: picto.expressions[0] expression: picto.expressions[0]
}); });
}) })
.catch(err => res.serverError("Error adding picto: " + err)); .catch(err => res.serverError("Error adding picto: " + err));
}, },
/** /**
* Removes an existing picto to the student's collection * Removes an existing picto to the student's collection
* Warning: yout must send the **stuPictoId** as url parameter, not the **pictoId**. * Warning: yout must send the **stuPictoId** as url parameter, not the **pictoId**.
* You can obtain this ID from the student picto collection. * You can obtain this ID from the student picto collection.
* @param {request} req {} (with studentId and stuPictoId as url parameters) * @param {request} req {} (with studentId and stuPictoId as url parameters)
* @param {response} res {} * @param {response} res {}
*/ */
delete_picto: function (req, res) { delete_picto: function (req, res) {
var params = req.allParams(); var params = req.allParams();
StuPicto.destroy({ id: params.id_stuPicto }) StuPicto.destroy({ id: params.id_stuPicto })
.then(destroyed => { .then(destroyed => {
if (!destroyed) if (!destroyed)
throw new Error(); throw new Error();
return res.ok(); return res.ok();
}) })
.catch(err => { .catch(err => {
return res.serverError('Not removed picto for student: ' + err); return res.serverError('Not removed picto for student: ' + err);
}); });
}, },
// update action // update action
// update picto atributes for a studentPicto // update picto atributes for a studentPicto
// //
update_picto: function (req, res) { update_picto: function (req, res) {
var params = req.allParams(); var params = req.allParams();
console.log('Updating attributes for picto student ' + JSON.stringify(params)); console.log('Updating attributes for picto student ' + JSON.stringify(params));
console.log(JSON.stringify(params)); console.log(JSON.stringify(params));
query = params.id_stuPicto ? { query = params.id_stuPicto ? {
id: params.id_stuPicto id: params.id_stuPicto
} : { } : {
id_stu: params.id_stu, id_stu: params.id_stu,
id_pic: params.id_pic id_pic: params.id_pic
} }
StuPicto.update(query, { StuPicto.update(query, {
attributes: params.attributes attributes: params.attributes
}) })
.then(updated => { .then(updated => {
if (!updated) if (!updated)
throw new Error ("error on update"); throw new Error ("error on update");
console.log('Updated attributes for picto student:' + JSON.stringify(updated[0])); console.log('Updated attributes for picto student:' + JSON.stringify(updated[0]));
// return res.json(updated[0]); // return res.json(updated[0]);
return res.ok({ return res.ok({
id: updated[0].id, // id of stu_picto id: updated[0].id, // id of stu_picto
attributes: updated[0].attributes, // picto attributes for student attributes: updated[0].attributes, // picto attributes for student
picto: { picto: {
id: updated[0].picto // picto information id: updated[0].picto // picto information
} }
}); });
}) })
.catch(err => { .catch(err => {
return res.serverError('Unable to update picto for student: ' + err); return res.serverError('Unable to update picto for student: ' + err);
}); });
}, },
/** // update action
* Updates the student profile image // update picto atributes for a studentPicto
* @param {request} req //
* file: [The image binary data] update_legend: function (req, res) {
* { var params = req.allParams();
* "id": "student ID" var query='update stu_picto'+
* } ' set attributes=json_set(attributes, \'$.legend\',\''+params.legend_value+'\')'+
* @param {response} res {} ' where id_stu='+params.id_stu;
*/ console.log('Updating legend for student ' + params.id_stu +" collection to "+
upload: function (req, res) { params.legend_value+": "+query);
var fs = require('fs');
var path = require('path'); StuPicto.query(query, function(err, result) {
var newAvatarFileName; if (err)
var newAvatarFileDescriptor; throw new Error ("error on update");
var newAvatarDirectory = sails.config.pictogram.paths.studentAvatarDirectory; else {
console.log('Updated attributes for picto student:' + params.id_stu);
Student.findOne({ id: req.body.id }).then(function (student) { return res.ok({
if (!student) { id: params.id_stu,
throw new Error("Student not found"); legend_value: params.legend_value, // picto attributes for student
} });
newAvatarFileName = sails.config.pictogram.paths.getStudentAvatarFileName(student.id); }
});
req.file('file').upload({ },
maxBytes: 1000000, /**
dirname: newAvatarDirectory, * Updates the student profile image
saveAs: newAvatarFileName * @param {request} req
}, function whenDone(error, uploadedFiles) { * file: [The image binary data]
if (error || (uploadedFiles.length === 0)) { * {
throw new Error("upload failed"); * "id": "student ID"
} * }
* @param {response} res {}
try { */
newAvatarFileDescriptor = uploadedFiles[0].fd; upload: function (req, res) {
if (student.pic !== sails.config.pictogram.paths.defaultAvatarFileName) { var fs = require('fs');
fs.unlinkSync(path.join(newAvatarDirectory, student.pic)); var path = require('path');
} var newAvatarFileName;
var newAvatarFileDescriptor;
student.pic = newAvatarFileName; var newAvatarDirectory = sails.config.pictogram.paths.studentAvatarDirectory;
student.save(function (updateStudentError) {
if (updateStudentError) { Student.findOne({ id: req.body.id }).then(function (student) {
throw updateStudentError; if (!student) {
} throw new Error("Student not found");
res.ok(); }
}); newAvatarFileName = sails.config.pictogram.paths.getStudentAvatarFileName(student.id);
} catch (updateAvatarError) {
fs.unlinkSync(newAvatarFileDescriptor); req.file('file').upload({
res.serverError("Error when updating profile image in server"); maxBytes: 1000000,
} dirname: newAvatarDirectory,
}); saveAs: newAvatarFileName
}) }, function whenDone(error, uploadedFiles) {
.catch(function (err) { if (error || (uploadedFiles.length === 0)) {
res.badRequest("Could not find supervisor: " + err); throw new Error("upload failed");
}); }
},
try {
// *************************************************************** newAvatarFileDescriptor = uploadedFiles[0].fd;
// WEBSOCKETS if (student.pic !== sails.config.pictogram.paths.defaultAvatarFileName) {
// *************************************************************** fs.unlinkSync(path.join(newAvatarDirectory, student.pic));
// }
// Subscribe to websockets events
// student.pic = newAvatarFileName;
subscribe: function (req, res) { student.save(function (updateStudentError) {
var action = req.param('action'); if (updateStudentError) {
var attributes = req.param('attributes'); throw updateStudentError;
attributes.ui = attributes.ui ? attributes.ui : 'PCB'; }
res.ok();
if (req.isSocket) { });
sails.hooks.rooms.subscribeToRoom( } catch (updateAvatarError) {
sails.hooks.rooms.student(attributes.id_stu), fs.unlinkSync(newAvatarFileDescriptor);
req.socket, res.serverError("Error when updating profile image in server");
attributes.ui }
); });
} })
res.ok({msg: "Subscribed to student "}); .catch(function (err) {
}, res.badRequest("Could not find supervisor: " + err);
});
// },
// Unsubscribe to websockets events
// // ***************************************************************
unsubscribe: function (req, res) { // WEBSOCKETS
var action = req.param('action'); // ***************************************************************
//var attributes = req.param('attributes'); //
// Subscribe to websockets events
if (req.isSocket) { //
subscribe: function (req, res) {
var rooms = sails.sockets.socketRooms(req.socket); var action = req.param('action');
console.log("Subscribed rooms in socket: " + JSON.stringify(rooms)); var attributes = req.param('attributes');
attributes.ui = attributes.ui ? attributes.ui : 'PCB';
// Leave all rooms
for (var i = 0; i < rooms.length; i++) { if (req.isSocket) {
//sails.sockets.leave(req.socket, rooms[i]); MODIFICADO POR FERNANDO. SI NO, NO SE ACTUALIZA UPDATE_PEERS sails.hooks.rooms.subscribeToRoom(
sails.hooks.rooms.unsubscribeFromRoom(rooms[i], req.socket); sails.hooks.rooms.student(attributes.id_stu),
sails.log.debug("Unsusbscribe from room " + rooms[i]); req.socket,
} attributes.ui
);
res.json({ }
msg: "Unsubscribed from all rooms" res.ok({msg: "Subscribed to student "});
}); },
}
}, //
// Unsubscribe to websockets events
// //
// Logs a vocabulary action and broadcast to anyone subscribed to this student unsubscribe: function (req, res) {
vocabulary: function (req, res) { var action = req.param('action');
var action = req.param('action'); //var attributes = req.param('attributes');
var attributes = req.param('attributes');
if (req.isSocket) {
var roomName = 'studentRoom' + attributes.id_stu;
var rooms = sails.sockets.socketRooms(req.socket);
sails.log.debug("Inside vocabulary"); console.log("Subscribed rooms in socket: " + JSON.stringify(rooms));
if (req.isSocket) { // Leave all rooms
sails.log.debug("Inside vocabulary - isSocket"); for (var i = 0; i < rooms.length; i++) {
//sails.sockets.leave(req.socket, rooms[i]); MODIFICADO POR FERNANDO. SI NO, NO SE ACTUALIZA UPDATE_PEERS
// Send to all sockets subscribed to this room except the own socket that sends the message sails.hooks.rooms.unsubscribeFromRoom(rooms[i], req.socket);
// Parameters: room, action, data to send, socket to avoid sending (the socket that send this) sails.log.debug("Unsusbscribe from room " + rooms[i]);
sails.sockets.broadcast(roomName, 'vocabulary', { }
"action": action,
"attributes": attributes res.json({
}, req.socket); msg: "Unsubscribed from all rooms"
});
res.json({ }
msg: "Vocabulary " + action + " action from student " + attributes.id_stu },
});
} //
}, // Logs a vocabulary action and broadcast to anyone subscribed to this student
vocabulary: function (req, res) {
/** var action = req.param('action');
* Logs a TRY action and broadcast to anyone subscribed to this student var attributes = req.param('attributes');
* @param {request} req
* { var roomName = 'studentRoom' + attributes.id_stu;
* "action": <action> ("add", "delete", ...),
* "attributes": { sails.log.debug("Inside vocabulary");
* "id_stu": <id_stu>,
* "timestamp": <timestamp_string_in_ISO_format> (e.g.: "2016-07-13 17:50:00.224+0200"), if (req.isSocket) {
* "picto": {...} sails.log.debug("Inside vocabulary - isSocket");
* }
* } // Send to all sockets subscribed to this room except the own socket that sends the message
* @param {response} res {<action_created>} // Parameters: room, action, data to send, socket to avoid sending (the socket that send this)
*/ sails.sockets.broadcast(roomName, 'vocabulary', {
action: function (req, res) { "action": action,
var action = req.param('action'); "attributes": attributes
var attributes = req.param('attributes'); }, req.socket);
sails.log.debug("Inside action. Student:" + attributes.id_stu); res.json({
msg: "Vocabulary " + action + " action from student " + attributes.id_stu
if (!req.isSocket) { });
sails.log.debug("No socket request for action"); }
res.badRequest() },
} else {
sails.log.debug("websockets - room " + sails.hooks.rooms.student(attributes.id_stu)); /**
// BROADCAST to everyone subscribed to this student * Logs a TRY action and broadcast to anyone subscribed to this student
const socketToOmit = (req.isSocket) ? req.socket : undefined; * @param {request} req
sails.hooks.events.broadcastEvent( * {
sails.hooks.rooms.student(attributes.id_stu), * "action": <action> ("add", "delete", ...),
sails.hooks.events.actionPerformed(action, attributes), * "attributes": {
socketToOmit * "id_stu": <id_stu>,
); * "timestamp": <timestamp_string_in_ISO_format> (e.g.: "2016-07-13 17:50:00.224+0200"),
* "picto": {...}
var sup = null; * }
if (attributes.id_sup) sup = attributes.id_sup; * }
* @param {response} res {<action_created>}
var desc = null; */
if (attributes.stu_picto) desc = attributes.stu_picto; // select, add and delete actions data action: function (req, res) {
if (attributes.pictos) desc = attributes.pictos; // show action data var action = req.param('action');
var attributes = req.param('attributes');
Action.create({
type: action, sails.log.debug("Inside action. Student:" + attributes.id_stu);
timestamp: attributes.timestamp, // it comes already in ISO format
supervisor: sup, if (!req.isSocket) {
student: attributes.id_stu, sails.log.debug("No socket request for action");
description: desc res.badRequest()
}) } else {
.then(function (created) { sails.log.debug("websockets - room " + sails.hooks.rooms.student(attributes.id_stu));
res.json({ // BROADCAST to everyone subscribed to this student
action: created const socketToOmit = (req.isSocket) ? req.socket : undefined;
}); sails.hooks.events.broadcastEvent(
}) sails.hooks.rooms.student(attributes.id_stu),
.fail(function(err) { sails.hooks.events.actionPerformed(action, attributes),
sails.log.error(err.details); socketToOmit
res.serverError(err.details); );
});
} var sup = null;
}, if (attributes.id_sup) sup = attributes.id_sup;
// var desc = null;
// Logs a config action and broadcast to anyone subscribed to this student if (attributes.stu_picto) desc = attributes.stu_picto; // select, add and delete actions data
config: function (req, res) { if (attributes.pictos) desc = attributes.pictos; // show action data
var action = req.param('action');
var attributes = req.param('attributes'); Action.create({
sails.log.debug("Inside config"); type: action,
timestamp: attributes.timestamp, // it comes already in ISO format
if (req.isSocket) { supervisor: sup,
const socketToOmit = (req.isSocket) ? req.socket : undefined; student: attributes.id_stu,
sails.hooks.events.broadcastEvent( description: desc
sails.hooks.rooms.student(attributes.id_stu), })
'action', .then(function (created) {
{ res.json({
"action": action, action: created
"attributes": attributes });
}, })
socketToOmit .fail(function(err) {
); sails.log.error(err.details);
} else { res.serverError(err.details);
res.ok({ });
msg: "Config " + action + " action from student " + attributes.id_stu }
}); },
}
}, //
// Logs a config action and broadcast to anyone subscribed to this student
// config: function (req, res) {
// Stores in the action table a bulk of actions loaded from of the var action = req.param('action');
// recorded action log var attributes = req.param('attributes');
// sails.log.debug("Inside config");
actions_batch: function (req, res) {
var params = req.allParams(); if (req.isSocket) {
var count = 0; const socketToOmit = (req.isSocket) ? req.socket : undefined;
sails.hooks.events.broadcastEvent(
sails.log.debug("Actions_batch request"); sails.hooks.rooms.student(attributes.id_stu),
'action',
if (!params.actions) {
return res.json(400, { "action": action,
'error': "no actions" "attributes": attributes
}); },
socketToOmit
// We loop through the actions and store them in the database );
async.forEach(params.actions, function (action, cb) { } else {
sails.log.debug("Actions batch is recording action: " + JSON.stringify(action)); res.ok({
var id_sup = null; msg: "Config " + action + " action from student " + attributes.id_stu
if (action.attributes.id_sup) });
id_sup = action.attributes.sup; }
},
var id_stu = null;
if (action.attributes.id_stu) //
id_stu = action.attributes.id_stu; // Stores in the action table a bulk of actions loaded from of the
// recorded action log
var desc = null; //
if (action.attributes.picto) actions_batch: function (req, res) {
desc = action.attributes.picto; // select, add and delete actions data var params = req.allParams();
var count = 0;
if (action.attributes.pictos)
desc = action.attributes.pictos; // show action data sails.log.debug("Actions_batch request");
Action.create({ if (!params.actions)
type: action.action, return res.json(400, {
timestamp: action.attributes.timestamp, 'error': "no actions"
supervisor: id_sup, });
student: id_stu,
description: desc // We loop through the actions and store them in the database
}) async.forEach(params.actions, function (action, cb) {
.exec(function (err, created) { sails.log.debug("Actions batch is recording action: " + JSON.stringify(action));
if (err) { var id_sup = null;
console.log(err.details); if (action.attributes.id_sup)
sails.log.error(err.details); id_sup = action.attributes.sup;
return cb(err);
} else if (created) var id_stu = null;
count++; if (action.attributes.id_stu)
cb(); id_stu = action.attributes.id_stu;
});
}, var desc = null;
function (err) { // function called when loop is done if (action.attributes.picto)
if (err) { desc = action.attributes.picto; // select, add and delete actions data
console.log(err.details);
sails.log.error(err.details); if (action.attributes.pictos)
return res.json({ desc = action.attributes.pictos; // show action data
'error': err.details
}); Action.create({
} else type: action.action,
return res.json({ timestamp: action.attributes.timestamp,
'result': 'Ok', supervisor: id_sup,
'total': count student: id_stu,
}); description: desc
}); })
}, .exec(function (err, created) {
if (err) {
// console.log(err.details);
// Returns the last instruction for the student sails.log.error(err.details);
// return cb(err);
last_instruction: function (req, res) { } else if (created)
if (!req.params.id_stu) count++;
return res.json(400, { cb();
err: 'id_stu parameter is missing' });
}); },
function (err) { // function called when loop is done
VStuLastInstruction.find({ if (err) {
id_stu: req.params.id_stu console.log(err.details);
}) sails.log.error(err.details);
.exec(function (err, found) { return res.json({
if (err) 'error': err.details
return res.json(500, err); });
if (!found) } else
return res.json({}); return res.json({
return res.json(found); 'result': 'Ok',
}); 'total': count
} });
}; });
},
//
// Returns the last instruction for the student
//
last_instruction: function (req, res) {
if (!req.params.id_stu)
return res.json(400, {
err: 'id_stu parameter is missing'
});
VStuLastInstruction.find({
id_stu: req.params.id_stu
})
.exec(function (err, found) {
if (err)
return res.json(500, err);
if (!found)
return res.json({});
return res.json(found);
});
}
};
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// Please note that $modalInstance represents a modal window (instance) dependency. // Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above. // It is not the same as the $modal service used above.
dashboardControllers.controller('PictoConfigCtrl', function ($scope, $modalInstance, $http, config, studentPicto, sup, stu) { dashboardControllers.controller('PictoConfigCtrl', function ($window, $scope, $modalInstance, $http, config, studentPicto, sup, stu) {
// Last parameter passed from collections.js // Last parameter passed from collections.js
// Basic data passed from the main window // Basic data passed from the main window
...@@ -34,7 +34,7 @@ dashboardControllers.controller('PictoConfigCtrl', function ($scope, $modalInsta ...@@ -34,7 +34,7 @@ dashboardControllers.controller('PictoConfigCtrl', function ($scope, $modalInsta
console.log("Expression changed: " + JSON.stringify(data)+": "+$scope.studentPicto.expression.text); console.log("Expression changed: " + JSON.stringify(data)+": "+$scope.studentPicto.expression.text);
$scope.studentPicto.attributes.expression=$scope.studentPicto.expression.text; $scope.studentPicto.attributes.expression=$scope.studentPicto.expression.text;
// Close the modal instance // Close the modal instance
$modalInstance.close($scope.studentPicto.expression.text); //$modalInstance.close($scope.studentPicto.expression.text);
// Notifcar cambio // Notifcar cambio
io.socket.post('/stu/vocabulary', { io.socket.post('/stu/vocabulary', {
...@@ -70,7 +70,7 @@ dashboardControllers.controller('PictoConfigCtrl', function ($scope, $modalInsta ...@@ -70,7 +70,7 @@ dashboardControllers.controller('PictoConfigCtrl', function ($scope, $modalInsta
console.log("Properties updated"); console.log("Properties updated");
// Close the modal instance // Close the modal instance
$modalInstance.close($scope.expression); //$modalInstance.close($scope.expression);
// ///////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////
// Websocket: Emit vocabulary update action // Websocket: Emit vocabulary update action
...@@ -92,6 +92,21 @@ dashboardControllers.controller('PictoConfigCtrl', function ($scope, $modalInsta ...@@ -92,6 +92,21 @@ dashboardControllers.controller('PictoConfigCtrl', function ($scope, $modalInsta
}); });
}; };
$scope.update_legend = function(){
console.log("Legend: " + $scope.studentPicto.attributes.legend+" to be modified");
$http
.put(config.backend+'/stu/'+ $scope.stu.id + '/legend/' + $scope.studentPicto.attributes.legend)
.success(function(data, status, headers, config) {
console.log("Legend updated");
// Close the modal instance
$modalInstance.close($scope.expression);
$window.location.reload();
});
};
$scope.close = function () { $scope.close = function () {
// Lo que se devuelve a collection // Lo que se devuelve a collection
$modalInstance.dismiss('cancel'); $modalInstance.dismiss('cancel');
......
...@@ -62,12 +62,12 @@ ...@@ -62,12 +62,12 @@
<hr> <hr>
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<input type="checkbox"> <input type="checkbox" ng-model="update_all_legend" ng-init="update_all_legend=false">
<span translate>legend_apply_all</span> <span translate>legend_apply_all</span>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<div class="form-group text-center"> <div class="form-group text-center">
<button type="submit" class="btn btn-primary ng-scope" ng-click="" disabled translate>apply</button> <button type="submit" class="btn btn-primary ng-scope" ng-click="update_all_legend ? update_legend() : close()" translate>apply</button>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -96,6 +96,7 @@ module.exports.policies = { ...@@ -96,6 +96,7 @@ module.exports.policies = {
ws: ['tokenAuth'], ws: ['tokenAuth'],
update: ['tokenAuth'], update: ['tokenAuth'],
update_picto: ['tokenAuth', 'isSupervisorOfStudent'], update_picto: ['tokenAuth', 'isSupervisorOfStudent'],
update_legend: ['tokenAuth'],
login: true, login: true,
create: ['tokenAuth'], create: ['tokenAuth'],
upload: ['tokenAuth'], upload: ['tokenAuth'],
......
...@@ -81,6 +81,7 @@ module.exports.routes = { ...@@ -81,6 +81,7 @@ module.exports.routes = {
'GET /stu/:id_stu/ws': 'StudentController.ws', 'GET /stu/:id_stu/ws': 'StudentController.ws',
'PUT /stu/:id_stu': 'StudentController.update', 'PUT /stu/:id_stu': 'StudentController.update',
'PUT /stu/:id_stu/picto/:id_stuPicto': 'StudentController.update_picto', 'PUT /stu/:id_stu/picto/:id_stuPicto': 'StudentController.update_picto',
'PUT /stu/:id_stu/legend/:legend_value': 'StudentController.update_legend',
'PUT /stu/:id_stu/picto': 'StudentController.update_picto', 'PUT /stu/:id_stu/picto': 'StudentController.update_picto',
'POST /stu/login': 'StudentController.login', 'POST /stu/login': 'StudentController.login',
'POST /stu': 'StudentController.create', 'POST /stu': 'StudentController.create',
......
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