Commit 85d680e8 by Fernando Martínez Santiago

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

# Conflicts:
#	android/Pictogram/Pictogram.iml
#	android/Pictogram/app/src/main/res/raw/pcbdb_create.sql
parents 7fb517e2 2d613873
Showing with 729 additions and 282 deletions
...@@ -22,15 +22,22 @@ sails/src/assets/app/modules ...@@ -22,15 +22,22 @@ sails/src/assets/app/modules
sails/src/assets/app/css sails/src/assets/app/css
sails/src/assets/app/js sails/src/assets/app/js
sails/src/assets/scripts/config.js sails/src/assets/scripts/config.js
# Other #
#########
sails/src/config/ssl/**/*.key sails/src/config/ssl/**/*.key
sails/src/config/ssl/**/*.crt sails/src/config/ssl/**/*.crt
sails/src/config/ssl/**/*.csr sails/src/config/ssl/**/*.csr
sails/src/config/local.js sails/src/config/local.js
sails/src/node_modules sails/src/node_modules
sails/.vagrant sails/.vagrant
sails/logs/
sails/npm-debug.log
sails/playbook.retry
sails/upload.zip
# NOT to be ignored #
# This files override sails-mysql files to support milliseconds timestamps #
############################################################################
!sails/src/node_modules/sails-mysql/lib/sql.js
!sails/src/node_modules/sails-mysql/lib/utils.js
# Android # # Android #
########### ###########
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" /> <excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content> </content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>
\ No newline at end of file
...@@ -31,7 +31,7 @@ android { ...@@ -31,7 +31,7 @@ android {
resValue "integer", "netservice_timing", "20" resValue "integer", "netservice_timing", "20"
} }
debug { debug {
resValue "string", "server", "https://dev.yottacode.com" //resValue "string", "server", "https://dev.yottacode.com"
resValue "bool", "force_db_create", "false" resValue "bool", "force_db_create", "false"
resValue "bool", "ssl_connect", "false" resValue "bool", "ssl_connect", "false"
resValue "bool", "force_img_download", "false" resValue "bool", "force_img_download", "false"
......
...@@ -43,11 +43,12 @@ public abstract class Action { ...@@ -43,11 +43,12 @@ public abstract class Action {
final String param_id_dev="id_dev"; final String param_id_dev="id_dev";
final String param_timestamp="timestamp"; final String param_timestamp="timestamp";
final Date currentTime = new Date(); final Date currentTime = new Date();
SimpleDateFormat datetime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); SimpleDateFormat datetime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
try { try {
JSONObject jsonObject = new JSONObject() JSONObject jsonObject = new JSONObject()
.put(param_id_stu, PCBcontext.getPcbdb().getCurrentUser().get_id_stu()) .put(param_id_stu, PCBcontext.getPcbdb().getCurrentUser().get_id_stu())
.put(param_timestamp, datetime.format(currentTime)); .put(param_timestamp, datetime.format(currentTime));
Log.d("TIMESTAMP-----------> ", datetime.format(currentTime));
if (PCBcontext.getPcbdb().getCurrentUser().has_supervisor()) if (PCBcontext.getPcbdb().getCurrentUser().has_supervisor())
jsonObject.put(param_id_sup,PCBcontext.getPcbdb().getCurrentUser().get_id_sup()); jsonObject.put(param_id_sup,PCBcontext.getPcbdb().getCurrentUser().get_id_sup());
//TODO Decidir qué almacenar con DEVICE //TODO Decidir qué almacenar con DEVICE
......
...@@ -27,11 +27,11 @@ SET time_zone = "+00:00"; ...@@ -27,11 +27,11 @@ SET time_zone = "+00:00";
CREATE TABLE IF NOT EXISTS `action` ( CREATE TABLE IF NOT EXISTS `action` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(20) COLLATE utf8_unicode_ci NOT NULL CHECK (type IN ('Add','Select','Delete','Show','Unshow','Pause','tryinit','tryend','initsession','endsession','pausesession','resumesession')), `type` varchar(20) COLLATE utf8_unicode_ci NOT NULL CHECK (type IN ('Add','Select','Delete','Show','Unshow','Pause','tryinit','tryend','initsession','endsession','pausesession','resumesession')),
`timestamp` timestamp DEFAULT CURRENT_TIMESTAMP, `timestamp` timestamp(3) DEFAULT CURRENT_TIMESTAMP(3),
`id_sup` int(11) DEFAULT NULL, `id_sup` int(11) DEFAULT NULL,
`id_stu` int(11) NOT NULL, `id_stu` int(11) NOT NULL,
`id_try` int(11) DEFAULT NULL, `id_try` int(11) DEFAULT NULL,
`description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'serialization of properties of the picto at the time of the action', `description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'serialization of properties of the picto at the time of the action',
`gps_lat` float DEFAULT NULL, `gps_lat` float DEFAULT NULL,
`gps_lon` float DEFAULT NULL, `gps_lon` float DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
...@@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS `action` ( ...@@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS `action` (
KEY `fk_stu_act` (`id_stu`), KEY `fk_stu_act` (`id_stu`),
KEY `id_try` (`id_try`) KEY `id_try` (`id_try`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="This table registers and action performed by a user at a given time, all information of the action is in JSON format in the 'description' column and the operation performed is one of the possible for the 'type' column"; COMMENT="This table registers and action performed by a user at a given time, all information of the action is in JSON format in the 'description' column and the operation performed is one of the possible for the 'type' column. NOTE: timestamps must support fractional seconds, so MySQL versions >= 5.6.4 are required.";
-- -------------------------------------------------------- -- --------------------------------------------------------
...@@ -70,10 +70,10 @@ COMMENT="Stores the expressions available in several languages for a given categ ...@@ -70,10 +70,10 @@ COMMENT="Stores the expressions available in several languages for a given categ
CREATE TABLE IF NOT EXISTS `method` ( CREATE TABLE IF NOT EXISTS `method` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, `description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`id_stu` int(11) NOT NULL, `id_stu` int(11) NOT NULL,
`registration` date DEFAULT NULL, `registration` date DEFAULT NULL,
`notes` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, `notes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `fk_stu_met` (`id_stu`) KEY `fk_stu_met` (`id_stu`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
...@@ -91,8 +91,8 @@ CREATE TABLE IF NOT EXISTS `instruction` ( ...@@ -91,8 +91,8 @@ CREATE TABLE IF NOT EXISTS `instruction` (
`name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, `name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`objective` varchar(512) COLLATE utf8_unicode_ci DEFAULT NULL, `objective` varchar(512) COLLATE utf8_unicode_ci DEFAULT NULL,
`status` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL CHECK (status IN ('started','finished')), `status` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL CHECK (status IN ('started','finished')),
`begin` timestamp NULL, `begin` timestamp(3) NULL,
`end` timestamp NULL, `end` timestamp(3) NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="An instruction is a 'phase' in a method for learning AAC"; COMMENT="An instruction is a 'phase' in a method for learning AAC";
...@@ -122,7 +122,7 @@ COMMENT="One in a set of instructions predefined or stored by users. They are re ...@@ -122,7 +122,7 @@ COMMENT="One in a set of instructions predefined or stored by users. They are re
CREATE TABLE IF NOT EXISTS `meta_method` ( CREATE TABLE IF NOT EXISTS `meta_method` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT, `id` tinyint(4) NOT NULL AUTO_INCREMENT,
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, `description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`id_sup` INT( 11 ) DEFAULT NULL, `id_sup` INT( 11 ) DEFAULT NULL,
UNIQUE(name,id_sup), UNIQUE(name,id_sup),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
...@@ -195,7 +195,7 @@ CREATE TABLE IF NOT EXISTS `picto_acl` ( ...@@ -195,7 +195,7 @@ CREATE TABLE IF NOT EXISTS `picto_acl` (
`id_sup` int(11) NOT NULL DEFAULT '0', `id_sup` int(11) NOT NULL DEFAULT '0',
`id_pic` int(11) NOT NULL DEFAULT '0', `id_pic` int(11) NOT NULL DEFAULT '0',
`privilege` varchar(1) COLLATE utf8_unicode_ci NOT NULL, `privilege` varchar(1) COLLATE utf8_unicode_ci NOT NULL,
`timestamp` datetime, `timestamp` timestamp(3),
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `k_pic_aclp` (`id_pic`), KEY `k_pic_aclp` (`id_pic`),
KEY `k_sup_aclp` (`id_sup`) KEY `k_sup_aclp` (`id_sup`)
...@@ -235,7 +235,7 @@ CREATE TABLE IF NOT EXISTS `picto_exp` ( ...@@ -235,7 +235,7 @@ CREATE TABLE IF NOT EXISTS `picto_exp` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `id_pic` (`id_pic`) KEY `id_pic` (`id_pic`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=72565 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=72565
COMMENT="Expression (text label) for a picto in different languages. This is used by the TTS engine"; COMMENT="Expression (text label) for a picto (or a category) in different languages. This is used by the TTS engine";
-- -------------------------------------------------------- -- --------------------------------------------------------
...@@ -264,7 +264,7 @@ COMMENT="Labels assigned to pictos by default or by supervisors"; ...@@ -264,7 +264,7 @@ COMMENT="Labels assigned to pictos by default or by supervisors";
CREATE TABLE IF NOT EXISTS `source` ( CREATE TABLE IF NOT EXISTS `source` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT, `id` tinyint(4) NOT NULL AUTO_INCREMENT,
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, `description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2
COMMENT="Contains all possible sources of pictos"; COMMENT="Contains all possible sources of pictos";
...@@ -285,9 +285,9 @@ CREATE TABLE IF NOT EXISTS `student` ( ...@@ -285,9 +285,9 @@ CREATE TABLE IF NOT EXISTS `student` (
`gender` char(1) COLLATE utf8_unicode_ci NOT NULL, `gender` char(1) COLLATE utf8_unicode_ci NOT NULL,
`country` char(2) COLLATE utf8_unicode_ci NOT NULL, `country` char(2) COLLATE utf8_unicode_ci NOT NULL,
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'defaultAvatar.jpg', `pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'defaultAvatar.jpg',
`notes` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, `notes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL, `lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`attributes` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Attributes describing student along with his/her configuration', `attributes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Attributes describing student along with his/her configuration',
`id_off` int(11) DEFAULT NULL, `id_off` int(11) DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`), UNIQUE KEY `username` (`username`),
...@@ -366,10 +366,10 @@ COMMENT="Supervisors information"; ...@@ -366,10 +366,10 @@ COMMENT="Supervisors information";
CREATE TABLE IF NOT EXISTS `try` ( CREATE TABLE IF NOT EXISTS `try` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`id_ws` int(11) NOT NULL, `id_ws` int(11) NOT NULL,
`begin` timestamp DEFAULT CURRENT_TIMESTAMP, `begin` timestamp(3) DEFAULT CURRENT_TIMESTAMP(3),
`end` timestamp NULL, `end` timestamp(3) NULL,
`result` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL, `result` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, `description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `id_ws` (`id_ws`) KEY `id_ws` (`id_ws`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
...@@ -388,10 +388,10 @@ CREATE TABLE IF NOT EXISTS `working_session` ( ...@@ -388,10 +388,10 @@ CREATE TABLE IF NOT EXISTS `working_session` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`id_sup` int(11) NOT NULL, `id_sup` int(11) NOT NULL,
`id_ins` int(11) NOT NULL, `id_ins` int(11) NOT NULL,
`begin` timestamp DEFAULT CURRENT_TIMESTAMP, `begin` timestamp(3) DEFAULT CURRENT_TIMESTAMP(3),
`end` timestamp NULL, `end` timestamp(3) NULL,
`current` boolean NULL DEFAULT 1, `current` boolean NULL DEFAULT 1,
`description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, `description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `id_sup` (`id_sup`), KEY `id_sup` (`id_sup`),
KEY `id_ins` (`id_ins`), KEY `id_ins` (`id_ins`),
......
...@@ -38,8 +38,8 @@ id_sup int(11) NOT NULL, ...@@ -38,8 +38,8 @@ id_sup int(11) NOT NULL,
id_ws int(11) NOT NULL, id_ws int(11) NOT NULL,
id_opentry int(11) , id_opentry int(11) ,
total_tries int DEFAULT 0, total_tries int DEFAULT 0,
begin timestamp NULL, begin timestamp(3) NULL,
end timestamp NULL, end timestamp(3) NULL,
PRIMARY KEY(id), PRIMARY KEY(id),
UNIQUE(id_stu), UNIQUE(id_stu),
UNIQUE(id_sup), UNIQUE(id_sup),
...@@ -142,9 +142,9 @@ thisTrigger: BEGIN ...@@ -142,9 +142,9 @@ thisTrigger: BEGIN
LEAVE thisTrigger; LEAVE thisTrigger;
END IF; END IF;
IF ((old.end IS NULL) and (new.end IS NOT NULL)) THEN IF ((old.end IS NULL) and (new.end IS NOT NULL)) THEN
CALL deleteOpenTry(new.id); CALL deleteOpenTry(new.id);
END IF; END IF;
END;; END;;
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
tags: tags:
- reset-test-database - reset-test-database
with_items: with_items:
- categories
- metadata - metadata
- categories
- name: Imports application essential data - name: Imports application essential data
mysql_db: mysql_db:
......
...@@ -11,6 +11,12 @@ ...@@ -11,6 +11,12 @@
- root_password_again - root_password_again
when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
- name: Install MySQL repos
apt:
deb: http://dev.mysql.com/get/mysql-apt-config_0.7.3-1_all.deb
state: present
when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
- name: Update apt-get cache - name: Update apt-get cache
apt: apt:
update-cache: yes update-cache: yes
...@@ -21,15 +27,17 @@ ...@@ -21,15 +27,17 @@
name: "{{ item }}" name: "{{ item }}"
state: present state: present
with_items: with_items:
- mysql-server - mysql-server-5.7
- mysql-client - mysql-client
- python-mysqldb # required by ansible - python-mysqldb # required by ansible
when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
- name: Add MySQL community repository - name: Add MySQL community repository
yum: yum:
name: "http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm" name: "http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm"
state: present state: present
when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7' when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '7'
- name: Install mysql packages - name: Install mysql packages
yum: yum:
name: "{{ item }}" name: "{{ item }}"
......
...@@ -42,7 +42,7 @@ module.exports = { ...@@ -42,7 +42,7 @@ module.exports = {
if (!params.type) return res.json(500, {error: "No type of action defined"}); if (!params.type) return res.json(500, {error: "No type of action defined"});
// Optional params // Optional params
var timestamp = null; if(params.timestamp) timestamp = params.timestamp; var timestamp = params.timestamp ? params.timestamp : null;
var sup = null; if(params.supervisor) sup = params.supervisor; var sup = null; if(params.supervisor) sup = params.supervisor;
var _try = null; if(params._try) _try = params._try; var _try = null; if(params._try) _try = params._try;
var description = null; if(params.description) description = params.description; var description = null; if(params.description) description = params.description;
...@@ -59,18 +59,20 @@ module.exports = { ...@@ -59,18 +59,20 @@ module.exports = {
"description": description, "description": description,
"gpsLat": gpsLat, "gpsLat": gpsLat,
"gpsLon": gpsLon "gpsLon": gpsLon
}).exec(function(err, created){ })
if(err || !created) return res.json(500, { error: "Error saving an action "+ params.type +": " + err }); .then(function(created){
if(created) { if (!created)
StuOpenTry.findOne({id_stu : params.student}).exec(function(err, data){ throw new Error("Action.create returned NULL");
if(err || !data){
sails.log.error("Error finding try for student "+ params.student + ' when creating action '+ params.type); StuOpenTry.findOne({id_stu : params.student})
return res.json(500, {error: 'Action '+ params.type +' not created'}); .then(function(data){
} if(!data)
sails.log.debug("Try for student "+params.student+ ":"+JSON.stringify(data)); throw new Error("Error finding try for student "+ params.student + ' when creating action '+ params.type);
return res.json(200,{open_try: data.openTry }); return res.ok({open_try: data.openTry });
}) })
} })
.fail(function(err) {
res.serverError("Error saving an action "+ params.type +": " + err);
}); });
}, },
...@@ -100,7 +102,7 @@ module.exports = { ...@@ -100,7 +102,7 @@ module.exports = {
Action.create({ Action.create({
type: a.action, type: a.action,
timestamp: a.attributes.timestamp, timestamp: a.attributes.timestamp.toISOString(),
supervisor: sup, supervisor: sup,
student: params.student, student: params.student,
description: desc description: desc
......
...@@ -80,7 +80,10 @@ module.exports = { ...@@ -80,7 +80,10 @@ module.exports = {
if (supervisor) { if (supervisor) {
Picto.find({ category: req.params.id_cat }) Picto.find({ category: req.params.id_cat })
.populate('expressions', { lang: supervisor.lang }) .populate('expressions', { lang: supervisor.lang })
.then(pictos => res.ok(pictos)) .then(function (pictos) {
sails.log.debug(pictos.length + " pictos sent for category " + req.params.id_cat + " in language " + supervisor.lang);
res.ok(pictos);
})
.catch(() => res.badRequest()); .catch(() => res.badRequest());
} else { } else {
res.badRequest(); res.badRequest();
...@@ -271,18 +274,19 @@ module.exports = { ...@@ -271,18 +274,19 @@ module.exports = {
* { * {
* id: pictoId, * id: pictoId,
* source: 1, * source: 1,
* owner: supervisorId * owner: supervisorId,
* uri: 'https://path/to/picto/in/the/web'
* } * }
*/ */
upload: function (req, res) { upload: function (req, res) {
Supervisor.findOne({ id: req.body.owner }).then(function (supervisor) { Supervisor.findOne({ id: req.body.owner }).then(function (supervisor) {
var pictoFileName; var pictoFileName;
var pictoDirectory = sails.config.pictogram.paths.supervisorCustomPictoDirectory; var pictoDirectory = sails.config.pictogram.paths.supervisorCustomPictoDirectory;
if (!supervisor) { if (!supervisor) {
throw new Error(); throw new Error();
} }
pictoFileName = sails.config.pictogram.paths.getSupervisorCustomPictoFileName(supervisor.id); pictoFileName = sails.config.pictogram.paths.getSupervisorCustomPictoFileName(supervisor.id);
sails.log.debug("Uploading picto with FileName: " + pictoFileName);
req.file('file').upload({ req.file('file').upload({
maxBytes: 1000000, maxBytes: 1000000,
......
...@@ -133,6 +133,7 @@ module.exports = { ...@@ -133,6 +133,7 @@ module.exports = {
Student.create(params) Student.create(params)
.exec(function (err, created) { .exec(function (err, created) {
if (err) { if (err) {
console.log(err);
sails.log.debug(err); sails.log.debug(err);
return res.json(500, err); return res.json(500, err);
} }
...@@ -410,10 +411,16 @@ module.exports = { ...@@ -410,10 +411,16 @@ module.exports = {
supervisor: req.param('id_sup') supervisor: req.param('id_sup')
}) })
.then((stuSup) => { .then((stuSup) => {
if (!stuSup) { if (!stuSup)
res.badRequest(); res.badRequest();
throw new Error('stusup not found');
} stuSup.destroy({
student: req.param('id_stu'),
supervisor: req.param('id_sup')
}).then(function(err){
if (err)
throw err;
});
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(
...@@ -1001,15 +1008,29 @@ module.exports = { ...@@ -1001,15 +1008,29 @@ module.exports = {
} }
}, },
// /**
// Logs a TRY action and broadcast to anyone subscribed to this student * Logs a TRY action and broadcast to anyone subscribed to this student
* @param {request} req
* {
* "action": <action> ("add", "delete", ...),
* "attributes": {
* "id_stu": <id_stu>,
* "timestamp": <timestamp_string_in_ISO_format> (e.g.: "2016-07-13 17:50:00.224+0200"),
* "picto": {...}
* }
* }
* @param {response} res {<action_created>}
*/
action: function (req, res) { action: function (req, res) {
var action = req.param('action'); var action = req.param('action');
var attributes = req.param('attributes'); var attributes = req.param('attributes');
sails.log.debug("Inside action. Student:" + attributes.id_stu); sails.log.debug("Inside action. Student:" + attributes.id_stu);
if (req.isSocket) { 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)); sails.log.debug("websockets - room " + sails.hooks.rooms.student(attributes.id_stu));
// BROADCAST to everyone subscribed to this student // BROADCAST to everyone subscribed to this student
const socketToOmit = (req.isSocket) ? req.socket : undefined; const socketToOmit = (req.isSocket) ? req.socket : undefined;
...@@ -1028,29 +1049,20 @@ module.exports = { ...@@ -1028,29 +1049,20 @@ module.exports = {
Action.create({ Action.create({
type: action, type: action,
timestamp: attributes.timestamp, timestamp: attributes.timestamp, // it comes already in ISO format
supervisor: sup, supervisor: sup,
student: attributes.id_stu, student: attributes.id_stu,
description: desc description: desc
}) })
.exec(function (err, created) { .then(function (created) {
if (err) { res.json({
sails.log.error(err.details); action: created
res.serverError(err.details); });
} })
else if (created) .fail(function(err) {
res.json({ sails.log.error(err.details);
action: created res.serverError(err.details);
});
});
/*
res.json({
msg: "Action "+ action +" action from student " + attributes.id_stu
}); });
*/
} else {
sails.log.debug("No socket request for action");
} }
}, },
......
...@@ -83,17 +83,17 @@ module.exports = { ...@@ -83,17 +83,17 @@ module.exports = {
res.serverError(); res.serverError();
}); });
} else { } else {
res.badRequest('Invalid user or password'); res.badRequest('Invalid password');
} }
} else { } else {
res.badRequest('Invalid user or password'); res.badRequest('Invalid user');
} }
}) })
.catch(function () { .catch(function () {
res.badRequest('Invalid user or password'); res.badRequest('Invalid user or password');
}); });
} else { } else {
res.badRequest('Invalid user or password'); res.badRequest('No email or or password');
} }
}, },
...@@ -374,10 +374,9 @@ module.exports = { ...@@ -374,10 +374,9 @@ module.exports = {
student.supervision = req.token.office ? 2 : 1; student.supervision = req.token.office ? 2 : 1;
return student; return student;
}); });
if (req.token.isSupAdmin && req.token.office && req.token.office.id) { if (req.token.isSupAdmin && req.token.office && req.token.office.id) {
Student.find({ office: req.token.office.id }).then(function (officeStudents) { Student.find({ office: req.token.office.id }).then(function (officeStudents) {
students.concat(officeStudents); students = students.concat(officeStudents);
students = students.map((student) => { students = students.map((student) => {
student.supervision = student.supervision || 0; student.supervision = student.supervision || 0;
return student; return student;
......
...@@ -73,5 +73,10 @@ module.exports = { ...@@ -73,5 +73,10 @@ module.exports = {
columnName: "gps_lon", columnName: "gps_lon",
type: "float" type: "float"
} }
} },
beforeCreate: function (attrs, next) {
sails.log.debug("Inserting action with following attrs: " + JSON.stringify(attrs));
next();
},
}; };
...@@ -169,6 +169,8 @@ module.exports = { ...@@ -169,6 +169,8 @@ module.exports = {
tape_background: '#00ffff' tape_background: '#00ffff'
}; };
sails.log.verbose('Requested attributes for Student', attributes);
if (typeof attributes === 'object') { if (typeof attributes === 'object') {
Object.keys(defaultAttributes).forEach((attribute) => { Object.keys(defaultAttributes).forEach((attribute) => {
if (defaultAttributes.hasOwnProperty(attribute) && attributes.hasOwnProperty(attribute)) { if (defaultAttributes.hasOwnProperty(attribute) && attributes.hasOwnProperty(attribute)) {
......
...@@ -30,7 +30,7 @@ module.exports = { ...@@ -30,7 +30,7 @@ module.exports = {
columnName: "id_ins", columnName: "id_ins",
required: true, required: true,
type: "integer", type: "integer",
model: "Instruction" model: "Instruction"
}, },
begin: { begin: {
type: "datetime", type: "datetime",
...@@ -40,21 +40,50 @@ module.exports = { ...@@ -40,21 +40,50 @@ module.exports = {
type: "datetime" type: "datetime"
}, },
current: { current: {
type: "integer", type: "integer",
}, },
description: { description: {
type: "string", type: "string",
size: 1024 size: 1024
}, },
// Relación con Try. [1 WorkingSession to N Try] // Relación con Try. [1 WorkingSession to N Try]
tries: { tries: {
collection: 'Try', collection: 'Try',
via: "workingSession" via: "workingSession"
} }
}, },
/**
* Checks a previous session is not opened for that supervisor. If so,
* session is closed (current is set to 0)
* @param {Object} attrs All session properties to be stored
* @param {Function} next Function to be executed when the check process
* has been completed (an error object will be passed
* to the function if necesary)
*/
beforeCreate: function (attrs, next) {
WorkingSession.find({id_sup: attrs.supervisor, current: 1})
.then(function(wss) {
if (wss) {
async.each(wss, function(ws, cb) {
ws.current = 0;
WorkingSession.update(ws.id, ws, function(err, update) {
if (err) throw new Error("Error when udpating open sessions");
cb();
});
});
}
next();
})
.fail(function(err) {
next(err);
})
},
// //
// Returns the number of working sessions per year (REPORTS) // Returns the number of working sessions per year (REPORTS)
// //
per_year: function(id_stu, year, callback) { per_year: function(id_stu, year, callback) {
var l = []; var l = [];
...@@ -65,18 +94,18 @@ module.exports = { ...@@ -65,18 +94,18 @@ module.exports = {
// eachSeries // eachSeries
async.eachSeries( async.eachSeries(
// 1st array of items // 1st array of items
months, months,
// 2nd function to operate over one item // 2nd function to operate over one item
function(month, next) { function(month, next) {
var month_1 = year +'-'+ month +'-01'; // 2015-1-01 var month_1 = year +'-'+ month +'-01'; // 2015-1-01
var month_2 = (month<12) ? (year +'-'+ (month+1) +'-01') : ((year+1) +'-01-01'); // 2015-2-01 ó 2016-01-01 var month_2 = (month<12) ? (year +'-'+ (month+1) +'-01') : ((year+1) +'-01-01'); // 2015-2-01 ó 2016-01-01
WorkingSession.count({ WorkingSession.count({
'id_stu' : id_stu, 'id_stu' : id_stu,
'begin' : { 'begin' : {
'>=' : month_1, '>=' : month_1,
'<' : month_2 '<' : month_2
} }
}).exec(function(err, ws) { }).exec(function(err, ws) {
if (err) if (err)
...@@ -84,7 +113,7 @@ module.exports = { ...@@ -84,7 +113,7 @@ module.exports = {
if(!ws) if(!ws)
console.log("No ws in this month"); console.log("No ws in this month");
if(ws) if(ws)
console.log(JSON.stringify(ws)); console.log(JSON.stringify(ws));
...@@ -99,7 +128,7 @@ module.exports = { ...@@ -99,7 +128,7 @@ module.exports = {
}, },
// 3rd final function when all is ready // 3rd final function when all is ready
function (err){ function (err){
console.log("It's the final functiooonnnnnnnn....."); console.log("It's the final functiooonnnnnnnn.....");
console.log(JSON.stringify(l)); console.log(JSON.stringify(l));
return callback(err, l); return callback(err, l);
...@@ -111,7 +140,7 @@ module.exports = { ...@@ -111,7 +140,7 @@ module.exports = {
// //
// Returns the number of working sessions per month (REPORTS) // Returns the number of working sessions per month (REPORTS)
// //
per_month: function(id_stu, month, callback) { per_month: function(id_stu, month, callback) {
var l = []; var l = [];
...@@ -122,18 +151,18 @@ module.exports = { ...@@ -122,18 +151,18 @@ module.exports = {
// eachSeries // eachSeries
async.eachSeries( async.eachSeries(
// 1st array of items // 1st array of items
months, months,
// 2nd function to operate over one item // 2nd function to operate over one item
function(month, next) { function(month, next) {
var month_1 = year + '-'+ month +'-01'; // 2015-1-01 var month_1 = year + '-'+ month +'-01'; // 2015-1-01
var month_2 = (month<12) ? (year +'-'+ (month+1) +'-01') : ((year+1) +'-01-01'); // 2015-2-01 ó 2016-01-01 var month_2 = (month<12) ? (year +'-'+ (month+1) +'-01') : ((year+1) +'-01-01'); // 2015-2-01 ó 2016-01-01
WorkingSession.count({ WorkingSession.count({
'id_stu' : id_stu, 'id_stu' : id_stu,
'begin' : { 'begin' : {
'>=' : month_1, '>=' : month_1,
'<' : month_2 '<' : month_2
} }
}).exec(function(err, ws) { }).exec(function(err, ws) {
if (err) if (err)
...@@ -141,7 +170,7 @@ module.exports = { ...@@ -141,7 +170,7 @@ module.exports = {
if(!ws) if(!ws)
console.log("No ws in this month"); console.log("No ws in this month");
if(ws) if(ws)
console.log(JSON.stringify(ws)); console.log(JSON.stringify(ws));
...@@ -154,7 +183,7 @@ module.exports = { ...@@ -154,7 +183,7 @@ module.exports = {
}, },
// 3rd final function when all is ready // 3rd final function when all is ready
function (err){ function (err){
console.log("It's the final functiooonnnnnnnn....."); console.log("It's the final functiooonnnnnnnn.....");
console.log(JSON.stringify(l)); console.log(JSON.stringify(l));
return callback(err, l); return callback(err, l);
......
...@@ -80,9 +80,11 @@ ...@@ -80,9 +80,11 @@
"enlarge": "Enlarge", "enlarge": "Enlarge",
"enormous": "Enormous", "enormous": "Enormous",
"error_adding_picto": "Error adding picto", "error_adding_picto": "Error adding picto",
"error_creating_session": "Error when creating session",
"error_deleting_picto": "Error deleting picto", "error_deleting_picto": "Error deleting picto",
"error_downloading_supervisors": "Error downloading supervisors", "error_downloading_supervisors": "Error downloading supervisors",
"error_downloading_offices": "Error downloading offices", "error_downloading_offices": "Error downloading offices",
"error_fetching_students": "Error when loading students",
"error_only_support_images": "Only images are supported (JPG, PNG or GIF files)", "error_only_support_images": "Only images are supported (JPG, PNG or GIF files)",
"error_loading_pictos": "Error loading pictos information", "error_loading_pictos": "Error loading pictos information",
"expand_navigation": "Expand navigation", "expand_navigation": "Expand navigation",
...@@ -125,6 +127,7 @@ ...@@ -125,6 +127,7 @@
"loading_pictos": "Loading pictos", "loading_pictos": "Loading pictos",
"login": "Log In", "login": "Log In",
"login_fail": "Invalid user or password", "login_fail": "Invalid user or password",
"login_footer": "Pictogram is a product by <a href='http://www.yottacode.com'>Yottacode S.L.</a> for Augmentative and Alternative Communication, loaded with more than 20,000 images from the <a href=''>SymbolStix</a> collection, in several languages. From here, you will be able to manage devices with official <i>Pictogram Tablet</i> app installed.",
"login_success": "Login succeed. Welcome {{name}}", "login_success": "Login succeed. Welcome {{name}}",
"logout": "Log Out", "logout": "Log Out",
"man": "Man", "man": "Man",
......
...@@ -83,9 +83,11 @@ ...@@ -83,9 +83,11 @@
"expand_navigation": "Desplegar navegación", "expand_navigation": "Desplegar navegación",
"expression": "Expresión:", "expression": "Expresión:",
"error_adding_picto": "Error al añadir el picto", "error_adding_picto": "Error al añadir el picto",
"error_creating_session": "Error al crear sesión",
"error_deleting_picto": "Error borrando el picto", "error_deleting_picto": "Error borrando el picto",
"error_downloading_supervisors": "Error al descargar los supervisores", "error_downloading_supervisors": "Error al descargar los supervisores",
"error_downloading_offices": "Error al descargar las oficinas", "error_downloading_offices": "Error al descargar las oficinas",
"error_fetching_students": "Error al cargar estudiantes",
"error_only_support_images": "Sólo se soportan imágenes (ficheros JPG, PNG o GIF)", "error_only_support_images": "Sólo se soportan imágenes (ficheros JPG, PNG o GIF)",
"error_loading_pictos": "Error cargando información de los pictos", "error_loading_pictos": "Error cargando información de los pictos",
"February": "Febrero", "February": "Febrero",
...@@ -125,6 +127,7 @@ ...@@ -125,6 +127,7 @@
"loading_pictos": "Cargando pictos", "loading_pictos": "Cargando pictos",
"login": "Iniciar sesión", "login": "Iniciar sesión",
"login_fail": "Usuario o contraseña incorrectos", "login_fail": "Usuario o contraseña incorrectos",
"login_footer": "Pictogram es un producto de <a href='http://www.yottacode.com'>Yottacode S.L.</a> para Comunicación Aumentativa y Alternativa, cargado con más los más de 20,000 pictogramas de <a href=''>SymbolStix</a>, en varios idiomas. Desde aquí podrás gestionar los dispositivos que dispongan de la app oficial <i>Pictogram Tablet</i>.",
"login_success": "Login correcto. Bienvenido {{name}}", "login_success": "Login correcto. Bienvenido {{name}}",
"logout": "Salir", "logout": "Salir",
"man": "Hombre", "man": "Hombre",
......
...@@ -20,12 +20,12 @@ var dashboardControllers = angular.module('dashboardControllers', ['dashboardCon ...@@ -20,12 +20,12 @@ var dashboardControllers = angular.module('dashboardControllers', ['dashboardCon
// Main Controller // Main Controller
// //
// //
dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $location, $translate) { dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $location, $translate, $rootScope) {
// Always use objects if we want to modify this scope in the childs // Always use objects if we want to modify this scope in the childs
// Save name and surname in global scope // Save name and surname in global scope
$scope.user = { $scope.user = {
id: '', id: '',
name: '', name: '',
surname: '', surname: '',
...@@ -43,7 +43,7 @@ dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $ ...@@ -43,7 +43,7 @@ dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $
lang = 'es-es'; lang = 'es-es';
$translate.use(lang); $translate.use(lang);
//$translateProvider.preferredLanguage('es-es'); //$translateProvider.preferredLanguage('es-es');
//--------------------------------------------------------------- //---------------------------------------------------------------
...@@ -56,6 +56,14 @@ dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $ ...@@ -56,6 +56,14 @@ dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $
$scope.logout(); $scope.logout();
}); });
//-------------------------------------------
// For scrolling when using routig
//
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
$location.hash($routeParams.scrollTo);
$anchorScroll();
});
//--------------------------------------------------------------- //---------------------------------------------------------------
// Controller's functions // Controller's functions
// //
...@@ -77,4 +85,4 @@ dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $ ...@@ -77,4 +85,4 @@ dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $
// Redirect to login // Redirect to login
$location.path('/login'); $location.path('/login');
}; };
}); });
\ No newline at end of file
...@@ -13,7 +13,9 @@ dashboardControllers.controller('StudentCollectionsCtrl', function StudentCollec ...@@ -13,7 +13,9 @@ dashboardControllers.controller('StudentCollectionsCtrl', function StudentCollec
$http, $http,
config, config,
$window, $window,
$location,
$filter, $filter,
$anchorScroll,
$modal) { $modal) {
$scope.emptyStudentPicto = { $scope.emptyStudentPicto = {
id: null, id: null,
...@@ -119,11 +121,8 @@ dashboardControllers.controller('StudentCollectionsCtrl', function StudentCollec ...@@ -119,11 +121,8 @@ dashboardControllers.controller('StudentCollectionsCtrl', function StudentCollec
$scope.show_category = function (studentPicto) { $scope.show_category = function (studentPicto) {
if ($scope.isCategory(studentPicto)) { if ($scope.isCategory(studentPicto)) {
$scope.selectedCategory = studentPicto; $scope.selectedCategory = studentPicto;
setTimeout(function () { $location.hash('picto-category-grid');
$(document.body).animate({ $anchorScroll();
scrollTop: $('#picto-category-grid').position().top
}, 500);
}, 0);
} }
}; };
......
...@@ -3,7 +3,14 @@ ...@@ -3,7 +3,14 @@
//----------------------- //-----------------------
// Student Session Controller // Student Session Controller
//----------------------- //-----------------------
dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtrl($scope, $stateParams, $http, config, $window) { dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtrl(
$scope,
$stateParams,
$http,
config,
$window,
$translate,
ngToast) {
...@@ -121,8 +128,10 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr ...@@ -121,8 +128,10 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
//Modify the desc. of a try //Modify the desc. of a try
$scope.update_try = function(t){ $scope.update_try = function(t){
var update_data={}; var update_data={};
if (t.description!=null) update_data.description=t.description; if (t.description)
if (t.result!=null) update_data.result=t.result; update_data.description = t.description;
if (t.result)
update_data.result = t.result;
$http $http
.put(config.backend+'/try/' + t.id, update_data) .put(config.backend+'/try/' + t.id, update_data)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
...@@ -183,12 +192,10 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr ...@@ -183,12 +192,10 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
.post(config.backend+ '/ws/'+$scope.wsessions[0].id+'/close') .post(config.backend+ '/ws/'+$scope.wsessions[0].id+'/close')
.then( .then(
function(data, status, headers, config) { function(data, status, headers, config) {
$scope.wsessions[0].end=data.data.end; $scope.wsessions[0].end=data.data.end;
$scope.ws_recover=false; $scope.ws_recover=false;
} }
, function(data, status, headers, config) { ,function(data, status, headers, config) {
} }
); );
} }
...@@ -206,7 +213,8 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr ...@@ -206,7 +213,8 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
.post(config.backend+'/ws', { .post(config.backend+'/ws', {
"id_sup": $scope.user.id, "id_sup": $scope.user.id,
"id_stu": $scope.studentData.id, "id_stu": $scope.studentData.id,
"id_ins": $scope.selectedIns "id_ins": $scope.selectedIns.id,
"begin": new Date().toISOString()
}) })
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
...@@ -229,20 +237,20 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr ...@@ -229,20 +237,20 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
$scope.studentData.current_instruction=$scope.selectedIns.name; $scope.studentData.current_instruction=$scope.selectedIns.name;
}) })
.error(function(data, status, headers, config) { .error(function(data, status, headers, config) {
$translate('error_creating_session').then(function (translation) {
ngToast.danger({ content: translation });
});
}); });
}; }
// //
// update the description of a given working session // update the description of a given working session
// //
$scope.update_ws = function (ws){ $scope.update_ws = function (ws){
$http $http
.put(config.backend+'/ws/' + ws.id, { "description" : ws.description }) .put(config.backend+'/ws/' + ws.id, { "description" : ws.description })
.then(function(data, status, headers, config) { .then(function(data, status, headers, config) {
// TODO notify update?
}) })
,function(data, status, headers, config) { ,function(data, status, headers, config) {
...@@ -252,16 +260,21 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr ...@@ -252,16 +260,21 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
// //
// Finish a working session updating its end time // Finish a working session updating its end time
// //
$scope.stop_ws = function (){ $scope.stop_ws = function () {
// For view // For view
$scope.sessionRunning = false; $scope.sessionRunning = false;
if ($scope.wsessions.length>0) $scope.wsessions[$scope.wsessions.length-1].tries.pop(); if ($scope.wsessions.length>0)
$scope.ws.end = new Date(); $scope.wsessions[$scope.wsessions.length-1].tries.pop();
$scope.ws.end = new Date().toISOString();
$http
.put(config.backend+'/ws/' + $scope.ws.id, { "end": $scope.ws.end, $http
"id_stu": $scope.studentData.id .post(
}) config.backend+'/ws/' + $scope.ws.id + '/close',
{
"end": $scope.ws.end,
"id_stu": $scope.studentData.id
}
)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
// Empty actual WS and actual try // Empty actual WS and actual try
...@@ -376,26 +389,22 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr ...@@ -376,26 +389,22 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
// what data has updated, and refresh what needs to be refreshed. // what data has updated, and refresh what needs to be refreshed.
if($scope.ws){ if($scope.ws){
console.log(data.action);
switch(data.action){ switch(data.action){
case 'Add': case 'Add':
$scope.actual_try.actions.push(data); $scope.actual_try.actions.push(data);
break; break;
case 'Delete': case 'Delete':
$scope.actual_try.actions.push(data); $scope.actual_try.actions.push(data);
break; break;
case 'Select': case 'Select':
$scope.actual_try.actions.push(data); $scope.actual_try.actions.push(data);
break; break;
case 'Show': case 'Show':
$scope.load_tries($scope.selectedIns);
$scope.load_tries($scope.selectedIns);
// Empty actual try and push the first action of next try // Empty actual try and push the first action of next try
$scope.actual_try.actions = []; $scope.actual_try.actions = [];
$scope.actual_try.actions.push({ action: 'tryinit' }); $scope.actual_try.actions.push({ action: 'tryinit' });
break; break;
} }
} }
......
...@@ -78,6 +78,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl( ...@@ -78,6 +78,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
*/ */
$scope.updateStudent = function () { $scope.updateStudent = function () {
var password; var password;
var attrs;
if ($scope.formUser.password_confirm || $scope.formUser.password) { if ($scope.formUser.password_confirm || $scope.formUser.password) {
if ($scope.formUser.password_confirm === $scope.formUser.password) { if ($scope.formUser.password_confirm === $scope.formUser.password) {
...@@ -90,7 +91,8 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl( ...@@ -90,7 +91,8 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
} }
} }
$http.put(config.backend + '/stu/' + $scope.studentData.id, {
attrs = {
birthdate: $scope.formUser.birthdate, birthdate: $scope.formUser.birthdate,
country: $scope.formUser.country, country: $scope.formUser.country,
gender: $scope.formUser.gender, gender: $scope.formUser.gender,
...@@ -99,8 +101,12 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl( ...@@ -99,8 +101,12 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
notes: $scope.formUser.notes, notes: $scope.formUser.notes,
surname: $scope.formUser.surname, surname: $scope.formUser.surname,
username: $scope.formUser.username, username: $scope.formUser.username,
password: password };
})
if (password)
attrs.password = password;
$http.put(config.backend + '/stu/' + $scope.studentData.id, attrs)
.success(function (data) { .success(function (data) {
$translate('student_updated').then(function (translation) { $translate('student_updated').then(function (translation) {
ngToast.success({ content: translation }); ngToast.success({ content: translation });
......
...@@ -48,9 +48,10 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl( ...@@ -48,9 +48,10 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
// WebSockets communication // WebSockets communication
// //
io.socket.on('update_peers', function (data) { io.socket.on('update_peers', function (data) {
$translate('num_peers').then(function (translation) { // REMOVED (too invasive)
ngToast.success(translation + ': ' + data.count); // $translate('num_peers').then(function (translation) {
}); // ngToast.success(translation + ': ' + data.count);
//});
$scope.studentData.num_peers = data.count; $scope.studentData.num_peers = data.count;
}); });
......
...@@ -125,6 +125,7 @@ ...@@ -125,6 +125,7 @@
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</div> </div>
<a name="picto-category-grid"/>
<div <div
id="picto-category-grid" id="picto-category-grid"
class="picto-grid picto-category-grid" class="picto-grid picto-category-grid"
......
...@@ -44,10 +44,10 @@ ...@@ -44,10 +44,10 @@
<img ng-src="{{ a.attributes.picto.picto.uri }}" /> <img ng-src="{{ a.attributes.picto.picto.uri }}" />
<div class="action-type"> <div class="action-type">
<span ng-if="a.action == 'add'" class="glyphicon glyphicon-plus color_green" aria-hidden="true"></span> <span ng-if="a.action == 'add'" class="glyphicon glyphicon-plus color_green" aria-hidden="true"></span>
<span ng-if="a.action == 'select'" class="glyphicon glyphicon-hand-up color_blue" aria-hidden="true"></span> <span ng-if="a.action == 'Select'" class="glyphicon glyphicon-hand-up color_blue" aria-hidden="true"></span>
<span ng-if="a.action == 'delete'" class="glyphicon glyphicon-remove color_red" aria-hidden="true"></span> <span ng-if="a.action == 'Delete'" class="glyphicon glyphicon-remove color_red" aria-hidden="true"></span>
<span ng-if="a.action == 'show'" class="glyphicon glyphicon-eye-open color_blue" aria-hidden="true"></span> <span ng-if="a.action == 'Show'" class="glyphicon glyphicon-eye-open color_blue" aria-hidden="true"></span>
<span ng-if="a.action == 'unshow'" class="glyphicon glyphicon-edit color_blue" aria-hidden="true"></span> <span ng-if="a.action == 'Unshow'" class="glyphicon glyphicon-edit color_blue" aria-hidden="true"></span>
<span ng-if="a.action == 'tryinit'" class="glyphicon glyphicon-log-in" aria-hidden="true"></span> <span ng-if="a.action == 'tryinit'" class="glyphicon glyphicon-log-in" aria-hidden="true"></span>
<span ng-if="a.action == 'tryend'" class="glyphicon glyphicon-log-out" aria-hidden="true"></span> <span ng-if="a.action == 'tryend'" class="glyphicon glyphicon-log-out" aria-hidden="true"></span>
<span ng-if="a.action == 'pausesession'" class="glyphicon glyphicon-pause" aria-hidden="true"></span> <span ng-if="a.action == 'pausesession'" class="glyphicon glyphicon-pause" aria-hidden="true"></span>
......
...@@ -49,7 +49,12 @@ ...@@ -49,7 +49,12 @@
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control" id="student_country" placeholder="{{ 'country' | translate }}" ng-model="formUser.country" /> <select class="form-control" name="student_country" id="student_country" ng-model="formUser.country" required>
<option value="ES">España</option>
<option value="US">United States</option>
<option value="UK">United Kingdom</option>
<option value="IE">Ireland</option>
</select>
</div> </div>
</fieldset> </fieldset>
......
...@@ -53,7 +53,9 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -53,7 +53,9 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$scope.students = data; $scope.students = data;
}) })
.error(function () { .error(function () {
// TODO show error with ngToast $translate('error_fetching_students').then(function (translation) {
ngToast.danger({ content: translation });
});
}); });
// Reset form Student // Reset form Student
...@@ -70,7 +72,6 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -70,7 +72,6 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
gender: 'F', gender: 'F',
lang: 'es-es', lang: 'es-es',
notes: '', notes: '',
pic: '/app/img/default.jpg',
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'
......
<h3 class="color_green" translate>add_student</h3> <h3 class="color_green" translate>add_student</h3>
<form name="AddStudentForm" role="form" ng-submit="add_student()" ng-controller="StudentAddCtrl"> <form name="AddStudentForm" role="form" ng-submit="add_student()" ng-controller="StudentAddCtrl">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
...@@ -45,7 +45,13 @@ ...@@ -45,7 +45,13 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control" id="student_country" placeholder="{{ 'country' | translate }}" ng-model="formdatastudent.country" /> <legend translate>country</legend>
<select class="form-control" name="student_country" id="student_country" ng-model="formdatastudent.country" required>
<option value="ES" selected>España</option>
<option value="US">United States</option>
<option value="UK">United Kingdom</option>
<option value="IE">Ireland</option>
</select>
</div> </div>
</fieldset> </fieldset>
</div> </div>
...@@ -77,4 +83,4 @@ ...@@ -77,4 +83,4 @@
</div> </div>
</form> </form>
<hr /> <hr />
\ No newline at end of file
/**
* Local environment settings
*
* Use this file to specify configuration settings for use while developing
* the app on your personal system: for example, this would be a good place
* to store database or email passwords that apply only to you, and shouldn't
* be shared with others in your organization.
*
* These settings take precedence over all other config files, including those
* in the env/ subfolder.
*
* PLEASE NOTE:
* local.js is included in your .gitignore, so if you're using git
* as a version control solution for your Sails app, keep in mind that
* this file won't be committed to your repository!
*
* Good news is, that means you can specify configuration for your local
* machine in this file without inadvertently committing personal information
* (like database passwords) to the repo. Plus, this prevents other members
* of your team from commiting their local configuration changes on top of yours.
*
* In a production environment, you probably want to leave this file out
* entirely and leave all your settings in env/production.js
*
*
* For more information, check out:
* http://sailsjs.org/#!/documentation/anatomy/myApp/config/local.js.html
*/
const path = require('path');
const fs = require('fs');
module.exports = {
/**
* Your SSL certificate and key, if you want to be able to serve HTTP
* responses over https:// and/or use websockets over the wss:// protocol
* (recommended for HTTP, strongly encouraged for WebSockets)
*/
ssl: {
// ca: fs.readFileSync(path.join(__dirname, 'ssl', 'bundle.crt')),
key: fs.readFileSync(path.join(__dirname, 'ssl', 'key.key')),
cert: fs.readFileSync(path.join(__dirname, 'ssl', 'cert.crt')),
},
/**
* The `port` setting determines which TCP port your app will be
* deployed on.
*
* By default, if it's set, Sails uses the `PORT` environment variable.
* Otherwise it falls back to port 1337.
*
* In env/production.js, you'll probably want to change this setting
* to 80 (http://) or 443 (https://) if you have an SSL certificate
*/
port: process.env.PORT || 1337,
/*
* The runtime "environment" of your Sails app is either typically
* 'development' or 'production'.
*
* In development, your Sails app will go out of its way to help you
* (for instance you will receive more descriptive error and
* debugging output)
*
* In production, Sails configures itself (and its dependencies) to
* optimize performance. You should always put your app in production mode
* before you deploy it to a server. This helps ensure that your Sails
* app remains stable, performant, and scalable.
*
* By default, Sails sets its environment using the `NODE_ENV` environment
* variable. If NODE_ENV is not set, Sails will run in the
* 'development' environment.
*/
environment: process.env.NODE_ENV || 'development',
};
...@@ -75,7 +75,10 @@ module.exports.routes = { ...@@ -75,7 +75,10 @@ module.exports.routes = {
'POST /stu/:id_stu/picto/:id_picto': 'StudentController.add_picto', 'POST /stu/:id_stu/picto/:id_picto': 'StudentController.add_picto',
'POST /stu/subscribe': 'StudentController.subscribe', 'POST /stu/subscribe': 'StudentController.subscribe',
'POST /stu/unsubscribe': 'StudentController.unsubscribe', 'POST /stu/unsubscribe': 'StudentController.unsubscribe',
// Websocket request for propagating actions add, delete, modify...
'POST /stu/vocabulary': 'StudentController.vocabulary', 'POST /stu/vocabulary': 'StudentController.vocabulary',
'POST /stu/action': 'StudentController.action', 'POST /stu/action': 'StudentController.action',
'POST /stu/config': 'StudentController.config', 'POST /stu/config': 'StudentController.config',
'POST /stu/actions_batch': 'StudentController.actions_batch', 'POST /stu/actions_batch': 'StudentController.actions_batch',
......
-----BEGIN CERTIFICATE REQUEST-----
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAPkWZj6TTJQon1rupP1SUY8dQiSv3+1xByQAGYaf
J9vZWfe6ZAy0ndFH26m0lc2S76BkQRfhWBTvWcsFhACWefSlGxpIiwxWdQOcF6cf
WyFi9VBPUXvTPyd64hCd+9+XML/0hzU4BpzJsEbPyhOv7VZA2VCZ+GAP86b/MGCS
s2QgWi7ZW0bTX0tO1WDC8JdHeaUXspwfJaqsw25SiDsNfWQmAZOa5F9I0vl4GCku
ivy16Cn/1XnpBw9M9DH18H1ENDFkOnUJYa8NU/t9lJJqNapDZ3zTLIlNd28nl3LP
HfbPGhq7qMAYmtiYt6rxHRBazL1OEFf2xb9DIVVlIKQXf/cCAwEAAaAAMA0GCSqG
SIb3DQEBCwUAA4IBAQArBhbVjPadSIWK9yGO7oca2TT+ZMp2kw4OY7+NHj+4NUFk
CKe2ZOAdvKM9wqY5P4QHux1WnqzEtga78ykaJofHeB/EFFqMkun5ETFbd/wIGKMy
WdB/vNNbsv5Hf2/ezGiw1HUsCGp2P/JTDO9+a5O3ioFhp4tvfJ7TBfdzD5eq7Xlq
DAHXPimbtnqiGGBf6efefG/Rl4cvvLyH5k/mUj00/stx3rjVayvedzOL8W4oRoxJ
SQEaqlp/MtPLXBuG0RkZsJloon+aZfcR3WE4iG2BVQe7Dqtdto+mRa9e1ba0ZUQK
Fq1iIGvsp9YIHCS3NXeJBeIllYkFK2hI7o6hALPf
-----END CERTIFICATE REQUEST-----
/**
* Utility Functions
*/
// Dependencies
var mysql = require('mysql');
var _ = require('lodash');
var url = require('url');
// Module Exports
var utils = module.exports = {};
/**
* Parse URL string from config
*
* Parse URL string into connection config parameters
*/
utils.parseUrl = function (config) {
if(!_.isString(config.url)) {
return config;
}
var obj = url.parse(config.url);
config.host = obj.hostname || config.host;
config.port = obj.port || config.port;
if(_.isString(obj.pathname)) {
config.database = obj.pathname.split('/')[1] || config.database;
}
if(_.isString(obj.auth)) {
config.user = obj.auth.split(':')[0] || config.user;
config.password = obj.auth.split(':')[1] || config.password;
}
return config;
};
/**
* Prepare values
*
* Transform a JS date to SQL date and functions
* to strings.
*/
utils.prepareValue = function(value) {
if(_.isUndefined(value) || value === null) {
return value;
}
// Cast functions to strings
if (_.isFunction(value)) {
value = value.toString();
}
// Store Arrays and Objects as strings
if (_.isArray(value) || value.constructor && value.constructor.name === 'Object') {
try {
value = JSON.stringify(value);
} catch (e) {
// just keep the value and let the db handle an error
value = value;
}
}
// Cast dates to SQL
if (_.isDate(value)) {
value = utils.toSqlDate(value);
}
return mysql.escape(value);
};
/**
* Builds a Select statement determining if Aggeregate options are needed.
*/
utils.buildSelectStatement = function(criteria, table, schemaDefs) {
var query = '';
if(criteria.groupBy || criteria.sum || criteria.average || criteria.min || criteria.max) {
query = 'SELECT ';
// Append groupBy columns to select statement
if(criteria.groupBy) {
if(_.isArray(criteria.groupBy)) {
_.each(criteria.groupBy, function(opt){
query += opt + ', ';
});
} else {
query += criteria.groupBy + ', ';
}
}
// Handle SUM
if (criteria.sum) {
if(_.isArray(criteria.sum)) {
_.each(criteria.sum, function(opt){
query += 'SUM(' + opt + ') AS ' + opt + ', ';
});
} else {
query += 'SUM(' + criteria.sum + ') AS ' + criteria.sum + ', ';
}
}
// Handle AVG (casting to float to fix percision with trailing zeros)
if (criteria.average) {
if(_.isArray(criteria.average)) {
_.each(criteria.average, function(opt){
query += 'AVG(' + opt + ') AS ' + opt + ', ';
});
} else {
query += 'AVG(' + criteria.average + ') AS ' + criteria.average + ', ';
}
}
// Handle MAX
if (criteria.max) {
if(_.isArray(criteria.max)) {
_.each(criteria.max, function(opt){
query += 'MAX(' + opt + ') AS ' + opt + ', ';
});
} else {
query += 'MAX(' + criteria.max + ') AS ' + criteria.max + ', ';
}
}
// Handle MIN
if (criteria.min) {
if(_.isArray(criteria.min)) {
_.each(criteria.min, function(opt){
query += 'MIN(' + opt + ') AS ' + opt + ', ';
});
} else {
query += 'MIN(' + criteria.min + ') AS ' + criteria.min + ', ';
}
}
// trim trailing comma
query = query.slice(0, -2) + ' ';
// Add FROM clause
return query += 'FROM `' + table + '` ';
}
/**
* If no aggregate options lets just build a normal query
*/
// Add all keys to the select statement for this table
query += 'SELECT ';
var selectKeys = [],
joinSelectKeys = [];
if ( !schemaDefs[table] ) {
throw new Error('Schema definition missing for table: `'+table+'`');
}
_.each(schemaDefs[table], function(schemaDef, key) {
selectKeys.push({ table: table, key: key });
});
// Check for joins
if(criteria.joins || criteria.join) {
var joins = criteria.joins || criteria.join;
_.each(joins, function(join) {
if(!join.select) {
return;
}
_.each(_.keys(schemaDefs[join.child.toLowerCase()]), function(key) {
var _join = _.cloneDeep(join);
_join.key = key;
joinSelectKeys.push(_join);
});
// Remove the foreign key for this join from the selectKeys array
selectKeys = selectKeys.filter(function(select) {
var keep = true;
if(select.key === join.parentKey && join.removeParentKey) {
keep = false;
}
return keep;
});
});
}
// Add all the columns to be selected that are not joins
_.each(selectKeys, function(select) {
query += '`' + select.table + '`.`' + select.key + '`, ';
});
// Add all the columns from the joined tables
_.each(joinSelectKeys, function(select) {
// Create an alias by prepending the child table with the alias of the join
var alias = select.alias.toLowerCase() + '_' + select.child.toLowerCase();
// If this is a belongs_to relationship, keep the foreign key name from the AS part
// of the query. This will result in a selected column like: "user"."id" AS "user_id__id"
if(select.model) {
return query += mysql.escapeId(alias) + '.' + mysql.escapeId(select.key) + ' AS ' +
mysql.escapeId(select.parentKey + '__' + select.key) + ', ';
}
// If a junctionTable is used, the child value should be used in the AS part of the
// select query.
if(select.junctionTable) {
return query += mysql.escapeId(alias) + '.' + mysql.escapeId(select.key) + ' AS ' +
mysql.escapeId(select.alias + '__' + select.key) + ', ';
}
// Else if a hasMany attribute is being selected, use the alias plus the child
return query += mysql.escapeId(alias) + '.' + mysql.escapeId(select.key) + ' AS ' +
mysql.escapeId(select.alias + '__' + select.key) + ', ';
});
// Remove the last comma
query = query.slice(0, -2) + ' FROM `' + table + '` ';
return query;
};
utils.toSqlDate = function toSqlDate(date) {
date = date.getFullYear() + '-' +
('00' + (date.getMonth()+1)).slice(-2) + '-' +
('00' + date.getDate()).slice(-2) + ' ' +
('00' + date.getHours()).slice(-2) + ':' +
('00' + date.getMinutes()).slice(-2) + ':' +
('00' + date.getSeconds()).slice(-2) + '.' +
('00' + date.getMilliseconds()).slice(-2);
return date;
};
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
"sails": "^0.12.3", "sails": "^0.12.3",
"sails-disk": "~0.10.0", "sails-disk": "~0.10.0",
"sails-generate-auth": "^0.2.0", "sails-generate-auth": "^0.2.0",
"sails-mysql": "^0.10.12", "sails-mysql": "^0.12",
"sails-test-helper": "^0.3.5", "sails-test-helper": "^0.3.5",
"socket.io": "~1.3.2", "socket.io": "~1.3.2",
"socket.io-redis": "^0.1.4", "socket.io-redis": "^0.1.4",
......
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