Commit f5651fec by Pablo Molina

Merge branch 'issue/357' into develop

Conflicts:
	.gitignore
	sails/README.md
	sails/Vagrantfile
	sails/install.sh
	sails/roles/database/README.md
	sails/roles/database/files/pictodb-schema.sql
	sails/roles/database/files/test-autismojaen.sql
	sails/roles/database/files/test-caja.sql
	sails/roles/mysql/tasks/main.yml
	sails/roles/server/tasks/main.yml
	sails/roles/server/vars/main.yml
	sails/roles/webapp/tasks/main.yml
	sails/src/package.json
parents 2c4b927e 6655da93
Showing with 1333 additions and 1975 deletions
......@@ -16,10 +16,13 @@ sails/src/assets/app/bower_components
sails/src/assets/app/modules
sails/src/assets/app/css
sails/src/assets/app/js
sails/src/assets/scripts/config.js
# Other #
#########
sails/src/config/ssl
sails/src/config/ssl/**/*.key
sails/src/config/ssl/**/*.crt
sails/src/config/local.js
sails/src/node_modules
sails/.vagrant
......
......@@ -47,15 +47,20 @@ todo el repositorio, organizadas en 3 categorías:
# Aspecto del código
- En el fichero [.editorconfig](./.editorconfig) se encuentra el estilo
utilizado en el código (en cuento a espacios, codificación y demás). Existen
numerosos plugins que pueden encontrarse en
[editorconfig.org](http://EditorConfig.org).
- En el fichero [/sails/src/.eslintrc](./sails/src/eslintrc) se encuentran los
estilos referentes a los ficheros de javascript. Tanto `eslint` como las
configuraciones necesarias se encuentran en el fichero
[/sails/src/package.json](./sails/src/package.json), y se instalarán como
dependencias de desarrollo.
> Puede configurarse eslint en el editor usado o ejecutando
> `eslint [ficheros]` desde el directorio [/sails/src](./sails/src).
- En el fichero [.editorconfig][3] se encuentra el estilo utilizado en el código (en cuento a
espacios, codificación y demás). Existen numerosos plugins que pueden encontrarse en
[editorconfig.org][4].
- En el fichero [/sails/src/.eslintrc][5] se encuentran los estilos referentes a los ficheros de
javascript. Tanto `eslint` como las configuraciones necesarias se encuentran en el fichero
[/sails/src/package.json][6], y se instalarán como dependencias de desarrollo.
> Puede configurarse eslint en el editor usado o ejecutando `eslint [ficheros]` desde
> el directorio [/sails/src][7].
[1]: https://pre.yottacode.com/
[2]: https://dev.yottacode.com/
[3]: /softuno/pictogram/blob/develop/.editorconfig
[4]: http://editorconfig.org
[5]: /softuno/pictogram/blob/develop/sails/src/.eslintrc
[6]: /softuno/pictogram/blob/develop/sails/src/package.json
[7]: /softuno/pictogram/tree/develop/sails/src
......@@ -10,7 +10,7 @@ En cada directorio puede leerse la descripción de dicha parte, incluyendo confi
utilidades. La estructura del repositorio en sí y forma de contribución se describe en
[el fichero de contribuciones][1].
[1]: ./CONTRIBUTING.md
[2]: ./sails
[3]: ./sails/src/assets/app
[4]: ./android/Pictogram
[1]: /softuno/pictogram/blob/develop/CONTRIBUTING.md
[2]: /softuno/pictogram/tree/develop/sails
[3]: /softuno/pictogram/tree/develop/sails/src/assets/app
[4]: /softuno/pictogram/tree/develop/android/Pictogram
......@@ -25,6 +25,10 @@ mostradas más adelante hacen todo el trabajo.
```
2. Ejecutar [./install.sh][3].
3. Ejecutar [./bootstrap.sh][19] para lanzar el servidor.
4. Configurar los ficheros `/sails/src/config/local.js` y `/sails/src/assets/scripts/config.js`
generados si fuera necesario (estos ficheros no se encuentran en el repositorio, son generados
por ansible a partir de una plantilla).
5. Generar los [certificados ssl][21] si fuera necesario.
### Opción B (desarrollo): ejecución en una máquina virtual generada automáticamente
......@@ -39,11 +43,15 @@ mostradas más adelante hacen todo el trabajo.
```
2. Instalar [virtualbox][1] y [vagrant][2].
3. Ejecutar `vagrant up` desde este directorio.
4. Configurar los ficheros `/sails/src/config/local.js` y `/sails/src/assets/scripts/config.js`
generados si fuera necesario (estos ficheros no se encuentran en el repositorio, son generados
por ansible a partir de una plantilla).
5. Generar los [certificados ssl][21] si fuera necesario.
> **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.
## Ejecución del servidor
## Ejecución
Una vez lanzado sails con el servidor comienza con la compilación de la aplicación web mediante
tareas de Grunt, para esta configuración existe, por un lado, un fichero [Gruntfile.js][11] que
......@@ -66,20 +74,22 @@ siguientes comandos**:
[1]: https://www.virtualbox.org/
[2]: https://www.vagrantup.com/
[3]: ./install.sh
[4]: ./roles/nodejs
[5]: ./roles/mysql
[6]: ./roles/database
[7]: ./roles/webapp
[8]: ./roles/server
[3]: /softuno/pictogram/blob/develop/sails/install.sh
[4]: /softuno/pictogram/blob/develop/sails/roles/nodejs/README.md
[5]: /softuno/pictogram/blob/develop/sails/roles/mysql/README.md
[6]: /softuno/pictogram/blob/develop/sails/roles/database/README.md
[7]: /softuno/pictogram/blob/develop/sails/roles/webapp/README.md
[8]: /softuno/pictogram/blob/develop/sails/roles/server/README.md
[9]: https://www.ansible.com/
[10]: ./src
[11]: ./src/Gruntfile.js
[12]: ./src/tasks
[13]: ./src/tasks/config
[14]: ./src/tasks/register
[15]: ./src/tasks/register/default.js
[16]: ./src/tasks/register/prod.js
[17]: ./src/tasks/register/build.js
[18]: ./src/tasks/register/buildProd.js
[19]: ./bootstrap.sh
[10]: /softuno/pictogram/blob/develop/sails/src/README.md
[11]: /softuno/pictogram/blob/develop/sails/src/Gruntfile.js
[12]: /softuno/pictogram/blob/develop/sails/src/tasks/README.md
[13]: /softuno/pictogram/blob/develop/sails/src/tasks/config/README.md
[14]: /softuno/pictogram/blob/develop/sails/src/tasks/register/README.md
[15]: /softuno/pictogram/blob/develop/sails/src/tasks/register/default.js
[16]: /softuno/pictogram/blob/develop/sails/src/tasks/register/prod.js
[17]: /softuno/pictogram/blob/develop/sails/src/tasks/register/build.js
[18]: /softuno/pictogram/blob/develop/sails/src/tasks/register/buildProd.js
[19]: /softuno/pictogram/blob/develop/sails/bootstrap.sh
[20]: https://localhost:1337/app
[21]: /softuno/pictogram/tree/develop/sails/src/config/ssl
# 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]: /softuno/pictogram/blob/develop/sails/doc/assets/database-er-diagram.png
[2]: /softuno/pictogram/blob/develop/sails/doc/api.md
[3]: /softuno/pictogram/blob/develop/sails/doc/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]: /softuno/pictogram/blob/develop/sails/src/config/routes.js
[2]: /softuno/pictogram/tree/develop/sails/src/api/controllers
[3]: /softuno/pictogram/blob/develop/sails/src/config/policies.js
[4]: /softuno/pictogram/tree/develop/sails/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
......@@ -20,13 +20,13 @@ Los ficheros SQL que importará este rol son los siguientes:
- [test-caja][9] contiene datos para el test de CAJA.
- [test-autismojaen][10] añade los datos para el test de autismojaen.
[1]: ./files/init.sql
[2]: ./files/init-ignoresymbolstix.sql
[3]: ./files/pictodb-schema.sql
[4]: ./files/pictodb-data.sql
[5]: ./files/symbolstx-categories.sql
[6]: ./files/symbolstx-metadata.sql
[7]: ./files/triggers-enrolments-integrity-constraints.sql
[8]: ./files/triggers-sessions-integrity-constraints.sql
[9]: ./files/test-autismojaen.sql
[10]: ./files/test-caja.sql
[1]: /softuno/pictogram/blob/develop/sails/roles/database/files/init.sql
[2]: /softuno/pictogram/blob/develop/sails/roles/database/files/init-ignoresymbolstix.sql
[3]: /softuno/pictogram/blob/develop/sails/roles/database/files/pictodb-schema.sql
[4]: /softuno/pictogram/blob/develop/sails/roles/database/files/pictodb-data.sql
[5]: /softuno/pictogram/blob/develop/sails/roles/database/files/symbolstx-categories.sql
[6]: /softuno/pictogram/blob/develop/sails/roles/database/files/symbolstx-metadata.sql
[7]: /softuno/pictogram/blob/develop/sails/roles/database/files/triggers-enrolments-integrity-constraints.sql
[8]: /softuno/pictogram/blob/develop/sails/roles/database/files/triggers-sessions-integrity-constraints.sql
[9]: /softuno/pictogram/blob/develop/sails/roles/database/files/test-autismojaen.sql
[10]: /softuno/pictogram/blob/develop/sails/roles/database/files/test-caja.sql
......@@ -15,13 +15,13 @@ SET foreign_key_checks=0;
-- Default supervisor (ID -1) for PCB autonomous mode
--
INSERT INTO `supervisor` (`id`, `name`, `surname`, `gender`, `pic`, `address`, `country`, `email`, `phone`, `lang`, `tts_engine`, `password`, `id_off`, `active`) VALUES
('-1', 'none', 'none', 'M', '/app/img/default.jpg', NULL, NULL, '', NULL, 'es-es', NULL, '', NULL, '0');
('-1', 'none', 'none', 'M', 'defaultAvatar.jpg', NULL, NULL, '', NULL, 'es-es', NULL, '', NULL, '0');
--
-- Meta-method
--
INSERT INTO `meta_method` (`id`, `name`, `description`, `id_sup`) VALUES
INSERT INTO `meta_method` (`id`, `name`, `description`, `id_sup`) VALUES
(1, 'Comunicación Aumentativa y Adaptativa', NULL, NULL);
--
......@@ -274,7 +274,7 @@ INSERT INTO `picto_core_cat` (`id`, `id_pic`, `id_cat_pic`, `coord_x`, `coord_y`
(186, 325, 54270, 2, 6, NULL), -- Change.turn on
(187, 328, 54270, 2, 7, NULL), -- Change.turn off
(188, 52670, 52736, 4, 5, NULL), -- Drinks.milk
(194, 4848,4724, 1, 2, NULL), -- Body parts.hair
(194, 4848,4724, 1, 2, NULL), -- Body parts.hair
(195, 4872,4724, 1, 3, NULL), -- Body parts.head
(196, 50694,4724, 1, 4, NULL), -- Body parts.eye
(197, 4787 ,4724, 1, 5, NULL), -- Body parts.ear
......
......@@ -30,7 +30,6 @@ CREATE TABLE IF NOT EXISTS `action` (
`timestamp` timestamp DEFAULT CURRENT_TIMESTAMP,
`id_sup` int(11) DEFAULT NULL,
`id_stu` int(11) NOT NULL,
`id_dev` 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',
`gps_lat` float DEFAULT NULL,
......@@ -41,7 +40,6 @@ CREATE TABLE IF NOT EXISTS `action` (
UNIQUE (id_stu,timestamp),
KEY `fk_sup_act` (`id_sup`),
KEY `fk_stu_act` (`id_stu`),
KEY `id_dev` (`id_dev`),
KEY `id_try` (`id_try`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
......@@ -64,20 +62,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`
--
......@@ -199,21 +183,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`
--
......@@ -365,7 +334,7 @@ CREATE TABLE IF NOT EXISTS `student` (
`birthdate` date NOT NULL,
`gender` char(1) COLLATE utf8_unicode_ci NOT NULL,
`country` char(2) COLLATE utf8_unicode_ci NOT NULL,
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT '/app/img/default.jpg',
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'defaultAvatar.jpg',
`notes` varchar(1024) COLLATE utf8_unicode_ci DEFAULT 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',
......@@ -411,21 +380,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`
--
......@@ -434,7 +388,7 @@ CREATE TABLE IF NOT EXISTS `supervisor` (
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`surname` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`gender` char(1) COLLATE utf8_unicode_ci NOT NULL,
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT '/app/img/default.jpg',
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT '/upload/supervisorAvatar/defaultAvatar.jpg',
`address` varchar(180) COLLATE utf8_unicode_ci DEFAULT NULL,
`country` varchar(2) COLLATE utf8_unicode_ci DEFAULT NULL,
`email` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
......@@ -496,7 +450,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`);
......@@ -534,12 +487,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`
--
......@@ -592,13 +539,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`
......@@ -652,7 +592,7 @@ VIEW `v_stu_last_instruction` AS
I.`name` AS `ins_name`,
M.`name` AS `met_name`,
M.`id_stu` AS `id_stu`
FROM
FROM
`working_session` AS WS join
`instruction` AS I join
`method` AS M join
......@@ -670,7 +610,7 @@ VIEW `v_stu_last_instruction` AS
--
-- Vista materializada mv_stu_last_working_session_detail
-- Mantenida por
-- Mantenida por
-- Utilizada por SAILS:StudentController.lasttries
--
--
......
/**
* 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',
};
This diff could not be displayed because it is too large.
---
- name: Install libselinux-python (necesary for copying files)
package:
name: libselinux-python
state: present
- name: Install NPM dependencies
npm:
path: "{{ server_path }}/{{ server_relative_path }}"
- name: Create log directory
file:
path: "{{ server_path }}/{{ server_relative_path }}/logs"
path: "{{ server_path }}/logs"
state: directory
- name: Create log file
file:
path: "{{ server_path }}/{{ server_relative_path }}/logs/my_log_file.log"
state: touch
- name: Copy local.js file
copy:
src: "{{ server_path }}/roles/server/files/local.js"
dest: "{{ server_path }}/{{ server_relative_path }}/config/local.js"
force: no
- name: Install sails globaly
npm:
......
......@@ -3,5 +3,5 @@
/* Configuration constants */
angular.module('dashboardConfig', []).constant('config', {
backend: "http://localhost:1337"
backend: "{{ server_backend_url }}"
});
/* global angular */
angular.module('dashboardConfig', []).constant('config', {
backend: 'https://localhost:1337',
});
---
- name: Install libselinux-python (necesary for copying files)
package:
name: libselinux-python
state: present
- name: Install git
package:
name: git
......@@ -11,5 +16,11 @@
state: present
global: yes
- name: Copy config.js file
copy:
src: "{{ server_path }}/roles/webapp/files/config.js"
dest: "{{ server_path }}/src/assets/scripts/config.js"
force: no
- name: Install bower dependencies
bower: path="{{ webapp_path }}"
......@@ -11,6 +11,7 @@
"object-shorthand": 0,
"prefer-arrow-callback": 0,
"prefer-template": 0,
"strict": 0
"strict": 0,
"prefer-rest-params": 0
}
}
/**
* AclPictoController
*
* @description :: Server-side logic for managing aclpictoes
* @help :: See http://links.sailsjs.org/docs/controllers
*/
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 a new Action, which is executed by a student during a try. If now try is
* specified, the current try will be used as default. If there is no try openned it will
* return an error.
* @param {request} req
* {
* student: studentId,
* type: 'Add / Select / Delete / Show / Unshow / Pause / tryinit /
* tryend / initsession / endsession / pausesession / resumesession',
* timestamp: 'Date()', (optional)
* supervisor: supervisorId, (optional)
* _try: _tryId, (optional)
* description: '{ json description }', (optional)
* gpsLat: 'location lattitude', (optional)
* gpsLon: 'location longitude' (optional)
* }
* @param {response} res
* {
* id: actionId,
* student: studentId,
* type: 'action_type',
* timestamp: 'Date()',
* supervisor: supervisorId,
* _try: _tryId,
* description: '{ json description }',
* gpsLat: 'location lattitude',
* gpsLon: 'location longitude'
* }
*/
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 +64,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 '+ params.type);
return res.json(500, {error: 'Action '+ params.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 +81,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 +97,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 +111,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 +120,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) {
// @TODO ¿?¿?
login: function (req, res) {
var bcrypt = require('bcrypt-nodejs');
var email = req.body.email;
var password = req.body.password;
......@@ -19,14 +13,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 +31,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
*/
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
*/
module.exports = {
};
/* global Instruction, Method */
/**
* InstructionController
*
* @description :: Server-side logic for managing instructions
* @help :: See http://links.sailsjs.org/docs/controllers
* InstructionController manages the requests related to the Instruction model.
* Read it's documentation for further information.
* @type {Object}
*/
module.exports = {
//
// Returns all tries for the given instruction
//
// Do a method to retrieve all tries by workingSessions attribute
/**
* Create a new Instruction, which is associated to the given method
* @param {request} req
* {
* method: methodId,
* name: 'New instruction' (optional)
* objective: 'This instruction has an objective... description' (optional)
* status: 'progress' (optional)
* begin: Date() (optional)
* end: Date() (optional)
* }
* @param {response} res
* {
* id (instructionId)
* method
* name
* objective
* status
* begin
* end
* }
*/
create: function (req, res) {
Method.findOne({ id: req.param('method') }).then(function (method) {
if (!method) {
res.badRequest();
throw new Error('method not found');
}
Instruction.create({
method: method.id,
name: req.param('name'),
objective: req.param('objective'),
status: req.param('status'),
begin: req.param('begin'),
end: req.param('end')
}).then(function (instruction) {
if (instruction) {
res.ok(instruction);
} else {
res.badRequest();
}
})
.catch(function () {
res.serverError();
});
})
.catch(function () {
res.serverError();
});
},
/**
* Update an existing Instruction, known by it's ID
* @param {request} req (with instruction id as url parameter)
* {
* method: methodId, (optional)
* name: 'New instruction' (optional)
* objective: 'This instruction has an objective... description' (optional)
* status: 'progress' (optional)
* begin: Date() (optional)
* end: Date() (optional)
* }
* @param {response} res
* {
* id
* method
* name
* objective
* status
* begin
* end
* }
*/
update: function (req, res) {
Instruction.findOne({ id: req.params.id }).then(function (instruction) {
if (!instruction) {
res.badRequest();
throw new Error('instruction not found');
}
instruction.method = req.param('method') || instruction.method;
instruction.name = req.param('name') || instruction.name;
instruction.objective = req.param('objective') || instruction.objective;
instruction.status = req.param('status') || instruction.status;
instruction.begin = req.param('begin') || instruction.begin;
instruction.end = req.param('end') || instruction.end;
instruction.save(function (error) {
if (error) {
res.serverError();
} else {
res.ok(instruction);
}
});
})
.catch(function () {
res.serverError();
});
},
/**
* Delete an instruction by its ID
* @param {request} req {} (with instructionId as url parameter)
* @param {response} res {}
*/
destroy: function (req, res) {
Instruction.destroy({ id: req.params.id }).exec(function (error) {
if (error) {
res.badRequest();
throw error;
}
res.ok();
});
},
ws: function(req, res) {
if (!req.params.id_ins) {
......@@ -23,4 +132,3 @@ module.exports = {
});
}
};
/**
* LearningUnitController
*
* @description :: Server-side logic for managing learningunits
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
};
/**
* MetaStuController
*
* @description :: Server-side logic for managing Metastus
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
};
/* global sails, Method, MetaMethod */
/**
* MethodController
*
......@@ -7,10 +9,29 @@
module.exports = {
//
// create action
// adds a method
//
/**
* Creates a new method for a student using a template (metamethod)
* @param {request} req
* {
* id_mmethod: metaMethodId,
* id_stu: studentId
* }
* @param {response} res
* {
* id: methodId,
* name: 'MetaMethod Name',
* description: 'MetaMethod Description',
* instructions: [
* {
* id: instructionId,
* name: 'Instruction Name',
* objective: 'Instruction Objective',
* method: methodId
* },
* ...
* ]
* }
*/
create: function(req, res) {
var params = req.allParams();
......@@ -30,10 +51,9 @@ module.exports = {
Method.create({ name: mmethod.name, description: mmethod.description, student: params.id_stu}).exec(function (err, created) {
if (err) {
sails.log.debug("Creating new method: " + err);
return res.json(500, {error: 'Method not created'});
return res.json(500, {error: 'Method not created'});
}
if (created) {
// Find meta instructions associated to meta method
MetaInstruction.find({id_met: params.id_mmethod}).exec(function(err, minstructions) {
......@@ -43,8 +63,8 @@ module.exports = {
}
sails.log.debug("Meta instructions found: " + JSON.stringify(minstructions));
console.log("Meta instructions found: " + JSON.stringify(minstructions));
var l_ins = [];
// Every meta instruction is going to be created in 'Instruction'
......@@ -54,8 +74,8 @@ module.exports = {
sails.log.debug("Loop adding meta instruction: " + mins.name + " to method " + created.id);
Instruction.create({
method: created.id,
Instruction.create({
method: created.id,
name: mins.name,
objective: mins.objective
}).exec(function(err, added){
......@@ -63,21 +83,21 @@ module.exports = {
if(added){
l_ins.push(added);
sails.log.debug("Instruction " + added.name + " added to method " + created.id);
console.log("Instruction " + added.name + " added to method " + created.id);
}
callback();
});
});
// 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 a metainstruction');
} else {
console.log('All metainstructions have been processed successfully');
return res.json({
"name": created.name,
"description": created.description,
......@@ -89,55 +109,75 @@ module.exports = {
});
});
}
});
});
},
// Create new empty method
newMethod: function(req, res) {
var params = req.allParams();
if (!params.id_stu) return res.json(500, {error: "No student defined"});
if (!params.name) return res.json(500, {error: "No method name defined"});
Method.create({ name: params.name, student: params.id_stu }).exec(function (err, created) {
if (err) {
sails.log.debug("Creating new method: " + err);
return res.json(500, {error: 'Method not created'});
}
if (created) {
return res.json(created);
}
});
});
},
meta_methods: function(req, res) {
/**
* Creates a new method from scratch (without using a template)
* @param {request} req
* {
* id_stu: studentId,
* name: 'Method name'
* }
* @param {response} res
* {
* id: methodId,
* student: studentId,
* name: 'Method name'
* }
*/
newMethod: function (req, res) {
if (req.param('name') && req.param('id_stu')) {
Method.create({
name: req.param('name'),
student: req.param('id_stu')
}).then(function (method) {
if (!method) {
res.badRequest();
throw new Error('method not created');
}
res.ok(method);
})
.catch(function () {
res.serverError();
});
} else {
res.badRequest();
}
},
/**
* Return all the metamethods of a given supervisor (including the public metamethods)
* not associated to a concrete supervisor.
* @param {request} req {} (with idSup specified as url parameter)
* @param {response} res
* [
* {
* id: metamethodId
* name: 'Metamethod Name'
* description: 'Metamethod description, which can be longer'
* },
* ...
* ]
*/
meta_methods: function (req, res) {
var params = req.allParams();
MetaMethod.find({ or: [
{ supervisor: null },
{ supervisor: params.id_sup }
] }).then(function (metaMethods) {
res.ok(metaMethods);
})
.catch(function () {
res.serverError();
});
},
var params = req.allParams();
MetaMethod.find({
or : [
{ supervisor : null }, // General MetaMethods
{ supervisor : params.id_sup } // Supervisor MetaMethods (templates)
]
}).exec(function(err, methods) {
if (err || !methods || methods.length == 0){
sails.log.debug("MetaMethods: " + err);
return res.json([]); // empty array
}
sails.log.debug("MetaMethods: " + methods.length);
sails.log.debug(methods);
return res.json(methods);
});
},
// FERNANDO: avoid method name duplicates
save: function(req, res){
......@@ -145,14 +185,14 @@ module.exports = {
if (!params.id_met) return res.json(500, {error: "No method defined"});
if (!params.id_sup) return res.json(500, {error: "No supervisor defined"});
Method.findOne(params.id_met).populate('instructions').exec(function(err, method) {
if (err){
sails.log.debug("Find Method: " + err);
return res.json(500, {error: "No method found"}); // empty array
}
console.log("Method found:" + JSON.stringify(method));
MetaMethod.create({
"name": method.name,
......@@ -172,30 +212,29 @@ module.exports = {
sails.log.debug("Loop adding meta instruction: " + mins.name + " from method " + createdMethod.id);
MetaInstruction.create({
id_met: createdMethod.id,
MetaInstruction.create({
id_met: createdMethod.id,
name: mins.name,
objective: mins.objective
}).exec(function(err, added){
if(err) sails.log.debug("MetaInstruction.create: " + err);
if(added){
sails.log.debug("MetaInstruction " + added.name + " added from method " + createdMethod.id);
console.log("MetaInstruction " + added.name + " added from method " + createdMethod.id);
}
callback();
});
});
// 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 a meta instruction');
} else {
console.log('All meta instructions have been processed successfully');
return res.json(createdMethod);
return res.json(createdMethod);
}
});
......@@ -219,24 +258,24 @@ module.exports = {
if (err || !instructions){
sails.log.debug("Destroy Instructions: " + err);
return res.json(500, {error: "Cannot delete instructions"});
return res.json(500, {error: "Cannot delete instructions"});
}
// Destroy method
Method.destroy({ id: params.id }).exec(function(err, method) {
console.log("Method ID: " + params.id);
console.log("Found: " + JSON.stringify(method));
if (err || !method){
sails.log.debug("Destroy Method: " + err);
return res.json(500, {error: "No method found"});
return res.json(500, {error: "No method found"});
}
return res.json(method);
});
});
},
......@@ -254,25 +293,24 @@ module.exports = {
if (err || !metainstructions){
sails.log.debug("Destroy MetaInstructions: " + err);
return res.json(500, {error: "No meta instructions found"});
return res.json(500, {error: "No meta instructions found"});
}
// Destroy method
MetaMethod.destroy({ id: params.id_mmet }).exec(function(err, metamethod) {
console.log("Meta Method ID: " + params.id_mmet);
console.log("Found: " + JSON.stringify(metamethod));
if (err || !metamethod){
sails.log.debug("Destroy MetaMethod: " + err);
return res.json(500, {error: "No meta method found"});
return res.json(500, {error: "No meta method found"});
}
return res.json(metamethod);
});
});
}
};
};
/* global Office */
/**
* OfficeController
*
* @description :: Server-side logic for managing offices
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
/**
* `OfficeController.create()`
*/
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)
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 (created){
// If the admin is specified in the office
// update the office for the admin too
if(created.admin){
Supervisor.update({id:created.admin},{office:created.id}).exec(function (err, updated) {
if(err) console.log("Error updating office of supervisor")
if(updated) console.log(updated);
});
}
return res.json({office: created});
}
});
});
},
/**
* `OfficeController.update()` by sails default
*/
/**
* `OfficeController.destroy()` by sails default
*/
/**
* `OfficeController.get()`
* Returns the office with the given id
* Return an Office found by id
* @param {request} req {} (with officeId as url parameter)
* @param {response} res
* {
* supervisors: [Empty array],
* admin: {
* "name": "John"
* "surname": "Doe"
* "gender": "F/M"
* "password": "1234"
* "pic": "url/to/photo.jpg"
* "address": "Nice street"
* "country": "ES/UK/..."
* "email": "john@doe.com"
* "phone": "+123456789"
* "lang": "ES/EN/..."
* "tts_engine": "IVONA Text-to-Speech HQ"
* },
* id: 3123,
* name: 'First Office in the World',
* address: 'The World, Earth',
* email: 'the_office@world.com',
* phone1: '+34 123 123 123',
* phone2: null,
* lang: 'es-es',
* contactPerson: 'John Doe'
* }
*/
get: function (req, res) {
if (!req.params.id)
return res.json(500, {err: "Office ID must be specified"});
Office.findOne(req.params.id).populate('admin').exec(function(err, office) {
if (err) return res.json(500, {err: err.details});
if (office)
return res.json(200, office);
return res.json({error: "Office not found"});
Office.findOne({ id: req.params.id }).populate('admin').then(function (office) {
if (office) {
res.ok(office);
} else {
res.notFound();
}
})
.catch(function () {
res.badRequest();
});
},
/**
* `OfficeController.getAll()`
* Returns all possible offices
* Return all offices
* @param {request} req {}
* @param {response} res
* [
* {
* supervisors: [Empty array],
* admin: {
* "name": "John"
* "surname": "Doe"
* "gender": "F/M"
* "password": "1234"
* "pic": "url/to/photo.jpg"
* "address": "Nice street"
* "country": "ES/UK/..."
* "email": "john@doe.com"
* "phone": "+123456789"
* "lang": "ES/EN/..."
* "tts_engine": "IVONA Text-to-Speech HQ"
* },
* id: 3123,
* name: 'First Office in the World',
* address: 'The World, Earth',
* email: 'the_office@world.com',
* phone1: '+34 123 123 123',
* phone2: null,
* lang: 'es-es',
* contactPerson: 'John Doe'
* },
* ...
* ]
*/
getAll: function (req, res) {
Office.find().populate('admin').exec(function(err, offices) {
if (err) return res.json(500, {err: err.details});
if (offices)
return res.json(200, offices);
return res.json({error: "Offices not found"});
Office.find().populate('admin').then(function (offices) {
res.ok(offices);
})
.catch(function () {
res.serverError();
});
},
/**
* `OfficeController.supervisors()`
* Returns all supervisors of an office
* Get all supervisors from an office
* @param {request} req {} (with officeId as url parameter)
* @param {response} res
* [
* {
* "name": "John"
* "surname": "Doe"
* "gender": "F/M"
* "password": "1234"
* "pic": "url/to/photo.jpg"
* "address": "Nice street"
* "country": "ES/UK/..."
* "email": "john@doe.com"
* "phone": "+123456789"
* "lang": "ES/EN/..."
* "tts_engine": "IVONA Text-to-Speech HQ"
* },
* ...
* ]
*/
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'});
return res.json(200, off.supervisors);
Office
.findOne({ id: req.params.id })
.populate('supervisors')
.then(function (office) {
if (office) {
res.ok(office.supervisors);
} else {
res.notFound();
}
})
.catch(function () {
res.badRequest();
});
},
};
/**
* PagesController
*
* @description :: This controller sends back AngularJS pages
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
login: function (req, res) {
res.view('login');
},
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
*/
module.exports = {
};
/**
* PictoPropController
*
* @description :: Server-side logic for managing pictoprops
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
};
/**
* PictoTagController
*
* @description :: Server-side logic for managing pictotags
* @help :: See http://links.sailsjs.org/docs/controllers
*/
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 = {
);
}
};
......@@ -4,21 +4,23 @@
* @description :: Server-side logic for managing server
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
//
// ping action
// This action simply return OK to ensure connection is up from device
//
ping: function(req, res) {
return res.json(200, {result: "OK"});
},
/**
* Returns ok (checking if the server is online)
* @param {request} req {}
* @param {response} res {}
*/
ping: function (req, res) {
res.ok();
},
//
// ping_session action
// Same as 'ping' but token is required (see config/policies.js)
//
ping_session: function(req, res) {
return res.json(200, {result: "OK"});
}
};
\ No newline at end of file
/**
* Returns ok (checking if the server is online).
* This method needs a previous authentication (check policies.js)
* @param {request} req {}
* @param {response} res {}
*/
ping_session: function (req, res) {
res.ok();
}
};
/**
* SourceController
*
* @description :: Server-side logic for managing sources
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
};
/**
* StuOpenTryController
*
* @description :: Server-side logic for managing StuOpenTry
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
};
/**
* StuSupController
*
* @description :: Server-side logic for managing stusups
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
};
/**
* 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
*/
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 = {
},
};
......@@ -12,7 +12,7 @@
* information to send.
* @type {Object}
*/
module.exports = function eventsHook (sails) {
module.exports = function eventsHook(sails) {
return {
/**
* Speacial Function wrapping sails.sockets.broadcast that uses a room
......@@ -38,12 +38,14 @@ module.exports = function eventsHook (sails) {
rooms = [rooms];
}
sails.log.debug('"websocketEvent":', JSON.stringify({
rooms: rooms,
name: event.name,
data: event.data,
socketToOmit: socketToOmit ? socketToOmit.id : undefined
}));
// Ensure data is an object
if (!(typeof event.data === 'object' && event.data !== null)) {
event.data = {};
}
sails.log.debug("Websocket event '%s' with data '%j' sent to '%s'",
event.name, event.data, rooms.join(', ')
);
sails.sockets.broadcast(
rooms,
......@@ -70,6 +72,22 @@ module.exports = function eventsHook (sails) {
},
/**
* A supervisor has been unlinked from a student.
* @param {ID} supId ID of the supervisor
* @param {ID} stu_id ID of the student
* @return {Object} {name, data}
*/
unlinkSupervisorFromStudent: function (supId, stuId) {
return {
name: 'unlinkSupervisorFromStudent',
data: {
sup_id: supId,
stu_id: stuId
}
};
},
/**
* Someone has subscribed/unsubscribed to/from a room. The number
* of subscribes is sent
* @param {number} subscriberCount Number of subscribers
......
......@@ -13,7 +13,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -23,11 +23,23 @@ module.exports = {
},
type: {
required: true,
type: "string",
size: 20
type: 'string',
enum: [
'Add',
'Select',
'Delete',
'Show',
'Unshow',
'Pause',
'tryinit',
'tryend',
'initsession',
'endsession',
'pausesession',
'resumesession'
]
},
timestamp: {
//required: true,
type: "datetime"
},
supervisor: { // FK de Supervisor. 1 a N
......@@ -42,23 +54,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 +74,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();
}
};
/* global sails */
/**
* picto.js
*
* @description :: TODO: Write a short summary of how this model works and what it represents here.
* @docs :: http://sailsjs.org/#!documentation/models
*/
* picto.js
*
* @description :: TODO: Write a short summary of how this model works and what it represents here.
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
tableName : 'picto',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
tableName: 'picto',
migrate: 'safe',
schema: true,
autoPK: false,
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
id: {
type: "integer",
type: 'integer',
autoIncrement: true,
primaryKey: true,
unique: true
},
uri: {
required: true,
type: "string",
type: 'string',
size: 250
},
source: { // FK de Source. 1 source to N pictos
columnName: "id_src",
source: { // 1 Source to N Pictos
columnName: 'id_src',
required: true,
type: "integer",
model: "Source"
type: 'integer',
model: 'Source'
},
owner: { // FK de Supervisor. 1 a N
columnName: "id_owner",
type: "integer",
owner: { // 1 Supervisor to N Owners
columnName: 'id_owner',
type: 'integer',
required: false,
model: "Supervisor"
model: 'Supervisor'
},
category:{
columnName: "id_cat",
type: "integer"
category: {
columnName: 'id_cat',
type: 'integer'
},
// Relación con Expression. [1 Picto to N Expression]
expressions: {
collection: "PictoExp",
via: "picto"
expressions: { // 1 Picto to N PictoExp
collection: 'PictoExp',
via: 'picto'
},
// Relación con PictoTag. [1 Picto to N PictoTag]
tags: {
collection: "PictoTag",
via: "picto"
tags: { // 1 Picto to N PictoTag
collection: 'PictoTag',
via: 'picto'
},
tagsSup: { // tags created by supervisors
collection: "PictoTagSup",
via: "picto"
tagsSup: {
collection: 'PictoTagSup',
via: 'picto'
},
// Relación con PictoAcl. [1 Picto to N PictoAcl]
pictoAcls:{
collection: "PictoAcl",
via: "picto"
pictoAcls: { // 1 Picto to N PictoAcl
collection: 'PictoAcl',
via: 'picto'
},
stusPicto: {
collection: 'StuPicto',
......@@ -66,44 +65,11 @@ module.exports = {
}
},
//
// Returns all categories for the given supercategory with the expression in the supervisor language
//
categories: function(id_sup, id_cat, callback) {
Supervisor.findOne(id_sup).exec(function(err, sup) {
if (err) {
console.log("Error retrieving categories for supervisor " + id_sup + ": " + err);
return callback(err, []);
}
// 0 for the main categories --> null in DB
// if(id_cat == 0) id_cat = null;
PictoCat.find({id_supercat: id_cat}).populate('exps', {lang: sup.lang}).exec(function(err, pictoCats) {
if (err || !pictoCats || pictoCats.length == 0)
return callback(err, []);
else
return callback(err, pictoCats);
});
});
},
//
// Returns all pictos from a given category with the expression in the supervisor language
//
fromcategory: function(id_sup, id_cat, callback) {
Supervisor.findOne(id_sup).exec(function(err, sup) {
if (err) {
console.log("Error retrieving categories for supervisor " + id_sup + ": " + err);
return callback(err, []);
}
Picto.find({category: id_cat}).populate('expressions', {lang: sup.lang}).exec(function(err, pictos) {
if (err || !pictos || pictos.length == 0)
return callback(err, []);
else
return callback(err, pictos);
});
});
toJSON: function () {
var picto = this.toObject();
if (picto.owner !== null) {
picto.uri = sails.config.pictogram.urls.getSupervisorCustomPictoUrl(picto.uri);
}
return picto;
}
};
\ No newline at end of file
};
/**
* 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'
}
}
};
/**
* StuPicto.js
*
* @description :: This model represents the collection of pictos for a student,
* with the properties associated to it
* @description :: This model represents the collection of pictos for a student,
* with the properties associated to it
* @docs :: http://sailsjs.org/#!documentation/models
*/
......@@ -13,7 +13,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -54,7 +54,7 @@ module.exports = {
"id_cat" : null,
"coord_x" : null,
"coord_y" : null,
"status": "enabled"
"status": "enabled"
};
*/
......@@ -79,8 +79,6 @@ module.exports = {
if(attrs.attributes.color !== undefined)
var previous_color = attrs.attributes.color;
console.log(configuration.toString());
attrs.attributes = JSON.parse("{" + configuration.toString() + "}");
// And we store them (If the picto is from picto_core, it has defined the coords)
......@@ -98,9 +96,8 @@ module.exports = {
if(previous_color !== undefined)
attrs.attributes.color = previous_color;
//console.log(attrs.attributes);
next();
});
});
}
}
\ No newline at end of file
}
/* global sails */
/**
* student.js
*
......@@ -12,7 +14,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -83,36 +85,28 @@ 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"
},
//
// JSON limitations
//
toJSON: function() {
var obj = this.toObject();
// avoid sending this fields
delete obj.password;
return obj;
toJSON: function () {
var student = this.toObject();
student.pic = sails.config.pictogram.urls.getStudentAvatarUrl(student.pic);
delete student.password;
return student;
},
},
//
// 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 +147,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,22 +156,21 @@ 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);
next();
},
......@@ -194,15 +187,14 @@ 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) {
delete stuSup.supervisor.password;
l.push(stuSup.supervisor);
}
next();
......@@ -221,15 +213,14 @@ 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) {
delete stuSup.supervisor.password;
l.push(stuSup.supervisor);
}
next();
......@@ -250,119 +241,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 +299,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 +309,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,28 +333,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();
});
});
},
sqlquery: function(query, callback) {
//code
Student.query(query, function (err,result) {
// Error handling
if (err) {
sails.log.debug(err);
return callback(err, {});
} else {
console.log("Data from raw sql query:", result);
return callback(err, result);
}
});
});
},
......@@ -435,7 +348,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 +358,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)
......
/* global Supervisor, sails */
/**
* supervisor.js
*
......@@ -5,18 +7,6 @@
* @docs :: http://sailsjs.org/#!documentation/models
*/
// Returns a 32 digit number from a string
String.prototype.hashCode = function() {
var hash = 0, i, chr, len;
if (this.length == 0) return hash;
for (i = 0, len = this.length; i < len; i++) {
chr = this.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer (| or bit a bit)
}
return hash;
};
module.exports = {
connection : 'localMysql',
tableName : 'supervisor',
......@@ -25,7 +15,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -94,17 +84,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 +104,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"
......@@ -128,21 +118,21 @@ module.exports = {
//
// JSON limitations
//
toJSON: function() {
var obj = this.toObject();
// avoid sending this fields
delete obj.password;
return obj;
toJSON: function () {
var supervisor = this.toObject();
supervisor.pic = sails.config.pictogram.urls.getSupervisorAvatarUrl(supervisor.pic);
delete supervisor.password;
return supervisor;
},
//
// sendMail
// adds a new entry into pending_registration
// and send an email confirmation to the user
sendMail: function() {
var hash_code = (this.name + this.email + this.phone);
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 +155,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
......@@ -184,104 +174,79 @@ module.exports = {
// Model hook for storing encrypted password when adding a new account
// and to check that the user is not already registered
//
beforeCreate: function(attrs, next) {
// We have to encryption AFTER checking user does not exist
// so... we use async.series to ensure task completion
beforeCreate: function (attrs, next) {
var async = require('async');
async.series(
[
function (cb) {
Supervisor.findOne({ email: attrs.email }).then(function (supervisor) {
if (supervisor) {
cb(new Error('Email being used'));
} else {
cb();
}
})
.catch(function () {
cb();
});
},
async.series([
function(cb) { // check email is new
Supervisor.findByEmail(attrs.email).exec(function(err, users) {
if (err) return cb(err);
if (users.length > 0)
return cb(new Error('User exists'));
cb();
});
},
function(cb) { // encrypt 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) {
if (err) return cb(err);
attrs.password = hash;
cb();
});
});
}
], function(err) {
if (err) return next(err);
next();
});
function (cb) {
var bcrypt = require('bcrypt-nodejs');
if (attrs.password) {
attrs.password = bcrypt.hashSync(attrs.password, bcrypt.genSaltSync());
}
cb();
}
],
function (err) {
if (err) {
next(err);
} else {
next();
}
}
);
},
//
// Model hook for storing encrypted password when updating an account
// and to check that the user new email is not already registered
//
beforeUpdate: function(attrs, next) {
async.series([
function(cb) {
//
// Check that user email does not exist
//
if(attrs.email){
Supervisor.findByEmail(attrs.email).exec(function(err, users) {
if (err)
return cb(err);
if (users.length > 0)
return cb(new Error('User email already exists'));
cb();
});
} else {
return cb(new Error('No email in user attributes'));
}
},
function(cb) {
//
// Encrypt password before insertion
//
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) {
if (err) return cb(err);
attrs.password = hash;
cb();
});
});
}else{
cb();
}
}], function(err) {
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);
beforeUpdate: function (attrs, next) {
var async = require('async');
async.series(
[
function (cb) {
Supervisor.findOne({ email: attrs.email }).then(function (supervisor) {
if (supervisor && supervisor.id !== attrs.id) {
cb(new Error('Email being used'));
} else {
cb();
}
})
.catch(function () {
cb();
});
},
async.eachSeries(stuSups,
function(stuSup, next) {
l.push(stuSup.student);
function (cb) {
var bcrypt = require('bcrypt-nodejs');
if (attrs.password) {
attrs.password = bcrypt.hashSync(attrs.password, bcrypt.genSaltSync());
}
cb();
}
],
function (err) {
if (err) {
next(err);
} else {
next();
},
function (err) {
return callback(err, l);
}
);
});
}
);
}
};
......@@ -11,7 +11,7 @@ principal:
- Los estilos se encuentran [/sails/src/assets/styles][3]
- Los scripts y vistas se encuentran en [/sails/src/assets/scripts][4]
[1]: ../../../install.sh
[2]: ../../../README.md
[3]: ../styles
[4]: ../scripts
[1]: /softuno/pictogram/blob/develop/sails/install.sh
[2]: /softuno/pictogram/tree/develop/sails
[3]: /softuno/pictogram/tree/develop/sails/src/assets/styles
[4]: /softuno/pictogram/tree/develop/sails/src/assets/scripts
......@@ -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;
});
//// 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/goddady/gd.yottacode.com.bundle.crt'),
key: require('fs').readFileSync(__dirname + '/ssl/goddady/gd.yottacode.com.key'),
cert: require('fs').readFileSync(__dirname + '/ssl/goddady/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'
};
'use strict';
//--------------------------
// Admin Devices Controller
//--------------------------
dashboardControllers.controller('AdminDevicesCtrl', function AdminDevicesCtrl($scope, $http, config) {
// The last parameter, config, is injected from config.js (defined in dashboardConfig module)
// Don't show the message at the begining and clean form
$scope.showmessagedevice = false;
// For message
$scope.tdata = {
idFirmware: '',
serial: '',
};
$scope.formdatadevice = {
idFirmware: '',
desc: '',
serial: ''
};
// List of free serials
$scope.freeserials = [];
$http
.get(config.backend+'/dev/freeserials')
.success(function(data, status, headers, config) {
// Add to list
$scope.freeserials = data;
console.log("Free serials listed");
})
.error(function(data, status, headers, config) {
console.log("Error from API: " + data.error);
});
// Generate serial
$scope.generate_serial = function(){
$http
.post(config.backend+'/dev/create')
.success(function(data, status, headers, config) {
$scope.showmessagedevice = true;
$scope.alertdevice = "alert-success";
$scope.messagedevice = "serial_created";
$scope.tdata.serial = data.serial;
console.log("Serial number created: " + data.serial);
// Add to list
$scope.freeserials.push(data);
})
.error(function(data, status, headers, config) {
$scope.showmessagedevice = true;
$scope.alertdevice = "alert-danger";
$scope.messagedevice = "serial_not_created";
console.log("Error from API: " + data.error);
});
};
// Register device with a free serial
$scope.register_device = function(){
$http
.post(config.backend+'/dev/register', $scope.formdatadevice)
.success(function(data, status, headers, config) {
$scope.showmessagedevice = true;
$scope.alertdevice = "alert-success";
$scope.messagedevice = "device_registered";
// For message
$scope.tdata.serial = $scope.formdatadevice.serial;
$scope.tdata.idFirmware = $scope.formdatadevice.idFirmware;
// Delete in view of free serials
for(var i=0; i < $scope.freeserials.length; i++) {
if($scope.formdatadevice.serial == $scope.freeserials[i].serial)
$scope.freeserials.splice(i,1);
}
console.log("Device registered with id firmware "+ $scope.formdatadevice.idFirmware +" and serial " + $scope.formdatadevice.serial);
// Clean form
$scope.formdatadevice = {
idFirmware: '',
desc: '',
serial: ''
};
})
.error(function(data, status, headers, config) {
$scope.showmessagedevice = true;
$scope.alertdevice = "alert-danger";
$scope.messagedevice = "device_not_registered";
console.log("Error from API: " + data.error);
});
};
});
\ No newline at end of file
......@@ -97,7 +97,7 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
lang: office.lang,
id: office.id,
maxStudents: office.maxStudents
};
};
$scope.formdataoffice.admin = {
id: office.admin.id,
......@@ -109,18 +109,18 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
// Save an Office updated
$scope.save_office = function(){
var office = $scope.formdataoffice;
console.log("1) Before searching admin id by email: " + JSON.stringify(office));
// If email admin is filled
// search id by email admin
console.log("2) Searching admin id by email");
$http
.get(config.backend+'/sup?where={"email":"'+ office.admin.email +'"}')
.get(config.backend + '/sup/email/' + office.admin.email)
.then(function(result) {
// result <-- data, status, headers, config
console.log("2.0) Data recovered: " + JSON.stringify(result.data[0]));
console.log("2.0) Data recovered: " + JSON.stringify(result.data[0]));
// If exists the email
if(result.data.length > 0){
if(result.data.length > 0){
office.admin.id = result.data[0].id;
console.log("2.1) Exists: " + office.admin.id);
// Delete the email, the id and id_off is the only needed
......@@ -130,12 +130,12 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
office.admin.id = null;
delete(office.admin.email);
}
console.log("3) Inside search by email admin: " + JSON.stringify(office));
console.log("3) Inside search by email admin: " + JSON.stringify(office));
// Returns the put request
return $http.put(config.backend+'/office/'+office.id, office);
return $http.put(config.backend+'/office/'+office.id, office);
})
.then(function(result){
console.log("4) Inside 2º then: " + JSON.stringify(result.data));
console.log("4) Inside 2º then: " + JSON.stringify(result.data));
// Show success message
$scope.showmessageoffice = true;
......@@ -148,14 +148,14 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
// Update the view: Se recorre el array de objetos json para buscarlo
for(var i=0; i < $scope.offices.length; i++) {
if(office.id == $scope.offices[i].id){
$scope.offices[i].name = result.data.name;
$scope.offices[i].address = result.data.address;
$scope.offices[i].contactPerson = result.data.contactPerson;
$scope.offices[i].email = result.data.email;
$scope.offices[i].phone1 = result.data.phone1;
$scope.offices[i].phone2 = result.data.phone2;
$scope.offices[i].lang = result.data.lang;
if(office.id == $scope.offices[i].id){
$scope.offices[i].name = result.data.name;
$scope.offices[i].address = result.data.address;
$scope.offices[i].contactPerson = result.data.contactPerson;
$scope.offices[i].email = result.data.email;
$scope.offices[i].phone1 = result.data.phone1;
$scope.offices[i].phone2 = result.data.phone2;
$scope.offices[i].lang = result.data.lang;
$scope.offices[i].maxStudents = result.data.maxStudents;
// Only if returns an admin
......@@ -163,7 +163,7 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
$scope.offices[i].admin.id = result.data.admin.id;
$scope.offices[i].admin.name = result.data.admin.name;
$scope.offices[i].admin.surname = result.data.admin.surname;
$scope.offices[i].admin.email = result.data.admin.email;
$scope.offices[i].admin.email = result.data.admin.email;
$scope.offices[i].admin.phone = result.data.admin.phone;
}else{
delete($scope.offices[i].admin);
......@@ -193,13 +193,13 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
// search id by email admin
console.log("2) Searching admin id by email");
$http
.get(config.backend+'/sup?where={"email":"'+ office.admin.email +'"}')
.get(config.backend + '/sup/email/' + office.admin.email)
.then(function(result) {
// result <-- data, status, headers, config
console.log("2.0) Data recovered: " + JSON.stringify(result.data[0]));
console.log("2.0) Data recovered: " + JSON.stringify(result.data[0]));
// If exists the email
if(result.data.length > 0){
sup = result.data[0];
if(result.data.length > 0){
sup = result.data[0];
office.admin.id = result.data[0].id;
console.log("2.1) Exists: " + office.admin.id);
// Delete the email, the id is the only needed
......@@ -208,12 +208,12 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
}else{
delete(office.admin);
}
console.log("3) Inside search by email admin: " + JSON.stringify(office));
console.log("3) Inside search by email admin: " + JSON.stringify(office));
// Returns the put request
return $http.post(config.backend+'/office', office);
return $http.post(config.backend+'/office', office);
})
.then(function(result){
console.log("4) Inside 2º then: " + JSON.stringify(result.data));
console.log("4) Inside 2º then: " + JSON.stringify(result.data));
// Show success message
$scope.showmessageoffice = true;
......@@ -244,7 +244,7 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
}
// Add to the list of office in view
$scope.offices.push(result.data.office);
$scope.offices.push(result.data.office);
})
.catch(function(result){
console.log("Error: " + result.data.error);
......@@ -265,10 +265,10 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
$http
.delete(config.backend+'/office/'+ office.id)
.success(function(data, status, headers, config) {
// Eliminar de la vista: Se recorre el array de objetos json para buscarlo
for(var i=0; i < $scope.offices.length; i++) {
if(office.id == $scope.offices[i].id)
if(office.id == $scope.offices[i].id)
$scope.offices.splice(i,1);
}
console.log("Office deleted:" + office.name);
......@@ -288,4 +288,4 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
});
}
};
});
\ No newline at end of file
});
......@@ -23,7 +23,7 @@ dashboardControllers.controller('AdminSupervisorsCtrl', function AdminSupervisor
// List of supervisors
$http
.get(config.backend+'/sup')
.get(config.backend+'/sup/all')
.success(function(data, status, headers, config) {
$scope.supervisors = data;
})
......@@ -104,7 +104,7 @@ dashboardControllers.controller('AdminSupervisorsCtrl', function AdminSupervisor
delete supervisor.id;
$http
.put(config.backend+'/supervisor/'+supid, supervisor)
.put(config.backend + '/sup/' + supid, supervisor)
.success(function(data, status, headers, config) {
$translate('supervisor_updated').then(function (translation) {
ngToast.success({ content: translation });
......
......@@ -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
......@@ -108,12 +108,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
// Search supervisor by email
$scope.search_sup = function () {
// Find tutor by email
$http.get([
config.backend,
'/sup?where={"email":"',
$scope.email_sup,
'", "office":{"!": null}}'
].join(''))
$http.get(config.backend + '/sup/email/' + $scope.email_sup)
.success(function (data) {
if (data.length > 0) {
$scope.supToAdd = data[0];
......@@ -190,7 +185,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
// Search tutor by email
$scope.search_tutor = function () {
// Find tutor by email
$http.get(config.backend + '/sup?where={"email":"' + $scope.email_tutor + '", "office":null}')
$http.get(config.backend + '/sup/email/' + $scope.email_tutor)
.success(function (data) {
// If it found the length is > 0
if (data.length > 0) {
......@@ -271,64 +266,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
//
......
......@@ -206,13 +206,4 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
.error(function () {
// TODO show error with ngToast
});
$scope.studentDevices = [];
$http.get(config.backend + '/stu/' + $scope.studentData.id + '/devices')
.success(function (data) {
$scope.studentDevices = data;
})
.error(function () {
// TODO show error with ngToast
});
});
......@@ -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 -->
......
......@@ -92,7 +92,7 @@ dashboardControllers.controller('SetupCtrl', function SetupCtrl(
delete supervisor.email;
}
$http.put(config.backend + '/sup', supervisor)
$http.put(config.backend + '/sup/' + supervisor.id, supervisor)
.success(function (data) {
$translate('data_saved').then(function (translation) {
ngToast.success({ content: translation });
......
......@@ -87,7 +87,7 @@ img.preview{
legend{ padding-top: 20px; }
/* Estilos aplicados por defecto
/* Estilos aplicados por defecto
(Móviles y pantallas menores de 992px)
*/
......@@ -122,7 +122,7 @@ div.languages {
padding-top: 10px;
margin: 0;
background-color: #f8f8f8;
border-top: 1px solid #e7e7e7;
border-top: 1px solid #e7e7e7;
font-size: 1.2em;
text-align: center;
}
......@@ -188,7 +188,7 @@ tr:hover .ops a{
#supervisor_header .img_profile{
margin-top: 10px;
margin-left: 10px;
margin-left: 10px;
margin-bottom: 0;
width: 50px;
height: 50px;
......@@ -233,11 +233,6 @@ tr:hover .ops a{
height: 40px;
}
/* Panel dipositivos del estudiante */
#student_devices{
margin-top: 30px;
}
/* Panel del estudiante (sin borde superior para pestañas) */
.student_tab_panel{
border-top: none;
......@@ -279,7 +274,7 @@ tr:hover .ops a{
/* Celdas con input para editar */
td.editable{
padding: 0px !important;
padding: 0px !important;
height: 40px;
}
......@@ -293,7 +288,7 @@ td.editable input{
.elipsis{
overflow: hidden;
text-overflow: ellipsis;
text-overflow: ellipsis;
}
......@@ -305,7 +300,7 @@ input.editable{
}
.editable:focus {
border-width: 1px;
border-width: 1px;
border-style: solid;
border-radius: 5px;
outline: none;
......@@ -321,7 +316,7 @@ textarea.editable{
padding: 6px;
margin-bottom: 8px;
}
/* Panel Colecciones */
.drag { opacity: 0.5; }
......@@ -427,7 +422,7 @@ textarea.editable{
/* Class for pictos when are deactivated to the student, but are visibles */
/*.picto img.deactivate {
filter: url('#grayscale'); / Versión SVG para IE10, Chrome 17, FF3.5, Safari 5.2 and Opera 11.6 /
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
......@@ -439,9 +434,9 @@ textarea.editable{
.picto img.disabled {
position: absolute;
bottom: 0px; /* position will be on bottom */
left: 0px;
width: 100%;
bottom: 0px; /* position will be on bottom */
left: 0px;
width: 100%;
}
/* Class for pictos that aren't saw by the student */
......@@ -521,7 +516,7 @@ textarea.editable{
/* Para que la altura de los li de la lista se adapte al tamaño automáticamente */
.list-group-item{
overflow:hidden;
overflow:hidden;
}
/* Etiquetas dentro de las ventanas modales de info y etiquetas de los pictos */
......@@ -662,7 +657,7 @@ textarea.editable{
/* Link to show the try actions */
.try_details{
visibility: hidden;
font-size: 2em;
font-size: 2em;
}
.try:hover .try_details{
......@@ -689,7 +684,7 @@ textarea.editable{
/* Para que se vea el menú contextual por encima del resto de paneles */
#options{
z-index: 10000;
z-index: 10000;
width: 200px;
}
......@@ -739,7 +734,7 @@ textarea.editable{
text-decoration: none;
}
/* Reports */
/* Reports */
#year_select{
max-width: 300px;
display: inline-block;
......@@ -778,7 +773,6 @@ img.profile{
#user_tutors .list-group-item:hover .delete_tutor,
#user_sups .list-group-item:hover .delete_sup,
#user_devices .list-group-item:hover .delete_device,
#table_students tr:hover .delete_stu{
visibility: visible;
}
......@@ -794,10 +788,10 @@ label.student_setup{
input[type=range] {
/*removes default webkit styles*/
-webkit-appearance: none;
/*fix for FF unable to apply focus style bug */
border: 1px solid white;
/*required for proper track sizing in FF*/
width: 300px;
}
......@@ -848,10 +842,10 @@ input[type=range]:-moz-focusring{
input[type=range]::-ms-track {
width: 300px;
height: 5px;
/*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */
background: transparent;
/*leave room for the larger thumb to overflow with a transparent border */
border-color: transparent;
border-width: 6px 0;
......@@ -898,9 +892,9 @@ input[type=range]:focus::-ms-fill-upper {
/* Se aplica de Dispositivos medianos en adelante
(tablets, ordenadores, anchura mayor o igual a 768px) */
@media (min-width: 768px) {
@media (min-width: 768px) {
/* Estilos generales */
/* Estilos para el panel de login*/
#login{
......@@ -912,7 +906,7 @@ input[type=range]:focus::-ms-fill-upper {
}
#signin .help-block{
}
}
......@@ -923,11 +917,11 @@ input[type=range]:focus::-ms-fill-upper {
width: 36px;
height: 36px;
padding: 8px;
background: #fff;
border: 2px solid #3071a9;
color: #3071a9;
text-align: center;
font: 32px Arial, sans-serif;
}
\ No newline at end of file
}
/**
* This tiny configuration tells sails that the assets folder should be served as public.
* These way we can send our application (and all the uploaded assets) as normal.
* @type {Object}
*/
module.exports = {
paths: {
public: __dirname+'/../assets' // or wherever
}
};
\ No newline at end of file
public: __dirname + '/../assets'
}
};
......@@ -8,48 +8,27 @@
* For more information on bootstrapping your app, check out:
* http://sailsjs.org/#/documentation/reference/sails.config/sails.config.bootstrap.html
*/
var fs = require('fs')
, path = require('path');
module.exports.bootstrap = function (cb) {
// Whatever else you want to bootstrap...
var source = path.join(process.cwd(), '../upload'),
dest = path.join(process.cwd(), 'assets/upload');
fs.readlink(dest, function(err, linkString){
// If symlin don't exists, it is created
if(!linkString){
console.log("Created symlink from " + source + " to " + dest);
fs.symlink(source, dest, 'dir', function(err) {
if (err) console.log(err);
});
}else{
console.log("Symlink to upload exists!");
}
});
var source2 = path.join(process.cwd(), '../symbolstx'),
dest2 = path.join(process.cwd(), 'assets/symbolstx');
fs.readlink(dest2, function(err, linkString2){
// If symlin don't exists, it is created
if(!linkString2){
console.log("Created symlink from " + source2 + " to " + dest2);
fs.symlink(source2, dest2, 'dir', function(err) {
if (err) console.log(err);
var fs = require('fs');
var path = require('path');
module.exports.bootstrap = function (callback) {
var i;
var directories = ['upload', 'symbolstx'];
function createSymlink(source, destination) {
fs.readlink(destination, function (error, linkString) {
if (!linkString) {
fs.symlink(source, destination, 'dir', function () {});
}
});
}
}else{
console.log("Symlink to symbolstx exists!");
}
});
for (i = 0; i < directories.length; i++) {
createSymlink(
path.join(process.cwd(), '..', directories[i]),
path.join(process.cwd(), 'assets', directories[i])
);
}
cb();
};
\ No newline at end of file
callback();
};
......@@ -10,34 +10,53 @@
* http://sailsjs.org/#/documentation/concepts/Logging
*/
var winston = require('winston');
var customLogger = new winston.Logger({
transports: [
new(winston.transports.File)({
level: 'debug',
filename: './logs/my_log_file.log'
}),
],
const winston = require('winston');
const path = require('path');
const customLogger = new winston.Logger({
level: 'silly'
});
module.exports.log = {
customLogger.add(winston.transports.File, {
name: 'silly-json',
silent: false,
colorize: false,
level: 'silly',
showLevel: true,
timestamp: true,
json: true,
tailable: true,
maxsize: 5 * 1024 * 1024, // 5 MegaByte
filename: path.resolve(__dirname, '..', 'logs', 'silly.json')
});
/***************************************************************************
* *
* Valid `level` configs: i.e. the minimum log level to capture with *
* sails.log.*() *
* *
* The order of precedence for log levels from lowest to highest is: *
* silly, verbose, info, debug, warn, error *
* *
* You may also set the level to "silent" to suppress all logs. *
* *
***************************************************************************/
customLogger.add(winston.transports.File, {
name: 'debug-json',
silent: false,
colorize: false,
level: 'debug',
showLevel: true,
timestamp: true,
json: true,
tailable: true,
maxsize: 5 * 1024 * 1024, // 5 MegaByte
filename: path.resolve(__dirname, '..', 'logs', 'debug.json')
});
// level: 'info'
// level: 'debug'
customLogger.add(winston.transports.File, {
name: 'error-json',
silent: false,
colorize: false,
level: 'error',
showLevel: true,
timestamp: true,
json: true,
tailable: true,
maxsize: 5 * 1024 * 1024, // 5 MegaByte
filename: path.resolve(__dirname, '..', 'logs', 'error.json')
});
colors: false, // To get clean logs without prefixes or color codings
custom: customLogger
module.exports.log = {
level: 'silly',
inspect: false,
custom: customLogger,
};
/* global sails */
var path = require('path');
var ASSETS_PATH = path.join(__dirname, '..', 'assets');
var UPLOAD_PATH = path.join(__dirname, '..', '..', 'upload');
module.exports.pictogram = {
//
// Administrator credentials
//
admin: {
email: 'amontejo@ujaen.es',
//password: '$2a$10$ZLdXN6OqROnE1eEC7D7mleqhwWDEemTswXhKh53qC5e3GEMm3Ch6q',
password: '$2a$10$omHwM62JNI5O1hbkfFGncOYwq3mZATmh8NnTQhN3f7JV3Q1/S9fGG'
},
serialSize: 10, // number of characters in generated serial numbers
pageLimit: 10 // number of elements per "page"
};
\ No newline at end of file
admin: {
email: 'amontejo@ujaen.es',
password: '$2a$10$omHwM62JNI5O1hbkfFGncOYwq3mZATmh8NnTQhN3f7JV3Q1/S9fGG'
},
serialSize: 10, // number of characters in generated serial numbers
pageLimit: 10, // number of elements per "page"
urls: {
/**
* Gets the public url of a supervisor avatar
* @param {String} filename filename of the avatar (stored in database)
* @return {String} Public url of user's avatar
*/
getSupervisorAvatarUrl: function (filename) {
return `/upload/supervisorAvatar/${filename}`;
},
/**
* Gets the public url of a student avatar
* @param {String} filename filename of the avatar (stored in database)
* @return {String} Public url of student's avatar
*/
getStudentAvatarUrl: function (filename) {
return `/upload/studentAvatar/${filename}`;
},
/**
* Gets the public url of a supervisor custom picto
* @param {String} filename filename of the custom picto (stored in database)
* @return {String} Public url of supervisor's custom picto
*/
getSupervisorCustomPictoUrl: function (filename) {
return `/upload/supervisorCustomPicto/${filename}`;
}
},
paths: {
public: ASSETS_PATH,
upload: UPLOAD_PATH,
defaultAvatarFileName: 'defaultAvatar.jpg',
supervisorAvatarDirectory: path.join(UPLOAD_PATH, 'supervisorAvatar'),
studentAvatarDirectory: path.join(UPLOAD_PATH, 'studentAvatar'),
supervisorCustomPictoDirectory: path.join(UPLOAD_PATH, 'supervisorCustomPicto'),
/**
* Get a random name used for uploaded file names
* @param {string} randomString String used for generating the name
* @param {number} randomNumber Number used for generating the name
* @return {string} Random name
*/
_getRandomFileName: function (randomString, randomNumber) {
var bcrypt = require('bcrypt-nodejs');
var randomDate = (new Date())
.getTime();
var randomFloat = Math.random();
return bcrypt.hashSync(
[randomString, randomDate, randomNumber, randomFloat].join(''),
bcrypt.genSaltSync()
)
.replace(/\W/g, '') + '.jpg';
},
/**
* Gets the supervisor avatar filename
* @param {supervisorId} supervisorId
* @return {string} fileName
*/
getSupervisorAvatarFileName: function (supervisorId) {
return sails.config.pictogram.paths._getRandomFileName(
'SUPERVISOR_AVATAR',
supervisorId
);
},
/**
* Gets the student avatar filename
* @param {studentId} studentId
* @return {string} fileName
*/
getStudentAvatarFileName: function (studentId) {
return sails.config.pictogram.paths._getRandomFileName(
'SUPERVISOR_AVATAR',
studentId
);
},
/**
* Gets the supervisor custom picto filename
* @param {supervisorId} supervisorId supervisorId
* @return {string} fileName
*/
getSupervisorCustomPictoFileName: function (supervisorId) {
return sails.config.pictogram.paths._getRandomFileName(
'SUPERVISOR_CUSTOM_PICTO',
supervisorId
);
}
}
};
......@@ -15,175 +15,111 @@
* For more information on configuring policies, check out:
* http://sailsjs.org/#/documentation/reference/sails.config/sails.config.policies.html
*/
module.exports.policies = {
// Sorted as they appear in routes.js
// Grouped by controller, sorted by HTTP method
/***************************************************************************
* *
* 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'],
},
SupervisorController: {
find: ['tokenAuth'],
findOne: ['tokenAuth'],
login: true,
create: true,
update: ['tokenAuth'],
activate: true,
list: ['tokenAuth', 'isAdmin'],
destroy: ['tokenAuth', 'isAdmin'],
students: ['tokenAuth'],
pictos: ['tokenAuth'],
upload: ['tokenAuth'],
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'],
ActionController: {
create: ['tokenAuth'],
createlist: ['tokenAuth']
},
AdminController: {
login: true
},
InstructionController: {
ws: ['tokenAuth'],
update: ['tokenAuth'],
create: ['tokenAuth'],
destroy: ['tokenAuth']
},
MethodController: {
update: ['tokenAuth'],
create: ['tokenAuth'],
newMethod: ['tokenAuth'],
save: ['tokenAuth'],
destroy: ['tokenAuth'],
destroyTemplate: ['tokenAuth'],
meta_methods: ['tokenAuth']
},
OfficeController: {
get: ['tokenAuth'],
findOne: ['tokenAuth'],
getAll: ['tokenAuth', 'isAdmin'],
create: ['tokenAuth', 'isAdmin'],
update: ['tokenAuth', 'isAdmin'],
destroy: ['tokenAuth', 'isAdmin'],
supervisors: ['tokenAuth', 'isAdmin'],
populate: ['tokenAuth']
get: ['tokenAuth'],
supervisors: ['tokenAuth', 'isAdmin']
},
PictoController: {
upload: ['tokenAuth'],
add_tag: ['tokenAuth'],
change_exp: ['tokenAuth'],
destroy: ['tokenAuth'],
del_tag: ['tokenAuth'],
categories: ['tokenAuth'],
fromcategory: ['tokenAuth']
},
ServerController: {
ping: true,
ping_session: ['tokenAuth']
},
StudentController: {
login: true,
find: ['tokenAuth'],
findOne: ['tokenAuth'],
getInfo: ['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
tutors: ['tokenAuth'],
link_supervisor: ['tokenAuth'],
unlink_supervisor: ['tokenAuth'],
link_device: ['tokenAuth'],
unlink_device: ['tokenAuth'],
subscribe: ['tokenAuth'], // websockets
unsubscribe: true, // websockets
vocabulary: true, // websockets
action: true, // websockets
config: true, // websockets
pictos: ['tokenAuth'],
add_picto: ['tokenAuth', 'isSupervisorOfStudent'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent'],
update_picto: ['tokenAuth', 'isSupervisorOfStudent'],
upload: ['tokenAuth'],
methods: ['tokenAuth'],
lasttries: ['tokenAuth'],
tries: ['tokenAuth'],
last_instruction: ['tokenAuth'],
ws: ['tokenAuth'],
actions_batch: ['tokenAuth'],
sqlquery: ['tokenAuth']
},
StuSupController:{
find: ['tokenAuth'],
findOne: ['tokenAuth'],
create: ['tokenAuth'],
destroy: ['tokenAuth']
},
PictoController:{
update: ['tokenAuth'],
update_picto: ['tokenAuth', 'isSupervisorOfStudent'],
login: true,
create: ['tokenAuth'],
destroy: ['tokenAuth'],
categories: ['tokenAuth'],
fromcategory: ['tokenAuth'],
find: ['tokenAuth'],
findOne: ['tokenAuth'],
add_tag: ['tokenAuth'],
del_tag: ['tokenAuth'],
change_exp: ['tokenAuth'],
upload: ['tokenAuth']
upload: ['tokenAuth'],
add_picto: ['tokenAuth', 'isSupervisorOfStudent'],
subscribe: ['tokenAuth'],
unsubscribe: true,
vocabulary: true,
action: true,
config: true,
actions_batch: ['tokenAuth'],
delete: ['tokenAuth'],
unlink_supervisor: ['tokenAuth'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent']
},
MethodController:{
create: ['tokenAuth'],
newMethod: ['tokenAuth'],
SupervisorController: {
list: ['tokenAuth', 'isAdmin'],
students: ['tokenAuth'],
pictos: ['tokenAuth'],
getByEmail: ['tokenAuth'],
update: ['tokenAuth'],
destroy: ['tokenAuth'],
find: ['tokenAuth'],
findOne: ['tokenAuth'],
meta_methods: ['tokenAuth'],
methods: ['tokenAuth'],
save: ['tokenAuth'],
destroyTemplate: ['tokenAuth'], // Add policie isOwner (supervisor.id == metamethod.id_sup)
create: true,
login: true,
activate: true,
upload: ['tokenAuth'],
subscribe: ['tokenAuth'],
unsubscribe: ['tokenAuth']
},
InstructionController:{
create: ['tokenAuth'],
TryController: {
update: ['tokenAuth'],
destroy: ['tokenAuth'],
find: ['tokenAuth'],
findOne: ['tokenAuth'],
ws: ['tokenAuth'],
create: ['tokenAuth']
},
WorkingSessionController:{
close: ['tokenAuth'],
create: ['tokenAuth'],
update: ['tokenAuth'],
destroy: ['tokenAuth'],
find: ['tokenAuth'],
findOne: ['tokenAuth'],
tries: ['tokenAuth'],
WorkingSessionController: {
per_year: ['tokenAuth'],
per_month: ['tokenAuth'],
tries: ['tokenAuth'],
},
TryController:{
create: ['tokenAuth'],
update: ['tokenAuth'],
},
ActionController:{
create: ['tokenAuth'],
createlist: ['tokenAuth'],
},
close: ['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']
// }
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