Commit 4d73a957 by Pablo Molina

Solved #357, eliminados dispositivos

Además se han integrado los siguientes cambios en el repositorio:

 - Añadida documentación sobre la API
 - Revisados métodos de SupervisorController
parent 312d4986
Showing with 490 additions and 1412 deletions
# Servidor de Pictogram e instalación del cliente web
En este directorio se encuentra el servidor web ([src](./src)) y la aplicación
web ([src/assets/app](./src/assets/app)). Los distintos ficheros de configuración
utilizados para la inicialización y el testeo de la aplicación se encuentran
en el directorio [conf](./conf).
En este directorio se encuentra el servidor web ([src][10]) y la aplicación web
([src/assets/app][12]). Los distintos ficheros de configuración utilizados para la inicialización y
el testeo de la aplicación se encuentran en el directorio [conf][9].
[TOC]
## Dependencias
......@@ -15,19 +16,19 @@ en el directorio [conf](./conf).
## Instalación del servidor y el cliente web
- Configurar el cliente ssh para poder conectarse a los servidores de
pre.yottacode.com (se intentará conectar como el usuario ec2-user).
- Ejecutar el script [install.sh](./install.sh) para instalar todas las
dependencias del servidor y el cliente web.
- Configurar el cliente ssh para poder conectarse a los servidores de Yottacode (se intentará
conectar como el usuario ec2-user).
- Ejecutar el script [install.sh](./install.sh) para instalar todas las dependencias del servidor y
el cliente web.
- Acceder al directorio [conf](./conf) para la instalación de la base de datos.
> **Importante**: el script utilizado creará un entorno para el servidor desde
> cero, por lo que **pueden perderse los datos** almacenados por usuarios.
> **Importante**: el script utilizado creará un entorno para el servidor desde cero, por lo que
> **pueden perderse los datos** almacenados por usuarios.
## Desarrollo y pruebas
Para ejecutar el servidor como desarrollo se debe acceder al directorio
[conf](./conf) e instalar los datos de la base de datos necesarios.
Para ejecutar el servidor como desarrollo se debe acceder al directorio [conf][9] e instalar los
datos de la base de datos necesarios.
## Proceso de compilación
......@@ -48,7 +49,7 @@ de configuración, la segunda la propia ejecución de las tareas.
## Ejecución
Para lanzar el servidor hay que acceder al directorio [src](./src) y ejecutar
Para lanzar el servidor hay que acceder al directorio [src][10] y ejecutar
uno de esos comandos:
- `sails lift`: para un servidor corriente
......@@ -56,7 +57,12 @@ uno de esos comandos:
variables de sails expuestas
> Puede añadirse --prod para ejecutar el servidor en modo producción.
> El servidor se ejecutará en [localhost:1337/app](http://localhost:1337/app).
> El servidor se ejecutará en [localhost:1337/app][11].
## Documentación
Toda la documentación referente al servidor y al cliente de angular se encuentra en el directorio
[doc][13].
[1]: ./src/Gruntfile.js
[2]: ./src/tasks
......@@ -66,3 +72,8 @@ uno de esos comandos:
[6]: ./src/tasks/register/prod.js
[7]: ./src/tasks/register/build.js
[8]: ./src/tasks/register/buildProd.js
[9]: ./conf
[10]: ./src
[11]: http://localhost:1337/app
[12]: ./src/assets/app
[13]: ./doc
......@@ -55,7 +55,7 @@ on it again with `SET foreign_key_checks=1;`
```sql
SET foreign_key_checks=0;
DROP TABLE `action`, `device`, `enrolment`, `instruction`, `license`,
DROP TABLE `action`, `enrolment`, `instruction`, `license`,
`license_activation`, `meta_picto`, `meta_stu`, `method`, `office`,
`official_dev`, `picto`, `picto_acl`, `picto_core`, `picto_core_cat`,
`picto_exp`, `picto_tag`, `picto_tag_sup`, `source`, `student`, `stu_picto`,
......
......@@ -65,20 +65,6 @@ CREATE TABLE IF NOT EXISTS `catexp`(
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `device`
--
CREATE TABLE IF NOT EXISTS `device` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_firmware` varchar(40) COLLATE utf8_unicode_ci NOT NULL COMMENT 'id of the firmware of the device (e.g. Android Device ID)',
`desc` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_firmware` (`id_firmware`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=47 ;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `method`
--
......@@ -200,21 +186,6 @@ CREATE TABLE IF NOT EXISTS `office` (
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `official_dev`
--
CREATE TABLE IF NOT EXISTS `official_dev` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_dev` int(11) DEFAULT NULL COMMENT 'is null when serial is registered but device is not registered yet',
`serial` varchar(40) NOT NULL,
PRIMARY KEY (`id`),
KEY `id_dev` (`id_dev`),
KEY `serial` (`serial`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=38 ;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `picto`
--
......@@ -389,7 +360,7 @@ CREATE TABLE IF NOT EXISTS `stu_picto` (
`attributes` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'JSON object describing the properties of the picto according to the properties defined in meta_picto',
PRIMARY KEY (`id`),
KEY `fk_picto` (`id_pic`),
KEY `id_stu` (`id_stu`),
KEY `id_stu` (`id_stu`),
UNIQUE `uq_stupicto` (`id_stu`,`id_pic`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
......@@ -412,21 +383,6 @@ CREATE TABLE IF NOT EXISTS `stu_sup` (
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `stu_dev`
--
CREATE TABLE IF NOT EXISTS `stu_dev` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_stu` int(11) NOT NULL,
`id_dev` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `id_stu` (`id_stu`),
KEY `id_dev` (`id_dev`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='This table relates official devices with pairs student-supervisor' AUTO_INCREMENT=49 ;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `supervisor`
--
......@@ -472,7 +428,7 @@ CREATE TABLE IF NOT EXISTS `try` (
--
-- Estructura de tabla para la tabla `working_session`
--
-- NOTA: current es un atributo derivado que es necesario porque MySQL 5.1
-- NOTA: current es un atributo derivado que es necesario porque MySQL 5.1
-- no soporta correctamente indices con valor unico donde un campo es NULL
-- Trabaja en combinación al índice unico (id_sup,current) (idx_ws_supcur)
--
......@@ -497,7 +453,6 @@ CREATE TABLE IF NOT EXISTS `working_session` (
-- Filtros para la tabla `action`
--
ALTER TABLE `action`
ADD CONSTRAINT `action_ibfk_1` FOREIGN KEY (`id_dev`) REFERENCES `device` (`id`),
ADD CONSTRAINT `fk_stu_act` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`),
ADD CONSTRAINT `fk_sup_act` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`);
......@@ -526,7 +481,7 @@ ALTER TABLE `meta_instruction`
--
ALTER TABLE `meta_method`
ADD CONSTRAINT `fk_met_sup` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`);
--
-- Filtros para la tabla `office`
......@@ -535,12 +490,6 @@ ALTER TABLE `office`
ADD CONSTRAINT `office_ibfk_1` FOREIGN KEY (`admin`) REFERENCES `supervisor` (`id`);
--
-- Filtros para la tabla `official_dev`
--
ALTER TABLE `official_dev`
ADD CONSTRAINT `official_dev_ibfk_1` FOREIGN KEY (`id_dev`) REFERENCES `device` (`id`);
--
-- Filtros para la tabla `picto`
--
......@@ -593,13 +542,6 @@ ALTER TABLE `stu_sup`
ADD CONSTRAINT `stu_sup_ibfk_2` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`);
--
-- Filtros para la tabla `stu_dev`
--
ALTER TABLE `stu_dev`
ADD CONSTRAINT `stu_dev_ibfk_1` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`),
ADD CONSTRAINT `stu_dev_ibfk_2` FOREIGN KEY (`id_dev`) REFERENCES `device` (`id`);
--
-- Filtros para la tabla `student`
--
ALTER TABLE `student`
......@@ -630,30 +572,30 @@ ALTER TABLE `working_session`
--
CREATE ALGORITHM=UNDEFINED
VIEW `v_stu_last_ws_time` AS
CREATE ALGORITHM=UNDEFINED
VIEW `v_stu_last_ws_time` AS
SELECT M.`id_stu`AS id_stu,
MAX(WS.begin) AS time
FROM
`working_session` AS WS join
`instruction` AS I join
`method` AS M
WHERE
`method` AS M
WHERE
WS.`id_ins` =I.`id`
and I.`id_met` = M.`id`
group by M.`id_stu`;
CREATE ALGORITHM=UNDEFINED
VIEW `v_stu_last_instruction` AS
select
WS.`id` AS `id_ws`,
CREATE ALGORITHM=UNDEFINED
VIEW `v_stu_last_instruction` AS
select
WS.`id` AS `id_ws`,
WS.`begin` AS `ws_begin`,
WS.`end` AS `ws_end`,
WS.`description` AS `ws_description`,
I.`name` AS `ins_name`,
M.`name` AS `met_name`,
M.`id_stu` AS `id_stu`
FROM
M.`id_stu` AS `id_stu`
FROM
`working_session` AS WS join
`instruction` AS I join
`method` AS M join
......@@ -671,7 +613,7 @@ VIEW `v_stu_last_instruction` AS
--
-- Vista materializada mv_stu_last_working_session_detail
-- Mantenida por
-- Mantenida por
-- Utilizada por SAILS:StudentController.lasttries
--
--
......
# Documentación del servidor y el cliente web de pictogram
- [Esquema de la base de datos][1]
- [API del servidor][2]
- [Documento de estados y reglas de integridad (documento docx)][3]
[1]: ./assets/database-er-diagram.png
[2]: ./api.md
[3]: ./assets/states-and-database-integrity.docx
# API del servidor
La API de pictogram está manejada por sails, de forma que todas las peticiones procesadas y las
políticas de acceso se encuentran implementadas y documentadas en los siguientes ficheros:
- [config/routes.js][1] contiene un diccionario en el que se asocia una ruta (url de la API)
con un método de un controlador de sails. Estos métodos son las funciones que efectuarán las
acciones asociadas cuando se mande una petición a esta ruta. Por ejemplo:
```
'post /mi/primera/:par/ruta': 'MiCrontrolador.miMetodo'
```
En este caso, cuando el servidor reciba una petición POST a la url `/mi/primera/:par/ruta`
ejecutará el método `miMetodo` perteneciente al controlador `MiControlador`. La parte `:par`
de la ruta definida indica que `:par` es una variable, es decir, esta ruta se efectuará para
todas las llamadas del tipo:
- `/mi/primera/parametro1/ruta`
- `/mi/primera/1234/ruta`
- ...
> Para consultar los parámetros que se esperan recibir en cada ruta y las respuestas
> enviadas al cliente, hay que consultar la documentación del controlador asociado a ella.
- [api/controllers][2] es un directorio en el que se encuentran todos los controladores
descritos anteriormente con sus métodos. Aquí se encuentra la documentación de los parámetros
que se esperan y las respuestas enviadas. También se encuentra la implementación, pero no
es necesaria para el uso de la API. La estructura de un controlador es la siguiente:
- El nombre del fichero del controlador es del tipo `MiControladorController.js`
- La estructura del interior del fichero sería:
```
/**
* MiControladorController
* Descripción del controlador
*/
module.exports = {
/**
* Descripción del método (función que responde a la ruta)
* @param {Request} request Contiene los datos de la petición
* {
* param1: "Param A", // Se espera este parámetro
* ...
* }
* @param {Response} response Se utiliza para enviar la respuesta
* {
* datos: "" // Ejemplo de respuesta
* }
*/
miMetodo: function (request, response) {
// Contenido del método
}
};
```
- [config/policies.js][3] contiene reglas referentes a los permisos que se necesitan para
ejecutar un método de un controlador. La estructura del fichero es la siguiente:
```
module.exports.policies = {
'*': false, // No se puede acceder a esta url de ninguna forma
// (aplicado si ninguna otra regla se cumple)
MiControladorPublico: { // Reglas de acceso para este controlador
'*': true // Puede accederse a todos los métodos de este controlador
miPrimerMetodo: ['auth'] // Para acceder a este método
// se debe cumplir la restricción 'auth'
},
MiPrimerControlador: {
miMetodo: true // Puede accederse a este método del controlador
}
...
}
```
> 1. Las descripción de las diferentes restricciones se encuentra documentada en el
> directorio [api/policies][4].
> 2. Si un método no se encuentra en este fichero no se podrá acceder a él.
[1]: ../src/config/routes.js
[2]: ../src/api/controllers/
[3]: ../src/config/policies.js
[4]: ../src/api/policies/

87.8 KB | W: | H:

87.8 KB | W: | H:

sails/doc/EC.png
sails/doc/assets/database-er-diagram.png
sails/doc/EC.png
sails/doc/assets/database-er-diagram.png
  • 2-up
  • Swipe
  • Onion skin
/**
* AclPictoController
*
* @description :: Server-side logic for managing aclpictoes
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* ActionController
*
* @description :: Server-side logic for managing actions
* @help :: See http://links.sailsjs.org/docs/controllers
* ActionController with methods for managing the Action Model.
* Read it's documentation for further information.
* @type {Object}
*/
module.exports = {
create: function(req, res) {
var params = req.allParams();
// Mandatory params
if (!params.student) return res.json(500, {error: "No student 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 sup = null; if(params.supervisor) sup = params.supervisor;
var dev = null; if(params.device) dev = params.device;
var sup = null; if(params.supervisor) sup = params.supervisor;
var _try = null; if(params._try) _try = params._try;
var description = null; if(params.description) description = params.description;
var gpsLat = null; if(params.gpsLat) gpsLat = params.gpsLat;
var gpsLon = null; if(params.gpsLon) gpsLon = params.gpsLon;
// Create a generic Action. Return open (=current, new) try
Action.create({
"type": params.type,
"timestamp": timestamp,
"supervisor": sup,
"student": params.student,
"device": dev,
"_try": _try,
"description": description,
"gpsLat": gpsLat,
......@@ -39,15 +35,15 @@ module.exports = {
if(created) {
StuOpenTry.findOne({id_stu : params.student}).exec(function(err, data){
if(err || !data){
sails.log.error("Error finding try for student "+params.student+ ' when creating action '+type);
return res.json(500, {error: 'Action '+type+' not created'});
sails.log.error("Error finding try for student "+params.student+ ' when creating action '+type);
return res.json(500, {error: 'Action '+type+' not created'});
}
sails.log.debug("Try for student "+params.student+ ":"+JSON.stringify(data));
sails.log.debug("Try for student "+params.student+ ":"+JSON.stringify(data));
return res.json(200,{open_try: data.openTry });
})
}
});
},
},
// createlist action
// adds a list of actions
......@@ -56,12 +52,11 @@ module.exports = {
var params = req.allParams();
if (!params.actions || params.actions.length == 0) return res.json(500, {error: "No actions defined"});
if (!params.student) return res.json(500, {error: "No student defined"});
if (!params.device) return res.json(500, {error: "No device defined"});
var sup = null;
if(params.supervisor) sup = params.supervisor;
if(params.supervisor) sup = params.supervisor;
sails.log.debug(params.actions.length + " Actions: " + JSON.stringify(params.actions));
// with .eachSeries the order of resulting array will be equal
......@@ -73,13 +68,12 @@ module.exports = {
var desc = null;
if(a.attributes.picto) desc = a.attributes.picto; // select, add and delete actions data
if(a.attributes.pictos) desc = a.attributes.pictos; // show action data
Action.create({
type: a.action,
timestamp: a.attributes.timestamp,
supervisor: sup,
student: params.student,
device: params.device,
description: desc
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new "+ a.action +" action: " + err);
......@@ -88,7 +82,7 @@ module.exports = {
});
// 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){
if( err ) {
// One of the iterations produced an error.
......@@ -97,11 +91,10 @@ module.exports = {
return res.json(500, { error: "Error saving one action: " + err });
} else {
// All end ok
console.log('All actions have been processed successfully');
console.log('All actions have been processed successfully');
return res.json(200, { msg: "Actions saved successfully" });
}
});
}
};
/**
* AdminController
*
* @description :: Server-side logic for managing Pictogram administrators
* @help :: See http://links.sailsjs.org/docs/controllers
* AdminController which manages the administration login and login
* @type {Object}
*/
module.exports = {
//
// login action
// expected params in post body: email, password
//
login: function (req, res) {
login: function (req, res) {
var bcrypt = require('bcrypt-nodejs');
var email = req.body.email;
var password = req.body.password;
......@@ -19,14 +16,14 @@ module.exports = {
// no credentials
if (!email || !password)
return res.json(401, {error: 'No credentials sent'});
// Check email
if (email != sails.config.pictogram.admin.email)
return res.json(401, {error: 'User not found'});
// if found, check password in encrypted form
bcrypt.compare(password, sails.config.pictogram.admin.password, function (err, match) {
if (err)
if (err)
return res.json(500, { error: 'Server error' });
if (!match) // password do not match
return res.json(401, { error: 'Invalid password' });
......@@ -37,10 +34,8 @@ module.exports = {
});
},
//
// logout action
//
logout: function (req, res) {
// @TODO 357
logout: function (req, res) {
delete req.token;
res.json(200, {notice: 'Session closed'});
}
......
/**
* AttributeController
*
* @description :: Server-side logic for managing attributes
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* ConfigurationController
*
* @description :: Server-side logic for managing configurations
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
// Añade pictograma a la colección del usuario
create: function(req, res){
var idStu = req.param('idStu');
var idStu = req.param('idStu');
var idPic = req.param('idPic');
var idPp = 0; // Inicialmente se crea sin propiedad
......@@ -27,7 +21,7 @@ module.exports = {
idPp: idPp
}
).exec(
function (err, configuration) {
function (err, configuration) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -52,7 +46,7 @@ module.exports = {
Configuration.findOne(
idConf
).exec(
function (err, configuration) {
function (err, configuration) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -80,7 +74,7 @@ module.exports = {
idPp: idPp
}
).exec(
function (err, configuration) {
function (err, configuration) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -105,7 +99,7 @@ module.exports = {
Configuration.destroy(
idConf
).exec(
function (err, configuration) {
function (err, configuration) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -116,4 +110,3 @@ module.exports = {
);
}
};
/**
* DeviceController
*
* @description :: Server-side logic for managing devices
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
//
// create action
// The system generates a new entry in official_device table with a
// random serial number returned to the client
//
create: function(req, res) {
OfficialDevice.create({}).exec(function (err, created) {
if (err) {
console.log(err);
res.serverError(err.details);
}
else if (created)
res.json(200, {serial: created.serial});
});
},
//
// list action
// The system list the entries in official_device table with
// the serial not assigned to a device
//
list: function(req, res) {
OfficialDevice.find({ device: null }).exec(function (err, serials) {
if (err)
res.serverError('DB error');
else if (serials)
res.json(200, serials);
else
res.serverError('No free serials found');
});
},
//
// register action
// Registers a new device with a (optional) serial number and a id_firmware
// If a valid serial number is provided then a official device is registered
// and a permanent JWT token is issued
//
register: function(req, res) {
var params = req.params.all();
if (!params.idFirmware)
res.badRequest('No firmware ID provided');
else if (params.serial) { // Register official device
OfficialDevice.findBySerial(params.serial).exec(function(err, devs) {
if (err)
res.serverError(err.details);
else if (devs.length == 0)
res.badRequest('Invalid serial number');
else {
Device.create(params).exec(function (err, created) {
if (err)
res.serverError(err.details);
else if (created) {
// update official device with dev id
var attrs = {
id_dev: created.id,
serial: devs[0].serial
};
OfficialDevice.update({id: devs[0].id}, attrs).exec(function(err, updated){
if (err)
res.serverError(err.details);
else
res.json({device: created, token: sailsTokenAuth.issueToken(created)});
});
}
});
}
});
}
else { // Register non official device
Device.create(params).exec(function (err, created) {
if (err)
res.serverError(err.details);
else if (created)
res.json({device: created, token: sailsTokenAuth.issueToken(created)});
});
}
},
//
// This action returns pairs <student/supervisor> that are associated to the device
//
users: function(req, res) {
if (!req.params.id)
return res.badRequest("Device ID must be specified");
var list = Device.users(req.params.id, function(err, list) {
if (err || !list)
return res.json(200, []);
return res.json(200, list);
});
},
};
\ No newline at end of file
/**
* ExpressionController
*
* @description :: Server-side logic for managing expressions
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* InstructionController
*
* @description :: Server-side logic for managing instructions
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
//
// Returns all tries for the given instruction
//
// Do a method to retrieve all tries by workingSessions attribute
ws: function(req, res) {
if (!req.params.id_ins) {
return res.json(500, {error: "No instruction defined"});
......@@ -23,4 +11,3 @@ module.exports = {
});
}
};
/**
* LearningUnitController
*
* @description :: Server-side logic for managing learningunits
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* MetaStuController
*
* @description :: Server-side logic for managing Metastus
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
......@@ -9,21 +9,22 @@ module.exports = {
/**
* `OfficeController.create()`
*/
// @TODO 357
create: function (req, res) {
var params = req.params.all();
// Search if the email is in the BDD (must be unique for Office)
Office.findOneByEmail(params.email).exec(function (err, office) {
if (err)
if (err)
return res.json(500, { error: 'DB error' });
if (office)
return res.json(400, {error: 'Email already exists in DB'});
Office.create(params).exec(function (err, created) {
if (err)
return res.json(500, {error: 'Office not created'});
if (err)
return res.json(500, {error: 'Office not created'});
if (created){
// If the admin is specified in the office
// update the office for the admin too
......@@ -37,7 +38,7 @@ module.exports = {
}
});
});
},
......@@ -85,7 +86,7 @@ module.exports = {
supervisors: function (req, res) {
if (!req.params.id)
return res.json(500, {err: "Office ID must be specified"});
Office.findOne(req.params.id).populate('supervisors').exec(function(err, off) {
if (err)
return res.json(500, {error: 'DB error'});
......@@ -93,4 +94,3 @@ module.exports = {
});
},
};
/**
* PagesController
*
* @description :: This controller sends back AngularJS pages
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
login: function (req, res) {
login: function (req, res) {
res.view('login');
},
signin: function (req, res) {
signin: function (req, res) {
res.view('signin');
}
};
\ No newline at end of file
};
/**
* PendingRegistrationController
*
* @description :: Server-side logic for managing pendingregistrations
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
......@@ -8,7 +8,8 @@
module.exports = {
//
// Returns all categories for the given supercategory
//
//
// @TODO 357
categories: function(req, res) {
if (!req.params.id) {
return res.json(500, {error: "No supervisor defined"});
......@@ -23,6 +24,7 @@ module.exports = {
});
},
// @TODO 357
fromcategory: function(req, res) {
if (!req.params.id) {
return res.json(500, {error: "No supervisor defined"});
......@@ -36,9 +38,10 @@ module.exports = {
});
},
// @TODO 357
add_tag: function(req, res) {
var params = req.params.all();
if (!params.picto || !params.supervisor || !params.tag || !params.lang) {
return res.json(500, {error: "Not enough data: picto, supervisor, tag and lang"});
}
......@@ -48,9 +51,10 @@ module.exports = {
});
},
// @TODO 357
del_tag: function(req, res) {
var params = req.params.all();
if (!params.id_tag) {
return res.json(500, {error: "No id_tag defined"});
}
......@@ -63,7 +67,7 @@ module.exports = {
// Destroy don't delete the picto, it removes the owner to students still having it
destroy: function(req, res) {
var params = req.params.all();
if (!params.id) {
return res.json(500, {error: "No id picto defined"});
}
......@@ -73,9 +77,10 @@ module.exports = {
});
},
// @TODO 357
change_exp: function(req, res) {
var params = req.params.all();
if (!params.picto || !params.lang || !params.text) {
return res.json(500, {error: "Not enough data: picto, lang or text"});
}
......@@ -107,10 +112,10 @@ module.exports = {
// Upload a picto to the server (/upload/custompictos/)
upload: function (req, res) {
if(req.method === 'GET')
return res.json({'status':'GET not allowed'});
return res.json({'status':'GET not allowed'});
// Call to /upload via GET is error
var fs = require('fs'), path = require('path'), dateFormat = require('dateformat');
// req.body.filename = sailsHash.hashCode(req.body.filename + Date().toString()) + '.' + req.body.extension;
......@@ -118,18 +123,18 @@ module.exports = {
console.log("Uploading " + req.body.filename +' at ' + req.body.folder + ' from source '+ req.body.source +
'. Renamed as '+req.body.filename );
var uploadFile = req.file('file');
var dirUpload = path.join(process.cwd(), '/assets/upload/' + req.body.folder);
uploadFile.upload({
dirname: dirUpload,
uploadFile.upload({
dirname: dirUpload,
saveAs: req.body.filename
},
function onUploadComplete (err, files) {
function onUploadComplete (err, files) {
// Files will be uploaded to .tmp/uploads
if (err) return res.serverError(err);
// Files will be uploaded to .tmp/uploads
if (err) return res.serverError(err);
// IF ERROR Return and send 500 error with error
// Check when it is uploaded
......@@ -151,7 +156,7 @@ module.exports = {
// 1) Build the picto object to add
var picto = {
"uri": "/upload/custompictos/" + req.body.filename,
"source": req.body.source,
"source": req.body.source,
"owner": req.body.owner
};
......@@ -173,4 +178,3 @@ module.exports = {
);
}
};
/**
* PictoPropController
*
* @description :: Server-side logic for managing pictoprops
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* PictoTagController
*
* @description :: Server-side logic for managing pictotags
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* ProfileController
*
* @description :: Server-side logic for managing profiles
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
// Añade atributo al perfil de usuario
create: function(req, res){
var idStu = req.param('idStu');
var idStu = req.param('idStu');
var idAtt = req.param('idAtt');
var value = ""; // Inicialmente sin valor asignado
......@@ -27,7 +21,7 @@ module.exports = {
value: value
}
).exec(
function (err, profile) {
function (err, profile) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -51,7 +45,7 @@ module.exports = {
Profile.findOne(
idProf
).exec(
function (err, profile) {
function (err, profile) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -79,7 +73,7 @@ module.exports = {
value: value
}
).exec(
function (err, profile) {
function (err, profile) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -105,7 +99,7 @@ module.exports = {
Profile.destroy(
idProf
).exec(
function (err, profile) {
function (err, profile) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -116,4 +110,3 @@ module.exports = {
);
}
};
......@@ -8,7 +8,7 @@
module.exports = {
//
// ping action
// This action simply return OK to ensure connection is up from device
// This action simply return OK to ensure connection is up
//
ping: function(req, res) {
return res.json(200, {result: "OK"});
......@@ -21,4 +21,4 @@ module.exports = {
ping_session: function(req, res) {
return res.json(200, {result: "OK"});
}
};
\ No newline at end of file
};
/**
* SourceController
*
* @description :: Server-side logic for managing sources
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* StuOpenTryController
*
* @description :: Server-side logic for managing StuOpenTry
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* StuSupController
*
* @description :: Server-side logic for managing stusups
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
......@@ -296,59 +296,6 @@ module.exports = {
});
},
//
// Returns all the devices associated to the student
//
devices: function(req, res) {
if (!req.params.id_stu) {
return res.json(500, {error: "No student defined"});
}
Student.devices(req.params.id_stu, function(err, devs) {
if (err) throw err;
return res.json(devs);
});
},
//
// Link a device to a student
//
link_device: function(req, res) {
var params = req.params.all();
console.log(params);
if (!params.id_stu)
return res.json(500, {error: "No student defined"});
if (!params.id_dev_firm)
return res.json(500, {error: "No device defined"});
Student.link_device(params.id_stu, params.id_dev_firm, function(err, created) {
if (err || !created)
return res.json(500, {error: 'The device could not be linked with the student'});
return res.json(created);
});
},
// destroy action
// remove the relation between student and device (stu_dev)
//
unlink_device: function(req, res) {
var params = req.allParams();
console.log(JSON.stringify(params));
StuDev.destroy({id_stu: params.id_stu, id_dev: params.id_dev}).exec(function (err, destroyed) {
if (err) {
console.log(err);
return res.json(500, {error: 'Relation student/device not removed'});
}
if (destroyed) {
console.log("Relation student/device removed");
return res.json(destroyed[0]);
}
});
},
// read action
// get methods of a student
//
......@@ -783,11 +730,6 @@ module.exports = {
// BROADCAST to everyone subscribed to this student
sails.sockets.broadcast(roomName, 'action', { "action": action, "attributes": attributes });
// PROBAR DESDE AQUÍ
// NEW DB STORAGE in table action
var dev = null;
if(attributes.device) dev = attributes.device;
var sup = null;
if(attributes.supervisor) sup = attributes.supervisor;
......@@ -800,7 +742,6 @@ module.exports = {
timestamp: attributes.timestamp,
supervisor: sup,
student: attributes.id_stu,
device: dev,
description: desc
}).exec(function (err, created) {
if (err)
......@@ -856,10 +797,6 @@ module.exports = {
// We loop through the actions and store them in the database
async.forEach(params.actions, function(action, cb){
sails.log.debug("Actions batch is recording action: "+JSON.stringify(action));
var id_dev = null;
if (action.attributes.id_dev)
id_dev = action.attributes.id_dev;
var id_sup = null;
if(action.attributes.id_sup)
id_sup = action.attributes.sup;
......@@ -880,7 +817,6 @@ module.exports = {
timestamp: action.attributes.timestamp,
supervisor: id_sup,
student: id_stu,
device: id_dev,
description: desc
}).exec(function (err, created) {
if (err) {
......@@ -943,6 +879,8 @@ module.exports = {
if (!params.id_stu)
return res.json(500, {error: "No student defined"});
// @TODO 357
// Bellísima inyección SQL (espero equivocarme)
var sql = "SELECT result, COUNT(result) percentage" +
" FROM method m, student s, instruction i, working_session w, try t" +
" WHERE m.id_stu=s.id and i.id_met=m.id and w.id_ins=i.id and t.id_ws=w.id and s.id="+ params.id_stu +
......
/**
* SupPictoTagController
*
* @description :: Server-side logic for managing suppictotags
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
// Mostrar etiquetas propias del supervisor para un pictograma
// Blueprint
// GET /supervisor/:idSup/pictos/:idAclPicto/tags -> Tutor.find
// NO BORRAR: Necesario cuando hay más de 2 niveles en la URL
find: function(req, res){
var idAclPicto = req.param('idAclPicto');
// Comprobación de que se envían los campos
......@@ -23,7 +17,7 @@ module.exports = {
SupPictoTag.find({
idAclPicto: idAclPicto
}).exec(
function (err, tags) {
function (err, tags) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -34,4 +28,3 @@ module.exports = {
);
}
};
/**
* TagController
*
* @description :: Server-side logic for managing tags
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
};
};
/**
* TeacherController
*
* @description :: Server-side logic for managing teachers
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
// Crear teacher/supervisor
......@@ -26,13 +20,13 @@ module.exports = {
// id: "17", Es autoincrement
idOff: idOff,
supervisor:{
name: name,
surname: surname,
contactEmail: contactEmail,
name: name,
surname: surname,
contactEmail: contactEmail,
preferedLanguage: preferedLanguage
}
}).exec(
function (err, teacher) {
function (err, teacher) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -45,7 +39,7 @@ module.exports = {
// Elimina teacher/supervisor
// CUSTOM Blueprint
// DELETE /teacher/:idSup -> Teacher.destroy
// DELETE /teacher/:idSup -> Teacher.destroy
destroy: function(req, res){
var idSup = req.param('idSup');
......@@ -59,7 +53,7 @@ module.exports = {
Teacher.destroy(
{"supervisor": idSup}
).exec(
function (err, teacher) {
function (err, teacher) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -68,7 +62,7 @@ module.exports = {
Supervisor.destroy(
idSup
).exec(
function (err, supervisor) {
function (err, supervisor) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -84,7 +78,6 @@ module.exports = {
}
);
}
};
/**
* TryController
*
* @description :: Server-side logic for managing learningunits
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
// create action
// adds a try
//
create: function(req, res) {
var params = req.allParams();
if (!params.ws) return res.json(500, {error: "No workingSession defined"});
if (!params.begin) return res.json(500, {error: "No begin defined"});
if (!params.end) return res.json(500, {error: "No end defined"});
......@@ -19,7 +13,6 @@ module.exports = {
if (!params.supervisor) return res.json(500, {error: "No supervisor in try defined"});
if (!params.student) return res.json(500, {error: "No student in try defined"});
if (!params.device) return res.json(500, {error: "No device in try defined"});
Try.create({
"workingSession":params.ws,
......@@ -40,7 +33,7 @@ module.exports = {
async.eachSeries(params.actions, function(a, callback) {
sails.log.debug("Loop adding actions: " + a.action + " to try " + tr.id);
var desc = null;
if(a.attributes.picto) desc = a.attributes.picto; // select, add and delete actions data
if(a.attributes.pictos) desc = a.attributes.pictos; // show action data
......@@ -50,7 +43,6 @@ module.exports = {
timestamp: a.attributes.timestamp,
supervisor: params.supervisor,
student: params.student,
device: params.device,
description: desc,
_try: tr.id
}).exec(function(err, action){
......@@ -63,14 +55,14 @@ module.exports = {
});
// 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){
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('An error ocurred with an action');
} else {
console.log('All actions have been processed successfully');
console.log('All actions have been processed successfully');
// Return the try
// with the array of actions
......@@ -92,7 +84,6 @@ module.exports = {
"timestamp": ws.begin,
"supervisor": ws.supervisor,
"student": ws.student,
"device": 58
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new Action InitSession: " + err);
if(action) sails.log.debug("Created Action: " + action.type);
......@@ -104,14 +95,13 @@ module.exports = {
"timestamp": ws.begin,
"supervisor": ws.supervisor,
"student": ws.student,
"device": 58,
"_try": tr.id
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new Action TryInit: " + err);
if(action){
sails.log.debug("Created Action: " + action.type);
// Return the working session created
// Return the working session created
// with the array of one try (the first)
// with the array of one action (the first too)
return res.json({
......@@ -119,7 +109,7 @@ module.exports = {
"begin": ws.begin,
"student": ws.student,
"supervisor": ws.supervisor,
"tries": [
"tries": [
{
"id": tr.id,
"instruction": tr.instruction,
......@@ -134,9 +124,8 @@ module.exports = {
*/
}
});
}
};
/**
* TutorController
*
* @description :: Server-side logic for managing tutors
* @help :: See http://links.sailsjs.org/docs/controllers
*/
// @TODO 357
module.exports = {
// Crear tutor/supervisor
// Blueprint
// POST /tutor -> Tutor.create
create: function(req, res){
var name = req.param('name');
var surname = req.param('surname');
var contactEmail = req.param('contactEmail');
......@@ -26,13 +20,13 @@ module.exports = {
Tutor.create({
// id: "17", Es autoincrement
supervisor:{
name: name,
surname: surname,
contactEmail: contactEmail,
name: name,
surname: surname,
contactEmail: contactEmail,
preferedLanguage: preferedLanguage
}
}).exec(
function (err, tutor) {
function (err, tutor) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -43,10 +37,10 @@ module.exports = {
);
},
// Elimina tutor/supervisor
// CUSTOM Blueprint
// DELETE /tutor/:idSup -> Tutor.destroy
// DELETE /tutor/:idSup -> Tutor.destroy
destroy: function(req, res){
var idSup = req.param('idSup');
......@@ -60,7 +54,7 @@ module.exports = {
Tutor.destroy(
{"supervisor": idSup}
).exec(
function (err, tutor) {
function (err, tutor) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -69,7 +63,7 @@ module.exports = {
Supervisor.destroy(
idSup
).exec(
function (err, supervisor) {
function (err, supervisor) {
if(err){
res.json(err.status, {err: err});
return;
......@@ -85,6 +79,6 @@ module.exports = {
}
);
}
};
\ No newline at end of file
};
......@@ -12,13 +12,13 @@ module.exports = {
// close a WS
//
close: function(req, res) {
if (!req.params.id_ws) return res.json(500, {error: "No working session defined"});
StuOpenTry.findOne( { id_ws : req.params.id_ws } ).exec(function(err, t) {
StuOpenTry.findOne( { id_ws : req.params.id_ws } ).exec(function(err, t) {
if (err) {
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
}
if(t && t.openTry!=null) /*WS recovery*/ {
sails.log.debug("Recovering WS required for WS "+req.params.id_ws);
......@@ -31,7 +31,7 @@ module.exports = {
return res.json(500, {error: 'Working Session could not be closed'});
}});
return res.json(200, {end: ws_end.toISOString()});
}
}
else
return res.json(200, {result:'no recovery required'});
......@@ -41,9 +41,10 @@ module.exports = {
// create action
// adds a working session and a InitSession action
//
// @TODO 357
create: function(req, res) {
var params = req.allParams();
if (!params.id_sup) return res.json(500, {error: "No supervisor defined"});
if (!params.id_ins) return res.json(500, {error: "No instruction defined"});
if (!params.id_stu) return res.json(500, {error: "No student defined"});
......@@ -51,24 +52,24 @@ module.exports = {
var data = {};
data.supervisor = params.id_sup;
data.instruction = params.id_ins;
data.instruction = params.id_ins;
data.description = params.desc;
StuOpenTry.findOne( {or: [
{ id_sup : params.id_sup },
{ id_stu : params.id_stu }
]} ).exec(function(err, t) {
]} ).exec(function(err, t) {
if (err) {
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
}
if(!t || t.openTry==null) //WS closed correctly
if(!t || t.openTry==null) //WS closed correctly
WorkingSession.create(data).exec(function(err, ws){
if(err || !ws){
sails.log.error("Creating new Working Sesion error "+err);
return res.json(500, {error: 'Working Session not created'});
}
sails.log.error("Creating new Working Sesion error "+err);
return res.json(500, {error: 'Working Session not created'});
}
// Create the InitSession Action
Action.create({
"type": "initsession",
......@@ -77,16 +78,16 @@ module.exports = {
"student": params.id_stu
}).exec(function(err, action){
if(err || !action) {
sails.log.error("Creating initial action for new Working Sesion. Error "+err);
return res.json(500, {error: 'Working Session not created'});
}
StuOpenTry.findOne( {id_stu : params.id_stu } ).exec(function(err, t) {
sails.log.error("Creating initial action for new Working Sesion. Error "+err);
return res.json(500, {error: 'Working Session not created'});
}
StuOpenTry.findOne( {id_stu : params.id_stu } ).exec(function(err, t) {
if (err) {
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
}
// Return the working session and try created
sails.log.debug("Initial action for new Working Sesion "+JSON.stringify(ws)+". Action:"+JSON.stringify(action));
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
}
// Return the working session and try created
sails.log.debug("Initial action for new Working Sesion "+JSON.stringify(ws)+". Action:"+JSON.stringify(action));
return res.json({
"id": ws.id,
"first_try_id":t.openTry,
......@@ -94,7 +95,7 @@ module.exports = {
})
})
});
});
});
else { //Not closed previous WS must be recovered and closed
sails.log.debug("Recovering WS required for student "+params.id_stu);
var ws_end;
......@@ -105,12 +106,12 @@ module.exports = {
sails.log.error("Error updating no closed WS " + t.id_ws);
return res.json(500, {error: 'Working Session not created'});
}
WorkingSession.create(data).exec(function(err, ws){
if(err || !ws){
sails.log.error("Creating new Working Sesion error "+err);
return res.json(500, {error: 'Working Session not created'});
}
sails.log.error("Creating new Working Sesion error "+err);
return res.json(500, {error: 'Working Session not created'});
}
// Create the InitSession Action
Action.create({
"type": "initsession",
......@@ -118,17 +119,17 @@ module.exports = {
"supervisor": ws.supervisor,
"student": params.id_stu
}).exec(function(err, action){
if(err || !action) {
sails.log.error("Creating initial action for new Working Sesion. Error "+err);
return res.json(500, {error: 'Working Session not created'});
}
StuOpenTry.findOne( {id_stu : params.id_stu} ).exec(function(err, t) {
if(err || !action) {
sails.log.error("Creating initial action for new Working Sesion. Error "+err);
return res.json(500, {error: 'Working Session not created'});
}
StuOpenTry.findOne( {id_stu : params.id_stu} ).exec(function(err, t) {
if (err) {
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
}
// Return the working session and try created
sails.log.debug("Initial action for new Working Sesion "+JSON.stringify(action));
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
}
// Return the working session and try created
sails.log.debug("Initial action for new Working Sesion "+JSON.stringify(action));
return res.json({
"id": ws.id,
"first_try_id":t.openTry,
......@@ -136,18 +137,19 @@ module.exports = {
})
})
});
});
});
});
}
}
});
},
},
// update action
// ends a working session and a creates an EndSession action
//
// @TODO 357
update: function(req, res) {
var params = req.allParams();
WorkingSession.update({id:params.id}, params).exec(function(err, ws){
if(err || !ws){
sails.log.error("Updating Working Sesion error: " + err);
......@@ -165,15 +167,15 @@ module.exports = {
"student": params.id_stu
}).exec(function(err, action){
if(err || !action) {
sails.log.debug("Error creating new Action EndSession: " + err);
sails.log.debug("Error creating new Action EndSession: " + err);
return res.json(500, {error: 'Working Session not updated'});
}
});
// Implementation of Integrity rule #8 for sessions management
Try.findOne( { id_ws : params.id } ).exec(function(err, t) { //Deleting empty WS (no tries)
if (err) {
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
sails.log.error("Error Recovering from ws "+err);
return res.json(500, {error: 'recovering from ws:'+err});
}
if (typeof(t) == 'undefined') /*Empty WS must be deleted*/{
sails.log.debug("Empty WS to be deleted, id: "+params.id);
......@@ -183,12 +185,12 @@ module.exports = {
return res.json(500, {error: 'Error deleting empty WS (no tries)'});
}});
}
});
}
// Return the working session updated
return res.json(ws);
return res.json(ws);
});
},
......@@ -199,7 +201,7 @@ module.exports = {
per_year: function(req, res) {
if (!req.params.id_stu)
return res.json(500, {error: "No student defined"});
if (!req.params.year)
return res.json(500, {error: "No year defined"});
......@@ -215,7 +217,7 @@ module.exports = {
per_month: function(req, res) {
if (!req.params.id_stu)
return res.json(500, {error: "No student defined"});
if (!req.params.month)
return res.json(500, {error: "No month defined"});
......@@ -227,7 +229,8 @@ module.exports = {
//
// Returns all tries for the given instruction
//
//
// @TODO 357
tries: function(req, res) {
if (!req.params.id_ws) {
return res.json(500, {error: "No working session defined"});
......@@ -236,9 +239,9 @@ module.exports = {
WorkingSession: req.params.id_ws, // With this working session id
or : [
{ result: null }, // This is necessary here because it's not enough with the following query to recover null results
{ result: { '!' : ['BROKEN', 'DISCARDED'] }} // And without this results
{ result: { '!' : ['BROKEN', 'DISCARDED'] }} // And without this results
]
}).populate('actions').exec(function(err, tries) {
if (err) throw err;
if(!tries || tries.length == 0) return res.json([]); // Empty array of tries
......@@ -247,4 +250,3 @@ module.exports = {
},
};
......@@ -13,7 +13,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -42,23 +42,17 @@ module.exports = {
required: true,
model: "Student"
},
device: { // FK de Device
columnName: 'id_dev',
type: 'integer',
required: false,
model: 'Device'
},
_try: { // FK de Try
columnName: 'id_try',
type: 'integer',
required: false,
model: 'Try'
},
description: {
description: {
type: "json",
required: false,
size: 1024
},
},
gpsLat: {
columnName: "gps_lat",
type: "float"
......@@ -68,4 +62,4 @@ module.exports = {
type: "float"
}
}
};
\ No newline at end of file
};
/**
* Device.js
*
* @description :: This are non-official devices connecto to Pictogram
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
tableName : 'device',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
idFirmware: {
columnName: 'id_firmware',
type: 'string',
size: 40,
unique: true,
required: true
},
desc: {
type: 'string',
size: 40
},
stuDevs: {
collection: 'StuDev',
via: 'device'
},
actions: {
collection: 'Action',
via: 'device'
},
},
//
// Model hook for creating a new device
// If a valid serial number is passed, id_dev is updated in official_device table
//
beforeCreate: function(attrs, next) {
// Check if firmware ID is provided
if (!attrs.idFirmware)
return next(new Error('No firmware ID provided'));
// Check if id_firmware is not already registered
Device.findById_firmware(attrs.idFirmware).exec(function(err, devs) {
if (err)
return next(err);
if (devs.length > 0) // device already registered
return next(new Error('Device already registered with that firmware ID'));
next();
});
},
//
// Class method to get the pairs <student, supervisor> associated with the device
//
users: function(dev_id, callback) {
var list = [];
// Get stuDevs with the dev_id
StuDev.find({device: dev_id})
.exec(function(err, stuDevs) {
if (err) return callback(err, []);
//console.log("stuDevs: " + JSON.stringify(stuDevs));
// Get stuSups with every student id of stuDevs
async.eachSeries(stuDevs, function(stuDev, cb) {
StuSup.find({student: stuDev.student})
.populate('student')
.populate('supervisor')
.exec(function(err, stuSups) {
if (err) throw err;
//console.log("stuSups: " + JSON.stringify(stuSups));
for (var i = 0; i < stuSups.length; i++)
list.push(stuSups[i]);
// next in series
cb();
});
},
function(err) {
if (err) throw err;
//console.log("Final list: " + JSON.stringify(list));
callback(err, list); // out loop finished, return result
// Return the list when finish asynch series
});
});
}
};
/**
* OfficialDevice.js
*
* @description :: This are official devices sold by us
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
tableName : 'official_dev',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
device: {
columnName: 'id_dev',
type: 'integer',
required: false,
model: 'Device'
},
serial: {
type: 'string',
size: 40,
required: true,
unique: true
}
},
//
// Model hook for creating a new device
// and generate a new serial number
//
beforeValidate: function(attrs, next) {
//
// Generate random serial with 10 hexadecial digits
//
if (!attrs.serial) {
var serial = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < sails.config.pictogram.serialSize; i++ )
serial += possible.charAt(Math.floor(Math.random() * possible.length));
attrs.serial = serial;
}
next();
}
};
/**
* StuDev.js
*
* @description :: TODO: You might write a short summary of how this model works and what it represents here.
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
tableName : 'stu_dev',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
student: {
columnName: 'id_stu',
type: 'integer',
required: true,
model: 'Student'
},
device: {
columnName: 'id_dev',
type: 'integer',
required: true,
model: 'Device'
}
}
};
......@@ -12,7 +12,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -83,17 +83,12 @@ module.exports = {
collection: "StuSup",
via: "student"
},
// Relación con StuDev
stuDevs: {
collection: 'StuDev',
via: 'student'
},
// Relación con Method. [1 Student to N Method]
// Relación con Method. [1 Student to N Method]
methods: {
collection: "Method",
via: "student"
},
// Relación con StuPicto. [1 Student to N StuPicto]
// Relación con StuPicto. [1 Student to N StuPicto]
stuPicto: {
collection: "StuPicto",
via: "student"
......@@ -112,7 +107,7 @@ module.exports = {
//
// Model hook for storing default device configuration adding a new account
// Model hook for storing default configuration adding a new account
//
beforeCreate: function(attrs, next) {
......@@ -153,7 +148,7 @@ module.exports = {
var bcrypt = require('bcrypt-nodejs');
bcrypt.genSalt(10, function(err, salt) {
if (err)
if (err)
return next(err);
bcrypt.hash(attrs.password, salt, null, function(err, hash) {
if (err)
......@@ -162,20 +157,20 @@ module.exports = {
next();
});
});
});
});
},
//
// Class method for getting the list of supervisors (therapist + tutors) associated to a given
// student
supervisors: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
async.eachSeries(stuSups,
async.eachSeries(stuSups,
function(stuSup, next) {
delete stuSup.supervisor.password;
l.push(stuSup.supervisor);
......@@ -194,11 +189,11 @@ module.exports = {
therapists: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
async.eachSeries(stuSups,
async.eachSeries(stuSups,
function(stuSup, next) {
// stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor
if (stuSup.supervisor && stuSup.supervisor.office && stuSup.supervisor.id > 0) {
......@@ -221,11 +216,11 @@ module.exports = {
tutors: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
async.eachSeries(stuSups,
async.eachSeries(stuSups,
function(stuSup, next) {
// stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor
if (stuSup.supervisor && !stuSup.supervisor.office && stuSup.supervisor.id > 0) {
......@@ -250,119 +245,56 @@ module.exports = {
StuPicto.find({student: id_stu}).populate('picto').exec(function(err, stuPictos) {
var l = [];
var l = [];
if (err || !stuPictos || stuPictos.length == 0)
return callback(err, l);
async.eachSeries(stuPictos, function(stuPicto, cb) {
// Populate expressions to get it with the picto
Picto.findOne(stuPicto.picto.id)
.populate('expressions', {lang: student.lang})
.exec(function(err, picto) {
if (err) throw err;
var stuPictoToAdd = {
"id": stuPicto.id,
"picto": stuPicto.picto,
"expression": picto.expressions[0],
"attributes": stuPicto.attributes
"attributes": stuPicto.attributes
};
l.push(stuPictoToAdd);
cb(); // next in the series
});
},
function(err) {
callback(err, l); // out loop finished, return result
});
});
});
}
});
},
//
// Class method for getting devices associated to student
//
devices: function(id_stu, callback) {
var list = [];
// Get devices for that student id
StuDev.find({student: id_stu})
.exec(function(err, stuDevs) {
if (err) return callback(err, []);
async.eachSeries(stuDevs, function(stuDev, cb) {
Device.findOne(stuDev.device)
.exec(function(err, dev) {
if (err) throw err;
list.push(dev);
cb(); // next in the series
});
},
function(err) {
if (err) throw err;
return callback(err, list); // loop finished, next in the outer loop
});
});
},
//
// Class method for link a device to a student (stu_dev)
//
link_device: function(id_stu, id_dev_firm, callback) {
// Find the student by student id
Student.findOne({id: id_stu}).exec(function(err, student) {
if (err || !student){
console.log("student not found");
return callback(err, null);
}
// Find the device id by device id firmware
Device.findOne({idFirmware: id_dev_firm}).exec(function(err, device){
if (err || !device){
console.log("Device not found");
return callback(err, null);
}
// Create a new entry in stuDev by id_stu and id_dev
StuDev.create({student: student.id, device: device.id}).exec(function(err, stuDev){
if (err || !stuDev){
console.log("StuDev not created");
return callback(err, null);
}
// Concat the description of device to stuDev and get it back
console.log(JSON.stringify(stuDev));
// It is is created
return callback(err, device);
});
});
});
},
//
// Returns all the tries of the student
//
//
tries: function(id_stu, callback) {
var l_met = [];
Method.find({ id_stu: id_stu }).exec(function(err, methods) {
if (err || !methods || methods.length == 0)
return callback(err, []);
// eachSeries
async.eachSeries(
// 1st array of items
methods,
methods,
// 2nd function to operate over one item
function(method, next) {
// Original: Devolver el objeto con el método completo / instructions / workinSessions / Tries
......@@ -371,7 +303,7 @@ module.exports = {
Instruction.find({ id_met: method.id }).populate('workingSessions').exec(function(err, instructions) {
if (err || !instructions || instructions.length == 0)
console.log("error finding instructions");
// Push method
l_met.push({
"id": method.id,
......@@ -381,14 +313,14 @@ module.exports = {
"registration": method.registration,
"notes": method.notes,
"instructions": instructions,
});
});
next();
});
},
// 3rd final function when all is ready
function (err){
function (err){
console.log("Final function");
console.log(JSON.stringify(l_met));
return callback(err, l_met);
......@@ -405,13 +337,13 @@ module.exports = {
Student.findOne(id_stu).exec(function(err, student) {
if (err || !student)
throw err;
// set office to NULL to unlink it
student.office = null;
student.save(function(err, saved) {
if (err) return cb(err);
return cb();
});
});
});
},
......@@ -435,7 +367,7 @@ module.exports = {
// and to check that the user new username is not already registered
//
beforeUpdate: function(attrs, next) {
// remove username as it shouldn't be changed
delete attrs.username;
......@@ -445,7 +377,7 @@ module.exports = {
var bcrypt = require('bcrypt-nodejs');
bcrypt.genSalt(10, function(err, salt) {
if (err || !attrs.password)
if (err || !attrs.password)
return next(err);
bcrypt.hash(attrs.password, salt, null, function(err, hash) {
if (err)
......
......@@ -25,7 +25,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -94,17 +94,17 @@ module.exports = {
required: false,
model: 'Office'
},
// Relación con WorkingSession. [1 Supervisor to N WorkingSession]
// Relación con WorkingSession. [1 Supervisor to N WorkingSession]
workingSessions:{
collection: "WorkingSession",
via: "supervisor"
},
// Relación con Picto. [1 Supervisor to N Picto]
// Relación con Picto. [1 Supervisor to N Picto]
ownPictos:{
collection: "Picto",
via: "owner"
},
// Relación con PictoAcl. [1 Supervisor to N PictoAcl]
// Relación con PictoAcl. [1 Supervisor to N PictoAcl]
aclPictos:{
collection: "PictoAcl",
via: "supervisor"
......@@ -114,12 +114,12 @@ module.exports = {
collection: "StuSup",
via: "supervisor"
},
// Relación con Action. [1 Supervisor to N Action]
// Relación con Action. [1 Supervisor to N Action]
actions: {
collection: "Action",
via: "supervisor"
},
// Relación con MetaMethods. [1 Supervisor to N MetaMethods]
// Relación con MetaMethods. [1 Supervisor to N MetaMethods]
metaMethods: {
collection: "MetaMethod",
via: "supervisor"
......@@ -142,7 +142,7 @@ module.exports = {
var hash_code = (this.name + this.email + this.phone).hashCode();
// Send email confirmation
// Send email confirmation
var nodemailer = require('nodemailer');
// create reusable transporter object using SMTP transport
......@@ -165,7 +165,7 @@ module.exports = {
to: this.email, // list of receivers
subject: 'Account activation', // Subject line
//text: 'plain text', // plaintext body
html: textBody // html body
html: textBody // html body
};
// send mail with defined transport object
......@@ -212,7 +212,7 @@ module.exports = {
], function(err) {
if (err) return next(err);
next();
});
});
},
//
......@@ -244,7 +244,7 @@ module.exports = {
//
if(attrs.password){
var bcrypt = require('bcrypt-nodejs');
bcrypt.genSalt(10, function(err, salt) {
if (err) return cb(err);
bcrypt.hash(attrs.password, salt, null, function(err, hash) {
......@@ -260,28 +260,5 @@ module.exports = {
if (err) return next(err);
next();
});
},
//
// Class method for getting the list of students associated to a given
// supervisor
students: function(id_sup, callback) {
StuSup.find({id_sup: id_sup}).populate('student').exec(function(err, stuSups) {
var l = [];
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
async.eachSeries(stuSups,
function(stuSup, next) {
l.push(stuSup.student);
next();
},
function (err) {
return callback(err, l);
}
);
});
}
};
......@@ -64,12 +64,6 @@
"delete": "Delete",
"delete_template": "Delete from templates",
"description": "Description",
"dev_not_found": "There is no device with this ID.",
"device_id_firmware": "Device ID Firmware",
"device_not_registered": "Device not registered",
"device_registered": "Device registered with firmware id {{idFirmware}} and serial {{serial}}",
"device_setup": "Device setup",
"devices": "Devices",
"disabled": "Disabled. Clic for invisible",
"double_click": "Double click",
"down": "Down",
......@@ -186,8 +180,6 @@
"previous_sessions": "Previous sessions",
"read_picto": "Read picto",
"register": "Sign in",
"register_button": "Register",
"register_device": "Register device",
"remember": "Remember me",
"reports": "Reports",
"save": "Save",
......
......@@ -65,11 +65,6 @@
"delete_template": "Eliminar de plantillas",
"description": "Descripción",
"dev_not_found": "No se ha encontrado dispositivo con ese ID.",
"device_id_firmware": "ID firmware del dispositivo",
"device_not_registered": "Dispositivo no registrado",
"device_registered": "Dispositivo registrado con id firmware: {{idFirmware}} y número de serie: {{serial}}",
"device_setup": "Configuración dispositivos",
"devices": "Dispositivos",
"disabled": "Desactivado. Clic para invisible",
"double_click": "Double clic",
"down": "Abajo",
......@@ -187,7 +182,6 @@
"read_picto": "Leer picto",
"register": "Regístrate",
"register_button": "Registrar",
"register_device": "Registrar dispositivo",
"remember": "No cerrar sesión",
"reports": "Informes",
"save": "Guardar",
......
......@@ -16,7 +16,7 @@ var dashboardApp = angular.module('dashboardApp', [
'ngAnimate',
'ngSanitize',
'ngToast', // This is for pop-up notifications
'ng-context-menu',
'ng-context-menu',
'chart.js', // Interactive charts!
'ngLodash'
//'ngWebsocket'
......@@ -36,7 +36,7 @@ dashboardApp.config(['ngToastProvider', function(ngToast) {
dashboardApp.config(function($translateProvider) {
/* i18n */
$translateProvider.useStaticFilesLoader({
'prefix': '/app/i18n/',
'suffix': '.json'
......@@ -149,12 +149,6 @@ dashboardApp.config(function($stateProvider, $urlRouterProvider) {
controller: 'AdminCtrl',
abstract: true,
})
.state('devices', {
url: '/devices',
parent: 'admin',
templateUrl: 'modules/admin/views/devices.html',
controller: 'AdminDevicesCtrl',
})
.state('offices', {
url: '/offices',
parent: 'admin',
......@@ -170,8 +164,8 @@ dashboardApp.config(function($stateProvider, $urlRouterProvider) {
;
$urlRouterProvider.otherwise('/login');
});
/* reCAPTCHA */
......@@ -211,4 +205,3 @@ dashboardApp.factory("newconfirm", function ($window, $q, $timeout) {
return newconfirm;
});
......@@ -4,9 +4,9 @@
<header-admin></header-admin>
<!-- Tab menu -->
<ul class="nav nav-pills nav-justified" ng-init="selectedTab = 'devices'">
<li role="presentation" ng-click="selectedTab = 'devices'" ng-class="{'active':selectedTab === 'devices'}">
<a href="#devices">{{ 'devices' | translate }}</a>
<ul class="nav nav-pills nav-justified" ng-init="selectedTab = 'supervisors'">
<li role="presentation" ng-click="selectedTab = 'supervisors'" ng-class="{'active':selectedTab === 'supervisors'}">
<a href="#supervisors">{{ 'supervisors' | translate }}</a>
</li>
<li role="presentation" ng-click="selectedTab = 'offices'" ng-class="{'active':selectedTab === 'offices'}">
<a href="#offices">{{ 'offices' | translate }}</a>
......@@ -23,4 +23,4 @@
<!-- Fin de container -->
<!-- Footer Translate -->
<footer-translate></footer-translate>
\ No newline at end of file
<footer-translate></footer-translate>
<!-- Admin Devices -->
<div class="row">
<div class="col-sm-6">
<h3 translate>generate_serial</h3>
<form name="GenerateSerialForm" role="form" ng-submit="generate_serial()">
<fieldset>
<div class="form-group">
<button type="submit" class="btn btn-primary" translate>generate</button>
</div>
</fieldset>
</form>
<!-- Alert and success messages -->
<div ng-show="{{ 'showmessagedevice' }}" class="alert" ng-class="alertdevice" translate translate-values="{{tdata}}">{{ messagedevice}}</div>
<h3 translate>register_device</h3>
<form name="RegisterDeviceForm" role="form" ng-submit="register_device()">
<fieldset>
<div class="form-group">
<input type="text" class="form-control" id="device_firmware" name="device_firmware" placeholder="{{ 'firmware' | translate }}" required ng-model="formdatadevice.idFirmware" pattern="[a-zA-Z0-9]+" oninvalid="setCustomValidity('Only admitted letters in upercase or lowercase and digits')" onchange="try{setCustomValidity('')}catch(e){}" />
</div>
<div class="form-group">
<input type="text" class="form-control" id="device_description" name="device_description" placeholder="{{ 'description' | translate }}" required ng-model="formdatadevice.desc" pattern="[a-zA-Z0-9\s.,-_]+" oninvalid="setCustomValidity('Only admitted letters in upercase or lowercase, digits, commas and point.')" onchange="try{setCustomValidity('')}catch(e){}" />
</div>
<div class="form-group">
<input type="text" class="form-control" id="device_serial" name="device_serial" placeholder="{{ 'serial' | translate }}" ng-model="formdatadevice.serial" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" translate>register_button</button>
</div>
</fieldset>
</form>
</div>
<div class="col-sm-6">
<h3 translate>serial_list</h3>
<ul class="list-group">
<li class="list-group-item" ng-repeat="freeserial in freeserials track by $index">{{freeserial.serial}}</li>
</ul>
</div>
</div>
\ No newline at end of file
......@@ -271,64 +271,8 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
}
};
// TODO issue/357
$scope.delete_device = function (id_dev){
var deleteDevice = $window.confirm('Are you absolutely sure you want to delete?');
if (deleteDevice) {
$http.delete(config.backend + '/stu/' + $scope.studentData.id + '/dev/' + id_dev)
.success(function(data, status, headers, config) {
var i;
// Eliminar de la vista: Se recorre el array de objetos json para buscarlo
for (i = 0; i < $scope.studentDevices.length; i++) {
if (id_dev == $scope.studentDevices[i].id) {
$scope.studentDevices.splice(i,1);
}
}
console.log("Device deleted with id " + id_dev);
})
.error(function(data, status, headers, config) {
$scope.showmessagedevnotfound = true;
$scope.messagedev = "dev_not_deleted";
console.log("Error from API: " + data.error);
});
}
};
// TODO issue/357
$scope.associate_dev = function(){
var stu_dev = {
"id_stu": $scope.studentData.id,
"id_dev_firm": $scope.device_id_firmware
}
$http
.post(config.backend+'/stu/dev/', stu_dev)
.success(function(data, status, headers, config) {
console.log("Created relation");
console.log(JSON.stringify(data));
// Add to the list of devices in view
$scope.studentDevices.push(data);
// Remove the id from the input text form
$scope.device_id_firmware = '';
// Hide not found message if it is displayed
$scope.showmessagedevnotfound = false;
})
.error(function(data, status, headers, config) {
console.log("Error from API: " + data.error);
$scope.showmessagedevnotfound = true;
$scope.messagedev = "dev_not_found";
});
};
// *******************************************************
// Devices Setup
// Setup
// $scope.studentData.attributes
// Update options attributes
//
......@@ -358,3 +302,4 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
});
};
});
d
......@@ -175,41 +175,6 @@
<div class="alert alert-info">{{ 'supervisor_note' | translate }}</div>
</div>
<!-- Fin de id student-tutors -->
<!-- Student devices -->
<div id="student_devices">
<h4 translate>devices</h4>
<!-- Formulario para introducir ID de dispositivo -->
<p>
<form role="search" ng-submit="associate_dev()">
<div class="input-group">
<input type="text" class="form-control" placeholder="{{ 'device_id_firmware' | translate }}" name="srch-term-device" id="srch-term-device" ng-model="device_id_firmware" required />
<div class="input-group-btn">
<button class="btn btn-success" type="submit" title="{{ 'add' | translate }}">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
</div>
</form>
</p>
<!-- Fin del formulario para añadir dispositivo -->
<!-- Alert messages for device not found -->
<div ng-show="{{ 'showmessagedevnotfound' }}" class="alert alert-warning">{{ messagedev | translate }}</div>
<!-- Dispositivos asignados -->
<ul class="list-group" id="user_devices">
<li class="list-group-item" ng-repeat="dev in studentDevices">
<span class="glyphicon glyphicon-phone" aria-hidden="true"></span> {{dev.desc}}
<!-- aquí mejor stusupdev.id -->
<a ng-click="delete_device(dev.id)" class="delete_device" title="{{ 'unlink' | translate }}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</li>
</ul>
<!-- Fin de Dispositivos asignados -->
</div>
<!-- Fin de id student-devices -->
</div>
</div>
<!-- Fin de row -->
......
module.exports = {
var path = require('path');
var ASSETS_PATH = path.join(__dirname, '..', 'assets');
module.exports = {
paths: {
public: __dirname+'/../assets' // or wherever
}
};
\ No newline at end of file
public: path.join(ASSETS_PATH),
upload: path.join(ASSETS_PATH, 'upload'),
defaultAvatar: path.join(ASSETS_PATH, 'defaultAvatar.jpg'),
supervisorAvatarDirectory: path.join(ASSETS_PATH, 'supervisorAvatar'),
/**
* Gets the supervisor avatar filename
* @param {supervisorId} supervisorId
* @return {string} fileName
*/
getSupervisorAvatarFileName: function (supervisorId) {
var imageNameHash = require('crypto').createHash('sha512');
imageNameHash.update(supervisorId);
imageNameHash.update((new Date()).getTime());
return imageNameHash.digest('hex') + '.jpg';
}
}
};
//// template file for sails/src/config/local.js
/**
* 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
*/
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) *
* *
* In this example, we'll assume you created a folder in your project, *
* `config/ssl` and dumped your certificate/key files there: *
***************************************************************************/
ssl: {
ca: require('fs').readFileSync(__dirname + '/ssl/godaddy/gd.yottacode.com.bundle.crt'),
key: require('fs').readFileSync(__dirname + '/ssl/godaddy/gd.yottacode.com.key'),
cert: require('fs').readFileSync(__dirname + '/ssl/godaddy/gd.yottacode.com.crt')
},
/***************************************************************************
* The `port` setting determines which TCP port your app will be *
* deployed on. *
* *
* Ports are a transport-layer concept designed to allow many different *
* networking applications run at the same time on a single computer. *
* More about ports: *
* http://en.wikipedia.org/wiki/Port_(computer_networking) *
* *
* 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'
};
......@@ -19,77 +19,73 @@
module.exports.policies = {
/***************************************************************************
* *
* Default policy for all controllers and actions (`true` allows public *
* access) *
* *
***************************************************************************/
'*': false,
PagesController: { // all static pages all publicy available
'*': true
},
ServerController: {
ping: true,
ping_session: ['tokenAuth'],
},
// Valido
'*': false, // Disable access as default
SupervisorController: {
find: ['tokenAuth'],
findOne: ['tokenAuth'],
login: true,
create: true,
update: ['tokenAuth'],
login: true,
activate: true,
list: ['tokenAuth', 'isAdmin'],
destroy: ['tokenAuth', 'isAdmin'],
upload: ['tokenAuth'],
students: ['tokenAuth'],
pictos: ['tokenAuth'],
upload: ['tokenAuth'],
list: ['tokenAuth', 'isAdmin'],
subscribe: ['tokenAuth'],
unsubscribe: ['tokenAuth']
},
DeviceController: {
register: true,
create: ['tokenAuth', 'isAdmin'],
users: ['tokenAuth'],
list: ['tokenAuth', 'isAdmin'],
// From here, there are blueprint actions
// IMPORTANT: do not place implemented methods beyond this point
findOne: ['tokenAuth'],
find: ['tokenAuth'],
update: ['tokenAuth', 'isAdmin'],
// Invalido
// SupervisorController: {
// find: ['tokenAuth'], /* @TODO isAdmin */
// findOne: ['tokenAuth'],
// update: ['tokenAuth'],
// destroy: ['tokenAuth', 'isAdmin'],
// },
// Sin comprobar
PagesController: { // all static pages all publicy available
'*': true
},
ServerController: {
ping: true,
ping_session: ['tokenAuth'],
},
AdminController: {
login: true
},
OfficeController: {
get: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
getAll: ['tokenAuth', 'isAdmin'],
// @TODO 357
create: ['tokenAuth', 'isAdmin'],
// @TODO 357
update: ['tokenAuth', 'isAdmin'],
// @TODO 357
destroy: ['tokenAuth', 'isAdmin'],
supervisors: ['tokenAuth', 'isAdmin'],
// @TODO 357
populate: ['tokenAuth']
},
StudentController: {
login: true,
find: ['tokenAuth'],
findOne: ['tokenAuth'],
// @TODO 357
find: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
getInfo: ['tokenAuth'],
create: ['tokenAuth',], // isSupAdmin too
update: ['tokenAuth'],
create: ['tokenAuth'], // isSupAdmin too
update: ['tokenAuth'],
delete: ['tokenAuth'],
//destroy: ['tokenAuth'], // isSupAdmin too
devices: ['tokenAuth' ], // isSupAdmin is supervisor of the
supervisors: ['tokenAuth'],
therapists: ['tokenAuth'],
tutors: ['tokenAuth'], // isSupervisorOfStudent falla en Student.supervisors
link_supervisor: ['tokenAuth'],
unlink_supervisor: ['tokenAuth'],
link_device: ['tokenAuth'],
unlink_device: ['tokenAuth'],
subscribe: ['tokenAuth'], // websockets
unsubscribe: true, // websockets
vocabulary: true, // websockets
......@@ -107,83 +103,76 @@ module.exports.policies = {
actions_batch: ['tokenAuth'],
sqlquery: ['tokenAuth']
},
StuSupController:{
find: ['tokenAuth'],
findOne: ['tokenAuth'],
// @TODO 357
StuSupController: {
find: ['tokenAuth'],
findOne: ['tokenAuth'],
create: ['tokenAuth'],
destroy: ['tokenAuth']
},
PictoController:{
PictoController: {
// @TODO 357
create: ['tokenAuth'],
destroy: ['tokenAuth'],
categories: ['tokenAuth'],
fromcategory: ['tokenAuth'],
// @TODO 357
find: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
add_tag: ['tokenAuth'],
del_tag: ['tokenAuth'],
change_exp: ['tokenAuth'],
upload: ['tokenAuth']
},
MethodController:{
MethodController: {
create: ['tokenAuth'],
newMethod: ['tokenAuth'],
update: ['tokenAuth'],
destroy: ['tokenAuth'],
// @TODO 357
find: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
meta_methods: ['tokenAuth'],
// @TODO 357
methods: ['tokenAuth'],
save: ['tokenAuth'],
destroyTemplate: ['tokenAuth'], // Add policie isOwner (supervisor.id == metamethod.id_sup)
},
InstructionController:{
InstructionController: {
create: ['tokenAuth'],
update: ['tokenAuth'],
destroy: ['tokenAuth'],
// @TODO 357
find: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
// @TODO 357
ws: ['tokenAuth'],
},
WorkingSessionController:{
WorkingSessionController: {
close: ['tokenAuth'],
// @TODO 357
create: ['tokenAuth'],
// @TODO 357
update: ['tokenAuth'],
// @TODO 357
destroy: ['tokenAuth'],
// @TODO 357
find: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
tries: ['tokenAuth'],
per_year: ['tokenAuth'],
per_month: ['tokenAuth'],
tries: ['tokenAuth'],
per_month: ['tokenAuth']
},
TryController:{
TryController: {
create: ['tokenAuth'],
update: ['tokenAuth'],
},
ActionController:{
ActionController: {
create: ['tokenAuth'],
createlist: ['tokenAuth'],
},
};
/***************************************************************************
* *
* Here's an example of mapping some policies to run before a controller *
* and its actions *
* *
***************************************************************************/
// RabbitController: {
// Apply the `false` policy as the default for all of RabbitController's actions
// (`false` prevents all access, which ensures that nothing bad happens to our rabbits)
// '*': false,
// For the action `nurture`, apply the 'isRabbitMother' policy
// (this overrides `false` above)
// nurture : 'isRabbitMother',
// Apply the `isNiceToAnimals` AND `hasRabbitFood` policies
// before letting any users feed our rabbits
// feed : ['isNiceToAnimals', 'hasRabbitFood']
// }
......@@ -22,34 +22,33 @@
module.exports.routes = {
// Supervisor
'post /sup/login': 'SupervisorController.login',
// Valido
'post /sup': 'SupervisorController.create',
'put /sup': 'SupervisorController.update',
'get /sup/all': 'SupervisorController.list',
'get /sup': 'SupervisorController.find',
'get /sup/get/:id': 'SupervisorController.findOne',
'post /sup/login': 'SupervisorController.login',
'post /sup/activate': 'SupervisorController.activate',
'post /sup/upload': 'SupervisorController.upload',
'get /sup/:id/students': 'SupervisorController.students',
'get /sup/:id/pictos': 'SupervisorController.pictos',
'get /sup/all': 'SupervisorController.list',
'post /sup/subscribe': 'SupervisorController.subscribe',
'post /sup/unsubscribe': 'SupervisorController.unsubscribe',
'post /sup/upload': 'SupervisorController.upload', // upload profile img file
// Invalido
'get /sup': 'SupervisorController.find',
'get /sup/get/:id': 'SupervisorController.findOne',
'put /sup': 'SupervisorController.update',
// Sin comprobar
// Pictos
'get /sup/:id/pictos': 'SupervisorController.pictos',
// @TODO 357
'get /sup/:id/pic_categories/:id_cat': 'Picto.categories',
// @TODO 357
'get /sup/:id/pic_fromcategory/:id_cat': 'Picto.fromcategory',
// Pictogram administration
'post /admin/login': 'AdminController.login',
// Devices
'post /dev/create': 'DeviceController.create',
'post /dev/register': 'DeviceController.register',
'get /dev/:id/users': 'DeviceController.users',
'get /dev/freeserials': 'DeviceController.list',
'get /dev/:id': 'DeviceController.find',
// Server
'get /server/ping': 'ServerController.ping',
'get /server/ping_session': 'ServerController.ping_session',
......@@ -59,14 +58,12 @@ module.exports.routes = {
'get /office/get_all': 'OfficeController.getAll',
'get /office/get/:id/supervisors': 'OfficeController.supervisors',
/////////////////////////////////////////////////////////////////////////
// STUDENTS /////////////////////////////////////////////////////////////
// Students
// get /student --> List all students
'post /stu/login': 'StudentController.login',
'post /stu': 'StudentController.create',
'put /stu/:id_stu': 'StudentController.update',
'delete /stu/:id_stu' : 'StudentController.delete', // DELETE is buggy in Angular, so we use POST instead
//'post /stu/:id_stu/delete': 'StudentController.delete',
'delete /stu/:id_stu': 'StudentController.delete',
'get /stu/:id_stu': 'StudentController.getInfo',
'post /stu/upload': 'StudentController.upload', // upload pic file
......@@ -77,11 +74,6 @@ module.exports.routes = {
'get /stu/:id_stu/sup/:id_sup': 'StudentController.link_supervisor',
'delete /stu/:id_stu/sup/:id_sup': 'StudentController.unlink_supervisor',
// Students > Devices
'get /stu/:id_stu/devices': 'StudentController.devices',
'post /stu/dev': 'StudentController.link_device',
'delete /stu/:id_stu/dev/:id_dev': 'StudentController.unlink_device',
// Students > Pictos
'get /stu/:id_stu/pictos': 'StudentController.pictos',
'delete /stu/:id_stu/picto/:id_stuPicto': 'StudentController.delete_picto',
......@@ -111,7 +103,6 @@ module.exports.routes = {
'post /stu/sqlquery': 'StudentController.sqlquery',
////////////////////////////////////////////////////////////////////////
//
// Working Sessions
//
......@@ -124,34 +115,38 @@ module.exports.routes = {
'get /ws/:id_stu/year/:year': 'WorkingSessionController.per_year',
'get /ws/:id_stu/month/:month': 'WorkingSessionController.per_month',
// @TODO 357
// Working Sessions > Tries
'get /ws/:id_ws/tries': 'WorkingSession.tries',
'post /workingsession/:id_ws/close': 'WorkingSession.close',
// @TODO 357
'put /try/:id': 'Try.update',
'post /try': 'Try.create',
// @TODO 357
// Instructions > Working Sessions
'get /instruction/:id_ins/ws': 'Instruction.ws',
//'get /instruction/:id_ins/tries': 'Instruction.tries', // BORRAR aquí y en wiki
// 'get /instruction/:id_ins/tries': 'Instruction.tries', // BORRAR aquí y en wiki
// Actions
'post /action': 'ActionController.create',
'post /actions': 'ActionController.createlist',
/////////////////////////////////////////////////////////////////////////
//
// Pictos
//
//'post /picto': 'Picto.create',
// @TODO 357
// 'post /picto': 'Picto.create',
'post /picto/upload': 'PictoController.upload', // upload picto file
'delete /picto/:id': 'PictoController.destroy',
// @TODO 357
'post /picto/tag': 'Picto.add_tag',
// @TODO 357
'delete /picto/tag/:id_tag': 'Picto.del_tag',
// @TODO 357
'post /picto/exp': 'Picto.change_exp',
////////////////////////////////////////////////////////////////////////
//
// Instructions
//
......@@ -163,6 +158,7 @@ module.exports.routes = {
'put /method/:id': 'MethodController.update',
'delete /method/:id': 'MethodController.destroy',
// @TODO 357
'post /instruction': 'Instruction.create',
'put /instruction/:id': 'Instruction.update',
'delete /instruction/:id': 'Instruction.destroy',
......@@ -173,12 +169,14 @@ module.exports.routes = {
//'get /test': 'User.test',
// @TODO 357
// // Gestionar atributos del perfil de usuario (profile)
// 'post /student/:idStu/attributes': 'Profile.create',
// 'get /student/:idStu/attributes/:idProf': 'Profile.get',
// 'put /student/:idStu/attributes/:idProf': 'Profile.update',
// 'delete /student/:idStu/attributes/:idProf': 'Profile.delete',
// @TODO 357
// // Gestionar pictogramas del usuario (configuration)
// 'post /student/:idStu/pictos': 'Configuration.create',
// 'get /student/:idStu/pictos/:idConf': 'Configuration.get',
......@@ -203,9 +201,11 @@ module.exports.routes = {
// 'put /supervisor/:idSup/pictos/:id': 'AclPicto.update',
// 'delete /supervisor/:idSup/pictos/:id': 'AclPicto.destroy',
// @TODO 357
// // Gestionar etiquetas propias del supervisor (supPictoTag)
// 'post /supervisor/:idSup/pictos/:idAclPicto/tags': 'SupPictoTag.create',
// 'get /supervisor/:idSup/pictos/:idAclPicto/tags': 'SupPictoTag.find', // Necesario indicarla cuando hay más de 2 niveles en la URL
// 'get /supervisor/:idSup/pictos/:idAclPicto/tags': 'SupPictoTag.find',
// Necesario indicarla cuando hay más de 2 niveles en la URL
// 'get /supervisor/:idSup/pictos/:idAclPicto/tags/:id': 'SupPictoTag.findOne',
// 'put /supervisor/:idSup/pictos/:idAclPicto/tags/:id': 'SupPictoTag.update',
// 'delete /supervisor/:idSup/pictos/:idAclPicto/tags/:id': 'SupPictoTag.destroy',
......@@ -216,7 +216,9 @@ module.exports.routes = {
// 'put /supervisor/:idSup/students/:id': 'StuSup.update',
// 'delete /supervisor/:idSup/students/:id': 'StuSup.destroy',
// @TODO 357
// 'delete /tutor/:idSup': 'Tutor.destroy',
// @TODO 357
// 'delete /teacher/:idSup': 'Teacher.destroy'
/***************************************************************************
* *
......
//
// Tests for DeviceController
//
// load supertest, which provides useful methods for HTTP requests
require("sails-test-helper");
describe('DeviceController', function() {
var token;
var serial;
describe('/dev/create', function() {
it('should login admin', function(done) {
// first login as admin
request
.post('/admin/login')
.send({email: 'amontejo@ujaen.es', password: 'KaTaCR00.oK'})
.expect(200)
.expect('Content-Type', /json/)
.expect(function(res) {
if (!res.body.token) throw new Error('no token received');
token = res.body.token;
})
.end(function(err, res){
if (err) return done(err);
done();
});
});
it('should return new serial number and 200 (ok) status code', function(done) {
request
.post('/dev/create')
.send({token: token})
.expect(200)
.expect('Content-Type', /json/)
.expect(function(res) {
if (!res.body.serial) throw new Error('no serial number received');
serial = res.body.serial
})
.end(function(err, res){
if (err) return done(err);
done();
});
});
});
describe('/dev/register', function() {
it('should return "Invalid serial number" error', function(done) {
request
.post('/dev/register')
.send({serial: 'xxx', idFirmware: 'android_02993', desc: 'Samsung Galaxy S20', token: token})
.expect(400)
.expect('Invalid serial number')
.end(function(err, res){
if (err) return done(err);
done();
});
});
it('should register official tablet', function(done) {
request
.post('/dev/register')
.send({serial: serial, idFirmware: 'android_0187', desc: 'Tableta de chocolate', token: token})
.expect(200)
.expect('Content-Type', /json/)
.expect(function(res) {
if (!res.body.token) throw new Error('no token received');
})
.end(function(err, res){
if (err) return done(err);
// Destroy device created during test
OfficialDevice.destroy({serial:serial}).exec(function(err, dests) {
if (err) return done(err);
Device.destroy({idFirmware:'android_0187'}).exec(function(err, dests) {
if (err) return done(err);
done();
});
});
});
});
it('should register non-official tablet', function(done) {
request
.post('/dev/register')
.send({idFirmware: 'android_0187', desc: 'Tableta de chocolate', token: token})
.expect(200)
.expect('Content-Type', /json/)
.expect(function(res) {
if (!res.body.token) throw new Error('no token received');
})
.end(function(err, res){
if (err) return done(err);
Device.destroy({idFirmware:'android_0187'}).exec(function(err, dests) {
if (err) return done(err);
return done();
});
});
});
});
});
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