Commit 6655da93 by Pablo Molina

Solved #357, corrección de ficheros de configuración

Ahora los roles de ansible copian correctamente estos ficheros, los
cuales han sido excluidos del control de versiones.
parent ae99d383
Showing with 1737 additions and 1357 deletions
...@@ -31,12 +31,13 @@ sails/src/assets/app/bower_components ...@@ -31,12 +31,13 @@ sails/src/assets/app/bower_components
sails/src/assets/app/modules sails/src/assets/app/modules
sails/src/assets/app/css sails/src/assets/app/css
sails/src/assets/app/js sails/src/assets/app/js
sails/src/assets/scripts/config.js
# Other # # Other #
######### #########
sails/src/config/ssl/**/*.key
sails/src/config/ssl/**/*.crt
sails/src/config/local.js sails/src/config/local.js
sails/src/config/ssl
sails/src/config/logs
sails/src/node_modules sails/src/node_modules
sails/src/.tmp sails/src/.tmp
sails/.vagrant sails/.vagrant
......
...@@ -47,15 +47,20 @@ todo el repositorio, organizadas en 3 categorías: ...@@ -47,15 +47,20 @@ todo el repositorio, organizadas en 3 categorías:
# Aspecto del código # Aspecto del código
- En el fichero [.editorconfig](./.editorconfig) se encuentra el estilo - En el fichero [.editorconfig][3] se encuentra el estilo utilizado en el código (en cuento a
utilizado en el código (en cuento a espacios, codificación y demás). Existen espacios, codificación y demás). Existen numerosos plugins que pueden encontrarse en
numerosos plugins que pueden encontrarse en [editorconfig.org][4].
[editorconfig.org](http://EditorConfig.org). - En el fichero [/sails/src/.eslintrc][5] se encuentran los estilos referentes a los ficheros de
- En el fichero [/sails/src/.eslintrc](./sails/src/eslintrc) se encuentran los javascript. Tanto `eslint` como las configuraciones necesarias se encuentran en el fichero
estilos referentes a los ficheros de javascript. Tanto `eslint` como las [/sails/src/package.json][6], y se instalarán como dependencias de desarrollo.
configuraciones necesarias se encuentran en el fichero
[/sails/src/package.json](./sails/src/package.json), y se instalarán como > Puede configurarse eslint en el editor usado o ejecutando `eslint [ficheros]` desde
dependencias de desarrollo. > el directorio [/sails/src][7].
> Puede configurarse eslint en el editor usado o ejecutando [1]: https://pre.yottacode.com/
> `eslint [ficheros]` desde el directorio [/sails/src](./sails/src). [2]: https://dev.yottacode.com/
[3]: /softuno/pictogram/blob/master/.editorconfig
[4]: http://editorconfig.org
[5]: /softuno/pictogram/blob/master/sails/src/.eslintrc
[6]: /softuno/pictogram/blob/master/sails/src/package.json
[7]: /softuno/pictogram/tree/master/sails/src
...@@ -10,7 +10,7 @@ En cada directorio puede leerse la descripción de dicha parte, incluyendo confi ...@@ -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 utilidades. La estructura del repositorio en sí y forma de contribución se describe en
[el fichero de contribuciones][1]. [el fichero de contribuciones][1].
[1]: ./CONTRIBUTING.md [1]: /softuno/pictogram/blob/master/CONTRIBUTING.md
[2]: ./sails [2]: /softuno/pictogram/tree/master/sails
[3]: ./sails/src/assets/app [3]: /softuno/pictogram/tree/master/sails/src/assets/app
[4]: ./android/Pictogram [4]: /softuno/pictogram/tree/master/android/Pictogram
...@@ -13,12 +13,34 @@ ...@@ -13,12 +13,34 @@
### Opción A (producción): ejecución en la máquina local ### Opción A (producción): ejecución en la máquina local
1. Ejecutar [./install.sh][3]. 1. Descargar upload.zip y symbolstx.zip desde el servidor de Yottacode:
```
scp ec2-user@pre.yottacode.com:~/upload.zip .
scp ec2-user@pre.yottacode.com:~/symbolstx.zip .
unzip upload.zip
unzip symbolstx.zip
rm upload.zip
rm symbolstx.zip
```
2. Ejecutar [./install.sh][3].
3. Ejecutar [./bootstrap.sh][19] para lanzar el servidor.
4. Configurar los ficheros [local.js][20] y [config.js][21] generados si fuera necesario.
### Opción B (desarrollo): ejecución en una máquina virtual generada automáticamente ### Opción B (desarrollo): ejecución en una máquina virtual generada automáticamente
1. Instalar [virtualbox][1] y [vagrant][2]. 1. Descargar upload.zip y symbolstx.zip desde el servidor de Yottacode:
2. Ejecutar `vagrant up` desde este directorio. ```
scp ec2-user@pre.yottacode.com:~/upload.zip .
scp ec2-user@pre.yottacode.com:~/symbolstx.zip .
unzip upload.zip
unzip symbolstx.zip
rm upload.zip
rm symbolstx.zip
```
2. Instalar [virtualbox][1] y [vagrant][2].
3. Ejecutar `vagrant up` desde este directorio.
4. Configurar los ficheros [local.js][20] y [config.js][21] generados si fuera necesario.
Para esta acción debe entrarse en el interior de la máquina haciendo uso de `vagrant ssh`.
> **Importante**: el script utilizado creará un entorno para el servidor desde cero, por lo que > **Importante**: el script utilizado creará un entorno para el servidor desde cero, por lo que
> **pueden perderse los datos** almacenados por usuarios. > **pueden perderse los datos** almacenados por usuarios.
...@@ -33,15 +55,27 @@ Para lanzar el servidor hay que acceder al directorio [src][10] y ejecutar uno d ...@@ -33,15 +55,27 @@ Para lanzar el servidor hay que acceder al directorio [src][10] y ejecutar uno d
> Si se añade el parámetro --prod, se ejecutará en modo producción > Si se añade el parámetro --prod, se ejecutará en modo producción
> El servidor se ejecutará en [localhost:1337/app](http://localhost:1337/app) > La opción `--prod` indica que sails se ejecutará en modo producción
>
> El servidor se ejecutará en [localhost][20]
[1]: https://www.virtualbox.org/ [1]: https://www.virtualbox.org/
[2]: https://www.vagrantup.com/ [2]: https://www.vagrantup.com/
[3]: ./install.sh [3]: /softuno/pictogram/blob/master/sails/install.sh
[4]: ./roles/nodejs [4]: /softuno/pictogram/blob/master/sails/roles/nodejs/README.md
[5]: ./roles/mysql [5]: /softuno/pictogram/blob/master/sails/roles/mysql/README.md
[6]: ./roles/database [6]: /softuno/pictogram/blob/master/sails/roles/database/README.md
[7]: ./roles/webapp [7]: /softuno/pictogram/blob/master/sails/roles/webapp/README.md
[8]: ./roles/server [8]: /softuno/pictogram/blob/master/sails/roles/server/README.md
[9]: https://www.ansible.com/ [9]: https://www.ansible.com/
[10]: ./src [10]: /softuno/pictogram/blob/master/sails/src/README.md
[11]: /softuno/pictogram/blob/master/sails/src/Gruntfile.js
[12]: /softuno/pictogram/blob/master/sails/src/tasks/README.md
[13]: /softuno/pictogram/blob/master/sails/src/tasks/config/README.md
[14]: /softuno/pictogram/blob/master/sails/src/tasks/register/README.md
[15]: /softuno/pictogram/blob/master/sails/src/tasks/register/default.js
[16]: /softuno/pictogram/blob/master/sails/src/tasks/register/prod.js
[17]: /softuno/pictogram/blob/master/sails/src/tasks/register/build.js
[18]: /softuno/pictogram/blob/master/sails/src/tasks/register/buildProd.js
[19]: /softuno/pictogram/blob/master/sails/bootstrap.sh
[20]: https://localhost:1337/app
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
- [API del servidor][2] - [API del servidor][2]
- [Documento de estados y reglas de integridad (documento docx)][3] - [Documento de estados y reglas de integridad (documento docx)][3]
[1]: ./assets/database-er-diagram.png [1]: /softuno/pictogram/blob/master/sails/doc/assets/database-er-diagram.png
[2]: ./api.md [2]: /softuno/pictogram/blob/master/sails/doc/api.md
[3]: ./assets/states-and-database-integrity.docx [3]: /softuno/pictogram/blob/master/sails/doc/assets/states-and-database-integrity.docx
...@@ -81,7 +81,7 @@ políticas de acceso se encuentran implementadas y documentadas en los siguiente ...@@ -81,7 +81,7 @@ políticas de acceso se encuentran implementadas y documentadas en los siguiente
> directorio [api/policies][4]. > directorio [api/policies][4].
> 2. Si un método no se encuentra en este fichero no se podrá acceder a él. > 2. Si un método no se encuentra en este fichero no se podrá acceder a él.
[1]: ../src/config/routes.js [1]: /softuno/pictogram/blob/master/sails/src/config/routes.js
[2]: ../src/api/controllers/ [2]: /softuno/pictogram/tree/master/sails/src/api/controllers
[3]: ../src/config/policies.js [3]: /softuno/pictogram/blob/master/sails/src/config/policies.js
[4]: ../src/api/policies/ [4]: /softuno/pictogram/tree/master/sails/src/api/policies
...@@ -20,13 +20,13 @@ Los ficheros SQL que importará este rol son los siguientes: ...@@ -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-caja][9] contiene datos para el test de CAJA.
- [test-autismojaen][10] añade los datos para el test de autismojaen. - [test-autismojaen][10] añade los datos para el test de autismojaen.
[1]: ./files/init.sql [1]: /softuno/pictogram/blob/master/sails/roles/database/files/init.sql
[2]: ./files/init-ignoresymbolstix.sql [2]: /softuno/pictogram/blob/master/sails/roles/database/files/init-ignoresymbolstix.sql
[3]: ./files/pictodb-schema.sql [3]: /softuno/pictogram/blob/master/sails/roles/database/files/pictodb-schema.sql
[4]: ./files/pictodb-data.sql [4]: /softuno/pictogram/blob/master/sails/roles/database/files/pictodb-data.sql
[5]: ./files/symbolstx-categories.sql [5]: /softuno/pictogram/blob/master/sails/roles/database/files/symbolstx-categories.sql
[6]: ./files/symbolstx-metadata.sql [6]: /softuno/pictogram/blob/master/sails/roles/database/files/symbolstx-metadata.sql
[7]: ./files/triggers-enrolments-integrity-constraints.sql [7]: /softuno/pictogram/blob/master/sails/roles/database/files/triggers-enrolments-integrity-constraints.sql
[8]: ./files/triggers-sessions-integrity-constraints.sql [8]: /softuno/pictogram/blob/master/sails/roles/database/files/triggers-sessions-integrity-constraints.sql
[9]: ./files/test-autismojaen.sql [9]: /softuno/pictogram/blob/master/sails/roles/database/files/test-autismojaen.sql
[10]: ./files/test-caja.sql [10]: /softuno/pictogram/blob/master/sails/roles/database/files/test-caja.sql
...@@ -15,13 +15,13 @@ SET foreign_key_checks=0; ...@@ -15,13 +15,13 @@ SET foreign_key_checks=0;
-- Default supervisor (ID -1) for PCB autonomous mode -- 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 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 -- 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); (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` ...@@ -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 (186, 325, 54270, 2, 6, NULL), -- Change.turn on
(187, 328, 54270, 2, 7, NULL), -- Change.turn off (187, 328, 54270, 2, 7, NULL), -- Change.turn off
(188, 52670, 52736, 4, 5, NULL), -- Drinks.milk (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 (195, 4872,4724, 1, 3, NULL), -- Body parts.head
(196, 50694,4724, 1, 4, NULL), -- Body parts.eye (196, 50694,4724, 1, 4, NULL), -- Body parts.eye
(197, 4787 ,4724, 1, 5, NULL), -- Body parts.ear (197, 4787 ,4724, 1, 5, NULL), -- Body parts.ear
......
...@@ -30,7 +30,6 @@ CREATE TABLE IF NOT EXISTS `action` ( ...@@ -30,7 +30,6 @@ CREATE TABLE IF NOT EXISTS `action` (
`timestamp` timestamp DEFAULT CURRENT_TIMESTAMP, `timestamp` timestamp DEFAULT CURRENT_TIMESTAMP,
`id_sup` int(11) DEFAULT NULL, `id_sup` int(11) DEFAULT NULL,
`id_stu` int(11) NOT NULL, `id_stu` int(11) NOT NULL,
`id_dev` int(11) DEFAULT NULL,
`id_try` int(11) DEFAULT NULL, `id_try` int(11) DEFAULT NULL,
`description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'serialization of properties of the picto at the time of the action', `description` varchar(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, `gps_lat` float DEFAULT NULL,
...@@ -41,7 +40,6 @@ CREATE TABLE IF NOT EXISTS `action` ( ...@@ -41,7 +40,6 @@ CREATE TABLE IF NOT EXISTS `action` (
UNIQUE (id_stu,timestamp), UNIQUE (id_stu,timestamp),
KEY `fk_sup_act` (`id_sup`), KEY `fk_sup_act` (`id_sup`),
KEY `fk_stu_act` (`id_stu`), KEY `fk_stu_act` (`id_stu`),
KEY `id_dev` (`id_dev`),
KEY `id_try` (`id_try`) KEY `id_try` (`id_try`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
...@@ -336,7 +334,7 @@ CREATE TABLE IF NOT EXISTS `student` ( ...@@ -336,7 +334,7 @@ CREATE TABLE IF NOT EXISTS `student` (
`birthdate` date NOT NULL, `birthdate` date NOT NULL,
`gender` char(1) COLLATE utf8_unicode_ci NOT NULL, `gender` char(1) COLLATE utf8_unicode_ci NOT NULL,
`country` char(2) COLLATE utf8_unicode_ci NOT NULL, `country` char(2) COLLATE utf8_unicode_ci NOT NULL,
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT '/app/img/default.jpg', `pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'defaultAvatar.jpg',
`notes` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL, `notes` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL, `lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`attributes` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Attributes describing student along with his/her configuration', `attributes` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Attributes describing student along with his/her configuration',
...@@ -390,7 +388,7 @@ CREATE TABLE IF NOT EXISTS `supervisor` ( ...@@ -390,7 +388,7 @@ CREATE TABLE IF NOT EXISTS `supervisor` (
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`surname` varchar(60) COLLATE utf8_unicode_ci NOT NULL, `surname` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`gender` char(1) 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, `address` varchar(180) COLLATE utf8_unicode_ci DEFAULT NULL,
`country` varchar(2) COLLATE utf8_unicode_ci DEFAULT NULL, `country` varchar(2) COLLATE utf8_unicode_ci DEFAULT NULL,
`email` varchar(80) COLLATE utf8_unicode_ci NOT NULL, `email` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
......
// template file for sails/src/config/local.js
/** /**
* Local environment settings * Local environment settings
* *
...@@ -29,59 +27,49 @@ ...@@ -29,59 +27,49 @@
* http://sailsjs.org/#!/documentation/anatomy/myApp/config/local.js.html * http://sailsjs.org/#!/documentation/anatomy/myApp/config/local.js.html
*/ */
module.exports = { const path = require('path');
const fs = require('fs');
/***************************************************************************
* 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: *
***************************************************************************/
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: { ssl: {
ca: require('fs').readFileSync(__dirname + '/ssl/goddady/gd.yottacode.com.bundle.crt'), ca: fs.readFileSync(path.join(__dirname, 'ssl', 'bundle.crt')),
key: require('fs').readFileSync(__dirname + '/ssl/goddady/gd.yottacode.com.key'), key: fs.readFileSync(path.join(__dirname, 'ssl', 'key.key')),
cert: require('fs').readFileSync(__dirname + '/ssl/goddady/gd.yottacode.com.crt') cert: fs.readFileSync(path.join(__dirname, 'ssl', 'cert.crt')),
}, },
/*************************************************************************** /**
* The `port` setting determines which TCP port your app will be * * The `port` setting determines which TCP port your app will be
* deployed on. * * deployed on.
* * *
* Ports are a transport-layer concept designed to allow many different * * By default, if it's set, Sails uses the `PORT` environment variable.
* networking applications run at the same time on a single computer. * * Otherwise it falls back to port 1337.
* More about ports: * *
* http://en.wikipedia.org/wiki/Port_(computer_networking) * * In env/production.js, you'll probably want to change this setting
* * * to 80 (http://) or 443 (https://) if you have an SSL certificate
* By default, if it's set, Sails uses the `PORT` environment variable. * */
* Otherwise it falls back to port 1337. * port: process.env.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'
/*
* 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',
}; };
...@@ -9,10 +9,11 @@ ...@@ -9,10 +9,11 @@
path: "{{ server_path }}/logs" path: "{{ server_path }}/logs"
state: directory state: directory
- name: Create log file - name: Copy local.js file
file: file:
path: "{{ server_path }}/{{ server_relative_path }}/logs/my_log_file.log" src: "{{ server_path }}/roles/server/files/local.js"
state: touch dest: "{{ server_path }}/config/local.js"
force: no
- name: Install sails globaly - name: Install sails globaly
npm: npm:
......
/* global angular */
angular.module('dashboardConfig', []).constant('config', {
backend: 'https://localhost:1337',
});
...@@ -11,5 +11,11 @@ ...@@ -11,5 +11,11 @@
state: present state: present
global: yes global: yes
- name: Copy config.js file
file:
src: "{{ server_path }}/roles/files/config.js"
dest: "{{ server_path }}/src/assets/scripts/config.js"
force: no
- name: Install bower dependencies - name: Install bower dependencies
bower: path="{{ webapp_path }}" bower: path="{{ webapp_path }}"
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"object-shorthand": 0, "object-shorthand": 0,
"prefer-arrow-callback": 0, "prefer-arrow-callback": 0,
"prefer-template": 0, "prefer-template": 0,
"strict": 0 "strict": 0,
"prefer-rest-params": 0
} }
} }
...@@ -5,6 +5,35 @@ ...@@ -5,6 +5,35 @@
*/ */
module.exports = { 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) { create: function(req, res) {
var params = req.allParams(); var params = req.allParams();
...@@ -35,8 +64,8 @@ module.exports = { ...@@ -35,8 +64,8 @@ module.exports = {
if(created) { if(created) {
StuOpenTry.findOne({id_stu : params.student}).exec(function(err, data){ StuOpenTry.findOne({id_stu : params.student}).exec(function(err, data){
if(err || !data){ if(err || !data){
sails.log.error("Error finding try for student "+params.student+ ' when creating action '+type); sails.log.error("Error finding try for student "+ params.student + ' when creating action '+ params.type);
return res.json(500, {error: 'Action '+type+' not created'}); 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 }); return res.json(200,{open_try: data.openTry });
......
...@@ -4,11 +4,8 @@ ...@@ -4,11 +4,8 @@
*/ */
module.exports = { module.exports = {
// // @TODO ¿?¿?
// login action login: function (req, res) {
// expected params in post body: email, password
//
login: function (req, res) {
var bcrypt = require('bcrypt-nodejs'); var bcrypt = require('bcrypt-nodejs');
var email = req.body.email; var email = req.body.email;
var password = req.body.password; var password = req.body.password;
......
// @TODO 357 /* global Instruction, Method */
/**
* InstructionController manages the requests related to the Instruction model.
* Read it's documentation for further information.
* @type {Object}
*/
module.exports = { module.exports = {
/**
* 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) { ws: function(req, res) {
if (!req.params.id_ins) { if (!req.params.id_ins) {
return res.json(500, {error: "No instruction defined"}); return res.json(500, {error: "No instruction defined"});
......
/* global sails, Method, MetaMethod */
/** /**
* MethodController * MethodController
* *
...@@ -7,10 +9,29 @@ ...@@ -7,10 +9,29 @@
module.exports = { module.exports = {
// /**
// create action * Creates a new method for a student using a template (metamethod)
// adds a method * @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) { create: function(req, res) {
var params = req.allParams(); var params = req.allParams();
...@@ -30,10 +51,9 @@ module.exports = { ...@@ -30,10 +51,9 @@ module.exports = {
Method.create({ name: mmethod.name, description: mmethod.description, student: params.id_stu}).exec(function (err, created) { Method.create({ name: mmethod.name, description: mmethod.description, student: params.id_stu}).exec(function (err, created) {
if (err) { if (err) {
sails.log.debug("Creating new method: " + 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) { if (created) {
// Find meta instructions associated to meta method // Find meta instructions associated to meta method
MetaInstruction.find({id_met: params.id_mmethod}).exec(function(err, minstructions) { MetaInstruction.find({id_met: params.id_mmethod}).exec(function(err, minstructions) {
...@@ -43,8 +63,8 @@ module.exports = { ...@@ -43,8 +63,8 @@ module.exports = {
} }
sails.log.debug("Meta instructions found: " + JSON.stringify(minstructions)); sails.log.debug("Meta instructions found: " + JSON.stringify(minstructions));
console.log("Meta instructions found: " + JSON.stringify(minstructions));
var l_ins = []; var l_ins = [];
// Every meta instruction is going to be created in 'Instruction' // Every meta instruction is going to be created in 'Instruction'
...@@ -54,8 +74,8 @@ module.exports = { ...@@ -54,8 +74,8 @@ module.exports = {
sails.log.debug("Loop adding meta instruction: " + mins.name + " to method " + created.id); sails.log.debug("Loop adding meta instruction: " + mins.name + " to method " + created.id);
Instruction.create({ Instruction.create({
method: created.id, method: created.id,
name: mins.name, name: mins.name,
objective: mins.objective objective: mins.objective
}).exec(function(err, added){ }).exec(function(err, added){
...@@ -63,21 +83,21 @@ module.exports = { ...@@ -63,21 +83,21 @@ module.exports = {
if(added){ if(added){
l_ins.push(added); l_ins.push(added);
sails.log.debug("Instruction " + added.name + " added to method " + created.id); sails.log.debug("Instruction " + added.name + " added to method " + created.id);
console.log("Instruction " + added.name + " added to method " + created.id);
} }
callback(); callback();
}); });
// Finish function when each callback is done // Finish function when each callback is done
// Optionaly it can be passed and err parameter // Optionaly it can be passed and err parameter
}, function(err){ }, function(err){
if( err ) { if( err ) {
// One of the iterations produced an error. // One of the iterations produced an error.
// All processing will now stop. // All processing will now stop.
console.log('An error ocurred with a metainstruction');
} else { } else {
console.log('All metainstructions have been processed successfully');
return res.json({ return res.json({
"name": created.name, "name": created.name,
"description": created.description, "description": created.description,
...@@ -89,55 +109,75 @@ module.exports = { ...@@ -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 // FERNANDO: avoid method name duplicates
save: function(req, res){ save: function(req, res){
...@@ -145,14 +185,14 @@ module.exports = { ...@@ -145,14 +185,14 @@ module.exports = {
if (!params.id_met) return res.json(500, {error: "No method defined"}); if (!params.id_met) return res.json(500, {error: "No method defined"});
if (!params.id_sup) return res.json(500, {error: "No supervisor defined"}); if (!params.id_sup) return res.json(500, {error: "No supervisor defined"});
Method.findOne(params.id_met).populate('instructions').exec(function(err, method) { Method.findOne(params.id_met).populate('instructions').exec(function(err, method) {
if (err){ if (err){
sails.log.debug("Find Method: " + err); sails.log.debug("Find Method: " + err);
return res.json(500, {error: "No method found"}); // empty array return res.json(500, {error: "No method found"}); // empty array
} }
console.log("Method found:" + JSON.stringify(method));
MetaMethod.create({ MetaMethod.create({
"name": method.name, "name": method.name,
...@@ -172,30 +212,29 @@ module.exports = { ...@@ -172,30 +212,29 @@ module.exports = {
sails.log.debug("Loop adding meta instruction: " + mins.name + " from method " + createdMethod.id); sails.log.debug("Loop adding meta instruction: " + mins.name + " from method " + createdMethod.id);
MetaInstruction.create({ MetaInstruction.create({
id_met: createdMethod.id, id_met: createdMethod.id,
name: mins.name, name: mins.name,
objective: mins.objective objective: mins.objective
}).exec(function(err, added){ }).exec(function(err, added){
if(err) sails.log.debug("MetaInstruction.create: " + err); if(err) sails.log.debug("MetaInstruction.create: " + err);
if(added){ if(added){
sails.log.debug("MetaInstruction " + added.name + " added from method " + createdMethod.id); sails.log.debug("MetaInstruction " + added.name + " added from method " + createdMethod.id);
console.log("MetaInstruction " + added.name + " added from method " + createdMethod.id);
} }
callback(); callback();
}); });
// Finish function when each callback is done // Finish function when each callback is done
// Optionaly it can be passed and err parameter // Optionaly it can be passed and err parameter
}, function(err){ }, function(err){
if( err ) { if( err ) {
// One of the iterations produced an error. // One of the iterations produced an error.
// All processing will now stop. // All processing will now stop.
console.log('An error ocurred with a meta instruction');
} else { } else {
console.log('All meta instructions have been processed successfully');
return res.json(createdMethod);
return res.json(createdMethod);
} }
}); });
...@@ -219,24 +258,24 @@ module.exports = { ...@@ -219,24 +258,24 @@ module.exports = {
if (err || !instructions){ if (err || !instructions){
sails.log.debug("Destroy Instructions: " + err); sails.log.debug("Destroy Instructions: " + err);
return res.json(500, {error: "Cannot delete instructions"}); return res.json(500, {error: "Cannot delete instructions"});
} }
// Destroy method // Destroy method
Method.destroy({ id: params.id }).exec(function(err, 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){ if (err || !method){
sails.log.debug("Destroy Method: " + err); 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); return res.json(method);
}); });
}); });
}, },
...@@ -254,25 +293,24 @@ module.exports = { ...@@ -254,25 +293,24 @@ module.exports = {
if (err || !metainstructions){ if (err || !metainstructions){
sails.log.debug("Destroy MetaInstructions: " + err); 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 // Destroy method
MetaMethod.destroy({ id: params.id_mmet }).exec(function(err, metamethod) { 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){ if (err || !metamethod){
sails.log.debug("Destroy MetaMethod: " + err); 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); return res.json(metamethod);
}); });
}); });
} }
};
};
/* global Office */
/** /**
* OfficeController * OfficeController
* *
* @description :: Server-side logic for managing offices * @description :: Server-side logic for managing offices
* @help :: See http://links.sailsjs.org/docs/controllers * @help :: See http://links.sailsjs.org/docs/controllers
*/ */
module.exports = { module.exports = {
/** /**
* `OfficeController.create()` * Return an Office found by id
*/ * @param {request} req {} (with officeId as url parameter)
// @TODO 357 * @param {response} res
create: function (req, res) { * {
* supervisors: [Empty array],
var params = req.params.all(); * admin: {
// Search if the email is in the BDD (must be unique for Office) * "name": "John"
Office.findOneByEmail(params.email).exec(function (err, office) { * "surname": "Doe"
if (err) * "gender": "F/M"
return res.json(500, { error: 'DB error' }); * "password": "1234"
* "pic": "url/to/photo.jpg"
if (office) * "address": "Nice street"
return res.json(400, {error: 'Email already exists in DB'}); * "country": "ES/UK/..."
* "email": "john@doe.com"
Office.create(params).exec(function (err, created) { * "phone": "+123456789"
if (err) * "lang": "ES/EN/..."
return res.json(500, {error: 'Office not created'}); * "tts_engine": "IVONA Text-to-Speech HQ"
* },
if (created){ * id: 3123,
// If the admin is specified in the office * name: 'First Office in the World',
// update the office for the admin too * address: 'The World, Earth',
if(created.admin){ * email: 'the_office@world.com',
Supervisor.update({id:created.admin},{office:created.id}).exec(function (err, updated) { * phone1: '+34 123 123 123',
if(err) console.log("Error updating office of supervisor") * phone2: null,
if(updated) console.log(updated); * lang: 'es-es',
}); * contactPerson: 'John Doe'
} * }
return res.json({office: created});
}
});
});
},
/**
* `OfficeController.update()` by sails default
*/
/**
* `OfficeController.destroy()` by sails default
*/
/**
* `OfficeController.get()`
* Returns the office with the given id
*/ */
get: function (req, res) { get: function (req, res) {
if (!req.params.id) Office.findOne({ id: req.params.id }).populate('admin').then(function (office) {
return res.json(500, {err: "Office ID must be specified"}); if (office) {
Office.findOne(req.params.id).populate('admin').exec(function(err, office) { res.ok(office);
if (err) return res.json(500, {err: err.details}); } else {
if (office) res.notFound();
return res.json(200, office); }
return res.json({error: "Office not found"}); })
.catch(function () {
res.badRequest();
}); });
}, },
/** /**
* `OfficeController.getAll()` * Return all offices
* Returns all possible 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) { getAll: function (req, res) {
Office.find().populate('admin').exec(function(err, offices) { Office.find().populate('admin').then(function (offices) {
if (err) return res.json(500, {err: err.details}); res.ok(offices);
if (offices) })
return res.json(200, offices); .catch(function () {
return res.json({error: "Offices not found"}); res.serverError();
}); });
}, },
/** /**
* `OfficeController.supervisors()` * Get all supervisors from an office
* Returns all supervisors of 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) { supervisors: function (req, res) {
if (!req.params.id) Office
return res.json(500, {err: "Office ID must be specified"}); .findOne({ id: req.params.id })
.populate('supervisors')
Office.findOne(req.params.id).populate('supervisors').exec(function(err, off) { .then(function (office) {
if (err) if (office) {
return res.json(500, {error: 'DB error'}); res.ok(office.supervisors);
return res.json(200, off.supervisors); } else {
res.notFound();
}
})
.catch(function () {
res.badRequest();
}); });
}, },
}; };
// @TODO 357
module.exports = {
login: function (req, res) {
res.view('login');
},
signin: function (req, res) {
res.view('signin');
}
};
...@@ -4,21 +4,23 @@ ...@@ -4,21 +4,23 @@
* @description :: Server-side logic for managing server * @description :: Server-side logic for managing server
* @help :: See http://links.sailsjs.org/docs/controllers * @help :: See http://links.sailsjs.org/docs/controllers
*/ */
module.exports = { module.exports = {
// /**
// ping action * Returns ok (checking if the server is online)
// This action simply return OK to ensure connection is up * @param {request} req {}
// * @param {response} res {}
ping: function(req, res) { */
return res.json(200, {result: "OK"}); ping: function (req, res) {
}, res.ok();
},
// /**
// ping_session action * Returns ok (checking if the server is online).
// Same as 'ping' but token is required (see config/policies.js) * This method needs a previous authentication (check policies.js)
// * @param {request} req {}
ping_session: function(req, res) { * @param {response} res {}
return res.json(200, {result: "OK"}); */
} ping_session: function (req, res) {
res.ok();
}
}; };
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* information to send. * information to send.
* @type {Object} * @type {Object}
*/ */
module.exports = function eventsHook (sails) { module.exports = function eventsHook(sails) {
return { return {
/** /**
* Speacial Function wrapping sails.sockets.broadcast that uses a room * Speacial Function wrapping sails.sockets.broadcast that uses a room
...@@ -38,12 +38,14 @@ module.exports = function eventsHook (sails) { ...@@ -38,12 +38,14 @@ module.exports = function eventsHook (sails) {
rooms = [rooms]; rooms = [rooms];
} }
sails.log.debug('"websocketEvent":', JSON.stringify({ // Ensure data is an object
rooms: rooms, if (!(typeof event.data === 'object' && event.data !== null)) {
name: event.name, event.data = {};
data: event.data, }
socketToOmit: socketToOmit ? socketToOmit.id : undefined
})); sails.log.debug("Websocket event '%s' with data '%j' sent to '%s'",
event.name, event.data, rooms.join(', ')
);
sails.sockets.broadcast( sails.sockets.broadcast(
rooms, rooms,
...@@ -70,6 +72,22 @@ module.exports = function eventsHook (sails) { ...@@ -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 * Someone has subscribed/unsubscribed to/from a room. The number
* of subscribes is sent * of subscribes is sent
* @param {number} subscriberCount Number of subscribers * @param {number} subscriberCount Number of subscribers
......
...@@ -23,11 +23,23 @@ module.exports = { ...@@ -23,11 +23,23 @@ module.exports = {
}, },
type: { type: {
required: true, required: true,
type: "string", type: 'string',
size: 20 enum: [
'Add',
'Select',
'Delete',
'Show',
'Unshow',
'Pause',
'tryinit',
'tryend',
'initsession',
'endsession',
'pausesession',
'resumesession'
]
}, },
timestamp: { timestamp: {
//required: true,
type: "datetime" type: "datetime"
}, },
supervisor: { // FK de Supervisor. 1 a N supervisor: { // FK de Supervisor. 1 a N
......
/* global sails */
/** /**
* picto.js * picto.js
* *
* @description :: TODO: Write a short summary of how this model works and what it represents here. * @description :: TODO: Write a short summary of how this model works and what it represents here.
* @docs :: http://sailsjs.org/#!documentation/models * @docs :: http://sailsjs.org/#!documentation/models
*/ */
module.exports = { module.exports = {
tableName : 'picto', tableName: 'picto',
migrate : 'safe', migrate: 'safe',
schema : true, schema: true,
autoPK : false, autoPK: false,
autoCreatedAt : false, autoCreatedAt: false,
autoUpdatedAt : false, autoUpdatedAt: false,
attributes: { attributes: {
id: { id: {
type: "integer", type: 'integer',
autoIncrement: true, autoIncrement: true,
primaryKey: true, primaryKey: true,
unique: true unique: true
}, },
uri: { uri: {
required: true, required: true,
type: "string", type: 'string',
size: 250 size: 250
}, },
source: { // FK de Source. 1 source to N pictos source: { // 1 Source to N Pictos
columnName: "id_src", columnName: 'id_src',
required: true, required: true,
type: "integer", type: 'integer',
model: "Source" model: 'Source'
}, },
owner: { // FK de Supervisor. 1 a N owner: { // 1 Supervisor to N Owners
columnName: "id_owner", columnName: 'id_owner',
type: "integer", type: 'integer',
required: false, required: false,
model: "Supervisor" model: 'Supervisor'
}, },
category:{ category: {
columnName: "id_cat", columnName: 'id_cat',
type: "integer" type: 'integer'
}, },
// Relación con Expression. [1 Picto to N Expression] expressions: { // 1 Picto to N PictoExp
expressions: { collection: 'PictoExp',
collection: "PictoExp", via: 'picto'
via: "picto"
}, },
// Relación con PictoTag. [1 Picto to N PictoTag] tags: { // 1 Picto to N PictoTag
tags: { collection: 'PictoTag',
collection: "PictoTag", via: 'picto'
via: "picto"
}, },
tagsSup: { // tags created by supervisors tagsSup: {
collection: "PictoTagSup", collection: 'PictoTagSup',
via: "picto" via: 'picto'
}, },
// Relación con PictoAcl. [1 Picto to N PictoAcl] pictoAcls: { // 1 Picto to N PictoAcl
pictoAcls:{ collection: 'PictoAcl',
collection: "PictoAcl", via: 'picto'
via: "picto"
}, },
stusPicto: { stusPicto: {
collection: 'StuPicto', collection: 'StuPicto',
...@@ -66,44 +65,11 @@ module.exports = { ...@@ -66,44 +65,11 @@ module.exports = {
} }
}, },
// toJSON: function () {
// Returns all categories for the given supercategory with the expression in the supervisor language var picto = this.toObject();
// if (picto.owner !== null) {
categories: function(id_sup, id_cat, callback) { picto.uri = sails.config.pictogram.urls.getSupervisorCustomPictoUrl(picto.uri);
Supervisor.findOne(id_sup).exec(function(err, sup) { }
if (err) { return picto;
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);
});
});
} }
}; };
\ No newline at end of file
/** /**
* StuPicto.js * StuPicto.js
* *
* @description :: This model represents the collection of pictos for a student, * @description :: This model represents the collection of pictos for a student,
* with the properties associated to it * with the properties associated to it
* @docs :: http://sailsjs.org/#!documentation/models * @docs :: http://sailsjs.org/#!documentation/models
*/ */
...@@ -13,7 +13,7 @@ module.exports = { ...@@ -13,7 +13,7 @@ module.exports = {
autoPK : false, autoPK : false,
autoCreatedAt : false, autoCreatedAt : false,
autoUpdatedAt : false, autoUpdatedAt : false,
attributes: { attributes: {
id: { id: {
type: "integer", type: "integer",
...@@ -54,7 +54,7 @@ module.exports = { ...@@ -54,7 +54,7 @@ module.exports = {
"id_cat" : null, "id_cat" : null,
"coord_x" : null, "coord_x" : null,
"coord_y" : null, "coord_y" : null,
"status": "enabled" "status": "enabled"
}; };
*/ */
...@@ -79,8 +79,6 @@ module.exports = { ...@@ -79,8 +79,6 @@ module.exports = {
if(attrs.attributes.color !== undefined) if(attrs.attributes.color !== undefined)
var previous_color = attrs.attributes.color; var previous_color = attrs.attributes.color;
console.log(configuration.toString());
attrs.attributes = JSON.parse("{" + configuration.toString() + "}"); attrs.attributes = JSON.parse("{" + configuration.toString() + "}");
// And we store them (If the picto is from picto_core, it has defined the coords) // And we store them (If the picto is from picto_core, it has defined the coords)
...@@ -98,9 +96,8 @@ module.exports = { ...@@ -98,9 +96,8 @@ module.exports = {
if(previous_color !== undefined) if(previous_color !== undefined)
attrs.attributes.color = previous_color; attrs.attributes.color = previous_color;
//console.log(attrs.attributes);
next(); next();
}); });
} }
} }
\ No newline at end of file
/* global sails */
/** /**
* student.js * student.js
* *
...@@ -94,14 +96,11 @@ module.exports = { ...@@ -94,14 +96,11 @@ module.exports = {
via: "student" via: "student"
}, },
// toJSON: function () {
// JSON limitations var student = this.toObject();
// student.pic = sails.config.pictogram.urls.getStudentAvatarUrl(student.pic);
toJSON: function() { delete student.password;
var obj = this.toObject(); return student;
// avoid sending this fields
delete obj.password;
return obj;
}, },
}, },
...@@ -172,7 +171,6 @@ module.exports = { ...@@ -172,7 +171,6 @@ module.exports = {
async.eachSeries(stuSups, async.eachSeries(stuSups,
function(stuSup, next) { function(stuSup, next) {
delete stuSup.supervisor.password;
l.push(stuSup.supervisor); l.push(stuSup.supervisor);
next(); next();
}, },
...@@ -197,7 +195,6 @@ module.exports = { ...@@ -197,7 +195,6 @@ module.exports = {
function(stuSup, next) { function(stuSup, next) {
// stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor // stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor
if (stuSup.supervisor && stuSup.supervisor.office && stuSup.supervisor.id > 0) { if (stuSup.supervisor && stuSup.supervisor.office && stuSup.supervisor.id > 0) {
delete stuSup.supervisor.password;
l.push(stuSup.supervisor); l.push(stuSup.supervisor);
} }
next(); next();
...@@ -224,7 +221,6 @@ module.exports = { ...@@ -224,7 +221,6 @@ module.exports = {
function(stuSup, next) { function(stuSup, next) {
// stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor // stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor
if (stuSup.supervisor && !stuSup.supervisor.office && stuSup.supervisor.id > 0) { if (stuSup.supervisor && !stuSup.supervisor.office && stuSup.supervisor.id > 0) {
delete stuSup.supervisor.password;
l.push(stuSup.supervisor); l.push(stuSup.supervisor);
} }
next(); next();
...@@ -347,21 +343,6 @@ module.exports = { ...@@ -347,21 +343,6 @@ module.exports = {
}); });
}, },
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);
}
});
},
// //
// Model hook for storing encrypted password when updating an account // Model hook for storing encrypted password when updating an account
// and to check that the user new username is not already registered // and to check that the user new username is not already registered
......
/* global Supervisor, sails */
/** /**
* supervisor.js * supervisor.js
* *
...@@ -5,18 +7,6 @@ ...@@ -5,18 +7,6 @@
* @docs :: http://sailsjs.org/#!documentation/models * @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 = { module.exports = {
connection : 'localMysql', connection : 'localMysql',
tableName : 'supervisor', tableName : 'supervisor',
...@@ -128,19 +118,19 @@ module.exports = { ...@@ -128,19 +118,19 @@ module.exports = {
// //
// JSON limitations // JSON limitations
// //
toJSON: function() { toJSON: function () {
var obj = this.toObject(); var supervisor = this.toObject();
// avoid sending this fields supervisor.pic = sails.config.pictogram.urls.getSupervisorAvatarUrl(supervisor.pic);
delete obj.password; delete supervisor.password;
return obj; return supervisor;
}, },
// //
// sendMail // sendMail
// adds a new entry into pending_registration // adds a new entry into pending_registration
// and send an email confirmation to the user // and send an email confirmation to the user
sendMail: function() { 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'); var nodemailer = require('nodemailer');
...@@ -184,81 +174,79 @@ module.exports = { ...@@ -184,81 +174,79 @@ module.exports = {
// Model hook for storing encrypted password when adding a new account // Model hook for storing encrypted password when adding a new account
// and to check that the user is not already registered // and to check that the user is not already registered
// //
beforeCreate: function(attrs, next) { beforeCreate: function (attrs, next) {
var async = require('async');
// We have to encryption AFTER checking user does not exist
// so... we use async.series to ensure task completion async.series(
[
async.series([ function (cb) {
function(cb) { // check email is new Supervisor.findOne({ email: attrs.email }).then(function (supervisor) {
Supervisor.findByEmail(attrs.email).exec(function(err, users) { if (supervisor) {
if (err) return cb(err); cb(new Error('Email being used'));
if (users.length > 0) } else {
return cb(new Error('User exists')); cb();
cb(); }
}); })
}, .catch(function () {
function(cb) { // encrypt password cb();
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) { function (cb) {
if (err) return cb(err); var bcrypt = require('bcrypt-nodejs');
attrs.password = hash; if (attrs.password) {
cb(); attrs.password = bcrypt.hashSync(attrs.password, bcrypt.genSaltSync());
}); }
}); cb();
} }
], function(err) { ],
if (err) return next(err); function (err) {
next(); if (err) {
}); next(err);
} else {
next();
}
}
);
}, },
// //
// Model hook for storing encrypted password when updating an account // Model hook for storing encrypted password when updating an account
// and to check that the user new email is not already registered // and to check that the user new email is not already registered
// //
beforeUpdate: function(attrs, next) { beforeUpdate: function (attrs, next) {
var async = require('async');
async.series([
function(cb) { async.series(
// [
// Check that user email does not exist function (cb) {
// Supervisor.findOne({ email: attrs.email }).then(function (supervisor) {
if(attrs.email){ if (supervisor && supervisor.id !== attrs.id) {
Supervisor.findByEmail(attrs.email).exec(function(err, users) { cb(new Error('Email being used'));
if (err) } else {
return cb(err); cb();
if (users.length > 0) }
return cb(new Error('User email already exists')); })
cb(); .catch(function () {
}); cb();
} else { });
return cb(new Error('No email in user attributes')); },
}
}, function (cb) {
function(cb) { var bcrypt = require('bcrypt-nodejs');
// if (attrs.password) {
// Encrypt password before insertion attrs.password = bcrypt.hashSync(attrs.password, bcrypt.genSaltSync());
// }
if(attrs.password){ cb();
var bcrypt = require('bcrypt-nodejs'); }
],
bcrypt.genSalt(10, function(err, salt) { function (err) {
if (err) return cb(err); if (err) {
bcrypt.hash(attrs.password, salt, null, function(err, hash) { next(err);
if (err) return cb(err); } else {
attrs.password = hash; next();
cb(); }
}); }
}); );
}else{
cb();
}
}], function(err) {
if (err) return next(err);
next();
});
} }
}; };
...@@ -11,7 +11,7 @@ principal: ...@@ -11,7 +11,7 @@ principal:
- Los estilos se encuentran [/sails/src/assets/styles][3] - Los estilos se encuentran [/sails/src/assets/styles][3]
- Los scripts y vistas se encuentran en [/sails/src/assets/scripts][4] - Los scripts y vistas se encuentran en [/sails/src/assets/scripts][4]
[1]: ../../../install.sh [1]: /softuno/pictogram/blob/master/sails/install.sh
[2]: ../../../README.md [2]: /softuno/pictogram/tree/master/sails
[3]: ../styles [3]: /softuno/pictogram/tree/master/sails/src/assets/styles
[4]: ../scripts [4]: /softuno/pictogram/tree/master/sails/src/assets/scripts
'use strict';
/* Configuration constants */
angular.module('dashboardConfig', []).constant('config', {
backend: "http://localhost:1337"
});
//// 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 ...@@ -97,7 +97,7 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
lang: office.lang, lang: office.lang,
id: office.id, id: office.id,
maxStudents: office.maxStudents maxStudents: office.maxStudents
}; };
$scope.formdataoffice.admin = { $scope.formdataoffice.admin = {
id: office.admin.id, id: office.admin.id,
...@@ -109,18 +109,18 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -109,18 +109,18 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
// Save an Office updated // Save an Office updated
$scope.save_office = function(){ $scope.save_office = function(){
var office = $scope.formdataoffice; var office = $scope.formdataoffice;
console.log("1) Before searching admin id by email: " + JSON.stringify(office)); console.log("1) Before searching admin id by email: " + JSON.stringify(office));
// If email admin is filled // If email admin is filled
// search id by email admin // search id by email admin
console.log("2) Searching admin id by email"); console.log("2) Searching admin id by email");
$http $http
.get(config.backend+'/sup?where={"email":"'+ office.admin.email +'"}') .get(config.backend + '/sup/email/' + office.admin.email)
.then(function(result) { .then(function(result) {
// result <-- data, status, headers, config // 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 exists the email
if(result.data.length > 0){ if(result.data.length > 0){
office.admin.id = result.data[0].id; office.admin.id = result.data[0].id;
console.log("2.1) Exists: " + office.admin.id); console.log("2.1) Exists: " + office.admin.id);
// Delete the email, the id and id_off is the only needed // Delete the email, the id and id_off is the only needed
...@@ -130,12 +130,12 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -130,12 +130,12 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
office.admin.id = null; office.admin.id = null;
delete(office.admin.email); 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 // 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){ .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 // Show success message
$scope.showmessageoffice = true; $scope.showmessageoffice = true;
...@@ -148,14 +148,14 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -148,14 +148,14 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
// Update the view: Se recorre el array de objetos json para buscarlo // Update the view: Se recorre el array de objetos json para buscarlo
for(var i=0; i < $scope.offices.length; i++) { 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[i].name = result.data.name; $scope.offices[i].name = result.data.name;
$scope.offices[i].address = result.data.address; $scope.offices[i].address = result.data.address;
$scope.offices[i].contactPerson = result.data.contactPerson; $scope.offices[i].contactPerson = result.data.contactPerson;
$scope.offices[i].email = result.data.email; $scope.offices[i].email = result.data.email;
$scope.offices[i].phone1 = result.data.phone1; $scope.offices[i].phone1 = result.data.phone1;
$scope.offices[i].phone2 = result.data.phone2; $scope.offices[i].phone2 = result.data.phone2;
$scope.offices[i].lang = result.data.lang; $scope.offices[i].lang = result.data.lang;
$scope.offices[i].maxStudents = result.data.maxStudents; $scope.offices[i].maxStudents = result.data.maxStudents;
// Only if returns an admin // Only if returns an admin
...@@ -163,7 +163,7 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -163,7 +163,7 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
$scope.offices[i].admin.id = result.data.admin.id; $scope.offices[i].admin.id = result.data.admin.id;
$scope.offices[i].admin.name = result.data.admin.name; $scope.offices[i].admin.name = result.data.admin.name;
$scope.offices[i].admin.surname = result.data.admin.surname; $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; $scope.offices[i].admin.phone = result.data.admin.phone;
}else{ }else{
delete($scope.offices[i].admin); delete($scope.offices[i].admin);
...@@ -193,13 +193,13 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -193,13 +193,13 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
// search id by email admin // search id by email admin
console.log("2) Searching admin id by email"); console.log("2) Searching admin id by email");
$http $http
.get(config.backend+'/sup?where={"email":"'+ office.admin.email +'"}') .get(config.backend + '/sup/email/' + office.admin.email)
.then(function(result) { .then(function(result) {
// result <-- data, status, headers, config // 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 exists the email
if(result.data.length > 0){ if(result.data.length > 0){
sup = result.data[0]; sup = result.data[0];
office.admin.id = result.data[0].id; office.admin.id = result.data[0].id;
console.log("2.1) Exists: " + office.admin.id); console.log("2.1) Exists: " + office.admin.id);
// Delete the email, the id is the only needed // Delete the email, the id is the only needed
...@@ -208,12 +208,12 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -208,12 +208,12 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
}else{ }else{
delete(office.admin); 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 // Returns the put request
return $http.post(config.backend+'/office', office); return $http.post(config.backend+'/office', office);
}) })
.then(function(result){ .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 // Show success message
$scope.showmessageoffice = true; $scope.showmessageoffice = true;
...@@ -244,7 +244,7 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -244,7 +244,7 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
} }
// Add to the list of office in view // Add to the list of office in view
$scope.offices.push(result.data.office); $scope.offices.push(result.data.office);
}) })
.catch(function(result){ .catch(function(result){
console.log("Error: " + result.data.error); console.log("Error: " + result.data.error);
...@@ -265,10 +265,10 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -265,10 +265,10 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s
$http $http
.delete(config.backend+'/office/'+ office.id) .delete(config.backend+'/office/'+ office.id)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
// Eliminar de la vista: Se recorre el array de objetos json para buscarlo // Eliminar de la vista: Se recorre el array de objetos json para buscarlo
for(var i=0; i < $scope.offices.length; i++) { 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); $scope.offices.splice(i,1);
} }
console.log("Office deleted:" + office.name); console.log("Office deleted:" + office.name);
...@@ -288,4 +288,4 @@ dashboardControllers.controller('AdminOfficesCtrl', function AdminOfficesCtrl($s ...@@ -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 ...@@ -23,7 +23,7 @@ dashboardControllers.controller('AdminSupervisorsCtrl', function AdminSupervisor
// List of supervisors // List of supervisors
$http $http
.get(config.backend+'/sup') .get(config.backend+'/sup/all')
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
$scope.supervisors = data; $scope.supervisors = data;
}) })
...@@ -104,7 +104,7 @@ dashboardControllers.controller('AdminSupervisorsCtrl', function AdminSupervisor ...@@ -104,7 +104,7 @@ dashboardControllers.controller('AdminSupervisorsCtrl', function AdminSupervisor
delete supervisor.id; delete supervisor.id;
$http $http
.put(config.backend+'/supervisor/'+supid, supervisor) .put(config.backend + '/sup/' + supid, supervisor)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
$translate('supervisor_updated').then(function (translation) { $translate('supervisor_updated').then(function (translation) {
ngToast.success({ content: translation }); ngToast.success({ content: translation });
......
...@@ -108,12 +108,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl( ...@@ -108,12 +108,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
// Search supervisor by email // Search supervisor by email
$scope.search_sup = function () { $scope.search_sup = function () {
// Find tutor by email // Find tutor by email
$http.get([ $http.get(config.backend + '/sup/email/' + $scope.email_sup)
config.backend,
'/sup?where={"email":"',
$scope.email_sup,
'", "office":{"!": null}}'
].join(''))
.success(function (data) { .success(function (data) {
if (data.length > 0) { if (data.length > 0) {
$scope.supToAdd = data[0]; $scope.supToAdd = data[0];
...@@ -190,7 +185,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl( ...@@ -190,7 +185,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
// Search tutor by email // Search tutor by email
$scope.search_tutor = function () { $scope.search_tutor = function () {
// Find tutor by email // 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) { .success(function (data) {
// If it found the length is > 0 // If it found the length is > 0
if (data.length > 0) { if (data.length > 0) {
...@@ -302,4 +297,3 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl( ...@@ -302,4 +297,3 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
}); });
}; };
}); });
d
...@@ -206,13 +206,4 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl( ...@@ -206,13 +206,4 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
.error(function () { .error(function () {
// TODO show error with ngToast // 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
});
}); });
...@@ -92,7 +92,7 @@ dashboardControllers.controller('SetupCtrl', function SetupCtrl( ...@@ -92,7 +92,7 @@ dashboardControllers.controller('SetupCtrl', function SetupCtrl(
delete supervisor.email; delete supervisor.email;
} }
$http.put(config.backend + '/sup', supervisor) $http.put(config.backend + '/sup/' + supervisor.id, supervisor)
.success(function (data) { .success(function (data) {
$translate('data_saved').then(function (translation) { $translate('data_saved').then(function (translation) {
ngToast.success({ content: translation }); ngToast.success({ content: translation });
......
...@@ -87,7 +87,7 @@ img.preview{ ...@@ -87,7 +87,7 @@ img.preview{
legend{ padding-top: 20px; } legend{ padding-top: 20px; }
/* Estilos aplicados por defecto /* Estilos aplicados por defecto
(Móviles y pantallas menores de 992px) (Móviles y pantallas menores de 992px)
*/ */
...@@ -122,7 +122,7 @@ div.languages { ...@@ -122,7 +122,7 @@ div.languages {
padding-top: 10px; padding-top: 10px;
margin: 0; margin: 0;
background-color: #f8f8f8; background-color: #f8f8f8;
border-top: 1px solid #e7e7e7; border-top: 1px solid #e7e7e7;
font-size: 1.2em; font-size: 1.2em;
text-align: center; text-align: center;
} }
...@@ -188,7 +188,7 @@ tr:hover .ops a{ ...@@ -188,7 +188,7 @@ tr:hover .ops a{
#supervisor_header .img_profile{ #supervisor_header .img_profile{
margin-top: 10px; margin-top: 10px;
margin-left: 10px; margin-left: 10px;
margin-bottom: 0; margin-bottom: 0;
width: 50px; width: 50px;
height: 50px; height: 50px;
...@@ -233,11 +233,6 @@ tr:hover .ops a{ ...@@ -233,11 +233,6 @@ tr:hover .ops a{
height: 40px; height: 40px;
} }
/* Panel dipositivos del estudiante */
#student_devices{
margin-top: 30px;
}
/* Panel del estudiante (sin borde superior para pestañas) */ /* Panel del estudiante (sin borde superior para pestañas) */
.student_tab_panel{ .student_tab_panel{
border-top: none; border-top: none;
...@@ -279,7 +274,7 @@ tr:hover .ops a{ ...@@ -279,7 +274,7 @@ tr:hover .ops a{
/* Celdas con input para editar */ /* Celdas con input para editar */
td.editable{ td.editable{
padding: 0px !important; padding: 0px !important;
height: 40px; height: 40px;
} }
...@@ -293,7 +288,7 @@ td.editable input{ ...@@ -293,7 +288,7 @@ td.editable input{
.elipsis{ .elipsis{
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
...@@ -305,7 +300,7 @@ input.editable{ ...@@ -305,7 +300,7 @@ input.editable{
} }
.editable:focus { .editable:focus {
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
border-radius: 5px; border-radius: 5px;
outline: none; outline: none;
...@@ -321,7 +316,7 @@ textarea.editable{ ...@@ -321,7 +316,7 @@ textarea.editable{
padding: 6px; padding: 6px;
margin-bottom: 8px; margin-bottom: 8px;
} }
/* Panel Colecciones */ /* Panel Colecciones */
.drag { opacity: 0.5; } .drag { opacity: 0.5; }
...@@ -427,7 +422,7 @@ textarea.editable{ ...@@ -427,7 +422,7 @@ textarea.editable{
/* Class for pictos when are deactivated to the student, but are visibles */ /* Class for pictos when are deactivated to the student, but are visibles */
/*.picto img.deactivate { /*.picto img.deactivate {
filter: url('#grayscale'); / Versión SVG para IE10, Chrome 17, FF3.5, Safari 5.2 and Opera 11.6 / filter: url('#grayscale'); / Versión SVG para IE10, Chrome 17, FF3.5, Safari 5.2 and Opera 11.6 /
-webkit-filter: grayscale(100%); -webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%); -moz-filter: grayscale(100%);
...@@ -439,9 +434,9 @@ textarea.editable{ ...@@ -439,9 +434,9 @@ textarea.editable{
.picto img.disabled { .picto img.disabled {
position: absolute; position: absolute;
bottom: 0px; /* position will be on bottom */ bottom: 0px; /* position will be on bottom */
left: 0px; left: 0px;
width: 100%; width: 100%;
} }
/* Class for pictos that aren't saw by the student */ /* Class for pictos that aren't saw by the student */
...@@ -521,7 +516,7 @@ textarea.editable{ ...@@ -521,7 +516,7 @@ textarea.editable{
/* Para que la altura de los li de la lista se adapte al tamaño automáticamente */ /* Para que la altura de los li de la lista se adapte al tamaño automáticamente */
.list-group-item{ .list-group-item{
overflow:hidden; overflow:hidden;
} }
/* Etiquetas dentro de las ventanas modales de info y etiquetas de los pictos */ /* Etiquetas dentro de las ventanas modales de info y etiquetas de los pictos */
...@@ -662,7 +657,7 @@ textarea.editable{ ...@@ -662,7 +657,7 @@ textarea.editable{
/* Link to show the try actions */ /* Link to show the try actions */
.try_details{ .try_details{
visibility: hidden; visibility: hidden;
font-size: 2em; font-size: 2em;
} }
.try:hover .try_details{ .try:hover .try_details{
...@@ -689,7 +684,7 @@ textarea.editable{ ...@@ -689,7 +684,7 @@ textarea.editable{
/* Para que se vea el menú contextual por encima del resto de paneles */ /* Para que se vea el menú contextual por encima del resto de paneles */
#options{ #options{
z-index: 10000; z-index: 10000;
width: 200px; width: 200px;
} }
...@@ -739,7 +734,7 @@ textarea.editable{ ...@@ -739,7 +734,7 @@ textarea.editable{
text-decoration: none; text-decoration: none;
} }
/* Reports */ /* Reports */
#year_select{ #year_select{
max-width: 300px; max-width: 300px;
display: inline-block; display: inline-block;
...@@ -778,7 +773,6 @@ img.profile{ ...@@ -778,7 +773,6 @@ img.profile{
#user_tutors .list-group-item:hover .delete_tutor, #user_tutors .list-group-item:hover .delete_tutor,
#user_sups .list-group-item:hover .delete_sup, #user_sups .list-group-item:hover .delete_sup,
#user_devices .list-group-item:hover .delete_device,
#table_students tr:hover .delete_stu{ #table_students tr:hover .delete_stu{
visibility: visible; visibility: visible;
} }
...@@ -794,10 +788,10 @@ label.student_setup{ ...@@ -794,10 +788,10 @@ label.student_setup{
input[type=range] { input[type=range] {
/*removes default webkit styles*/ /*removes default webkit styles*/
-webkit-appearance: none; -webkit-appearance: none;
/*fix for FF unable to apply focus style bug */ /*fix for FF unable to apply focus style bug */
border: 1px solid white; border: 1px solid white;
/*required for proper track sizing in FF*/ /*required for proper track sizing in FF*/
width: 300px; width: 300px;
} }
...@@ -848,10 +842,10 @@ input[type=range]:-moz-focusring{ ...@@ -848,10 +842,10 @@ input[type=range]:-moz-focusring{
input[type=range]::-ms-track { input[type=range]::-ms-track {
width: 300px; width: 300px;
height: 5px; height: 5px;
/*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */ /*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */
background: transparent; background: transparent;
/*leave room for the larger thumb to overflow with a transparent border */ /*leave room for the larger thumb to overflow with a transparent border */
border-color: transparent; border-color: transparent;
border-width: 6px 0; border-width: 6px 0;
...@@ -898,9 +892,9 @@ input[type=range]:focus::-ms-fill-upper { ...@@ -898,9 +892,9 @@ input[type=range]:focus::-ms-fill-upper {
/* Se aplica de Dispositivos medianos en adelante /* Se aplica de Dispositivos medianos en adelante
(tablets, ordenadores, anchura mayor o igual a 768px) */ (tablets, ordenadores, anchura mayor o igual a 768px) */
@media (min-width: 768px) { @media (min-width: 768px) {
/* Estilos generales */ /* Estilos generales */
/* Estilos para el panel de login*/ /* Estilos para el panel de login*/
#login{ #login{
...@@ -912,7 +906,7 @@ input[type=range]:focus::-ms-fill-upper { ...@@ -912,7 +906,7 @@ input[type=range]:focus::-ms-fill-upper {
} }
#signin .help-block{ #signin .help-block{
} }
} }
...@@ -923,11 +917,11 @@ input[type=range]:focus::-ms-fill-upper { ...@@ -923,11 +917,11 @@ input[type=range]:focus::-ms-fill-upper {
width: 36px; width: 36px;
height: 36px; height: 36px;
padding: 8px; padding: 8px;
background: #fff; background: #fff;
border: 2px solid #3071a9; border: 2px solid #3071a9;
color: #3071a9; color: #3071a9;
text-align: center; text-align: center;
font: 32px Arial, sans-serif; font: 32px Arial, sans-serif;
} }
\ No newline at end of file
var path = require('path'); /**
var ASSETS_PATH = path.join(__dirname, '..', 'assets'); * 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 = { module.exports = {
paths: { paths: {
public: path.join(ASSETS_PATH), public: __dirname + '/../assets'
upload: path.join(ASSETS_PATH, 'upload'),
defaultAvatar: path.join(ASSETS_PATH, 'defaultAvatar.jpg'),
supervisorAvatarDirectory: path.join(ASSETS_PATH, 'supervisorAvatar'),
/**
* Gets the supervisor avatar filename
* @param {supervisorId} supervisorId
* @return {string} fileName
*/
getSupervisorAvatarFileName: function (supervisorId) {
var imageNameHash = require('crypto').createHash('sha512');
imageNameHash.update(supervisorId);
imageNameHash.update((new Date()).getTime());
return imageNameHash.digest('hex') + '.jpg';
}
} }
}; };
...@@ -8,48 +8,27 @@ ...@@ -8,48 +8,27 @@
* For more information on bootstrapping your app, check out: * For more information on bootstrapping your app, check out:
* http://sailsjs.org/#/documentation/reference/sails.config/sails.config.bootstrap.html * http://sailsjs.org/#/documentation/reference/sails.config/sails.config.bootstrap.html
*/ */
var fs = require('fs') var fs = require('fs');
, path = require('path'); var path = require('path');
module.exports.bootstrap = function (cb) { module.exports.bootstrap = function (callback) {
// Whatever else you want to bootstrap... var i;
var directories = ['upload', 'symbolstx'];
var source = path.join(process.cwd(), '../upload'),
dest = path.join(process.cwd(), 'assets/upload'); function createSymlink(source, destination) {
fs.readlink(destination, function (error, linkString) {
fs.readlink(dest, function(err, linkString){ if (!linkString) {
// If symlin don't exists, it is created fs.symlink(source, destination, 'dir', function () {});
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);
}); });
}
}else{ for (i = 0; i < directories.length; i++) {
console.log("Symlink to symbolstx exists!"); createSymlink(
} path.join(process.cwd(), '..', directories[i]),
}); path.join(process.cwd(), 'assets', directories[i])
);
}
cb(); callback();
}; };
\ No newline at end of file
...@@ -10,34 +10,53 @@ ...@@ -10,34 +10,53 @@
* http://sailsjs.org/#/documentation/concepts/Logging * http://sailsjs.org/#/documentation/concepts/Logging
*/ */
var winston = require('winston'); const winston = require('winston');
const path = require('path');
var customLogger = new winston.Logger({ const customLogger = new winston.Logger({
transports: [ level: 'silly'
new(winston.transports.File)({
level: 'debug',
filename: './logs/my_log_file.log'
}),
],
}); });
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')
});
/*************************************************************************** customLogger.add(winston.transports.File, {
* * name: 'debug-json',
* Valid `level` configs: i.e. the minimum log level to capture with * silent: false,
* sails.log.*() * colorize: false,
* * level: 'debug',
* The order of precedence for log levels from lowest to highest is: * showLevel: true,
* silly, verbose, info, debug, warn, error * timestamp: true,
* * json: true,
* You may also set the level to "silent" to suppress all logs. * tailable: true,
* * maxsize: 5 * 1024 * 1024, // 5 MegaByte
***************************************************************************/ filename: path.resolve(__dirname, '..', 'logs', 'debug.json')
});
// level: 'info' customLogger.add(winston.transports.File, {
// level: 'debug' 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 module.exports.log = {
custom: customLogger 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 = { module.exports.pictogram = {
// admin: {
// Administrator credentials email: 'amontejo@ujaen.es',
// password: '$2a$10$omHwM62JNI5O1hbkfFGncOYwq3mZATmh8NnTQhN3f7JV3Q1/S9fGG'
admin: { },
email: 'amontejo@ujaen.es', serialSize: 10, // number of characters in generated serial numbers
//password: '$2a$10$ZLdXN6OqROnE1eEC7D7mleqhwWDEemTswXhKh53qC5e3GEMm3Ch6q', pageLimit: 10, // number of elements per "page"
password: '$2a$10$omHwM62JNI5O1hbkfFGncOYwq3mZATmh8NnTQhN3f7JV3Q1/S9fGG'
}, urls: {
serialSize: 10, // number of characters in generated serial numbers /**
pageLimit: 10 // number of elements per "page" * Gets the public url of a supervisor avatar
}; * @param {String} filename filename of the avatar (stored in database)
\ No newline at end of file * @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,164 +15,111 @@ ...@@ -15,164 +15,111 @@
* For more information on configuring policies, check out: * For more information on configuring policies, check out:
* http://sailsjs.org/#/documentation/reference/sails.config/sails.config.policies.html * http://sailsjs.org/#/documentation/reference/sails.config/sails.config.policies.html
*/ */
module.exports.policies = { module.exports.policies = {
// Sorted as they appear in routes.js
// Grouped by controller, sorted by HTTP method
// Valido '*': false,
'*': false, // Disable access as default ActionController: {
create: ['tokenAuth'],
createlist: ['tokenAuth']
},
SupervisorController: { AdminController: {
create: true, login: true
login: true,
activate: true,
upload: ['tokenAuth'],
students: ['tokenAuth'],
pictos: ['tokenAuth'],
list: ['tokenAuth', 'isAdmin'],
subscribe: ['tokenAuth'],
unsubscribe: ['tokenAuth']
}, },
// Invalido InstructionController: {
ws: ['tokenAuth'],
update: ['tokenAuth'],
create: ['tokenAuth'],
destroy: ['tokenAuth']
},
// SupervisorController: { MethodController: {
// find: ['tokenAuth'], /* @TODO isAdmin */ update: ['tokenAuth'],
// findOne: ['tokenAuth'], create: ['tokenAuth'],
// update: ['tokenAuth'], newMethod: ['tokenAuth'],
// destroy: ['tokenAuth', 'isAdmin'], save: ['tokenAuth'],
// }, destroy: ['tokenAuth'],
destroyTemplate: ['tokenAuth'],
meta_methods: ['tokenAuth']
},
// Sin comprobar OfficeController: {
getAll: ['tokenAuth', 'isAdmin'],
get: ['tokenAuth'],
supervisors: ['tokenAuth', 'isAdmin']
},
PagesController: { // all static pages all publicy available PictoController: {
'*': true upload: ['tokenAuth'],
add_tag: ['tokenAuth'],
change_exp: ['tokenAuth'],
destroy: ['tokenAuth'],
del_tag: ['tokenAuth'],
categories: ['tokenAuth'],
fromcategory: ['tokenAuth']
}, },
ServerController: { ServerController: {
ping: true, ping: true,
ping_session: ['tokenAuth'], ping_session: ['tokenAuth']
},
AdminController: {
login: true
},
OfficeController: {
get: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
getAll: ['tokenAuth', 'isAdmin'],
// @TODO 357
create: ['tokenAuth', 'isAdmin'],
// @TODO 357
update: ['tokenAuth', 'isAdmin'],
// @TODO 357
destroy: ['tokenAuth', 'isAdmin'],
supervisors: ['tokenAuth', 'isAdmin'],
// @TODO 357
populate: ['tokenAuth']
}, },
StudentController: { StudentController: {
login: true,
// @TODO 357
find: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
getInfo: ['tokenAuth'], getInfo: ['tokenAuth'],
create: ['tokenAuth'], // isSupAdmin too
update: ['tokenAuth'],
delete: ['tokenAuth'],
supervisors: ['tokenAuth'], supervisors: ['tokenAuth'],
therapists: ['tokenAuth'], therapists: ['tokenAuth'],
tutors: ['tokenAuth'], // isSupervisorOfStudent falla en Student.supervisors tutors: ['tokenAuth'],
link_supervisor: ['tokenAuth'], link_supervisor: ['tokenAuth'],
unlink_supervisor: ['tokenAuth'],
subscribe: ['tokenAuth'], // websockets
unsubscribe: true, // websockets
vocabulary: true, // websockets
action: true, // websockets
config: true, // websockets
pictos: ['tokenAuth'], pictos: ['tokenAuth'],
add_picto: ['tokenAuth', 'isSupervisorOfStudent'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent'],
update_picto: ['tokenAuth', 'isSupervisorOfStudent'],
upload: ['tokenAuth'],
methods: ['tokenAuth'], methods: ['tokenAuth'],
lasttries: ['tokenAuth'], lasttries: ['tokenAuth'],
tries: ['tokenAuth'], tries: ['tokenAuth'],
last_instruction: ['tokenAuth'],
ws: ['tokenAuth'], ws: ['tokenAuth'],
actions_batch: ['tokenAuth'],
sqlquery: ['tokenAuth']
},
// @TODO 357
StuSupController: {
find: ['tokenAuth'],
findOne: ['tokenAuth'],
create: ['tokenAuth'],
destroy: ['tokenAuth']
},
PictoController: {
// @TODO 357
create: ['tokenAuth'],
destroy: ['tokenAuth'],
categories: ['tokenAuth'],
fromcategory: ['tokenAuth'],
// @TODO 357
find: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
add_tag: ['tokenAuth'],
del_tag: ['tokenAuth'],
change_exp: ['tokenAuth'],
upload: ['tokenAuth']
},
MethodController: {
create: ['tokenAuth'],
newMethod: ['tokenAuth'],
update: ['tokenAuth'], update: ['tokenAuth'],
destroy: ['tokenAuth'], update_picto: ['tokenAuth', 'isSupervisorOfStudent'],
// @TODO 357 login: true,
find: ['tokenAuth'],
// @TODO 357
findOne: ['tokenAuth'],
meta_methods: ['tokenAuth'],
// @TODO 357
methods: ['tokenAuth'],
save: ['tokenAuth'],
destroyTemplate: ['tokenAuth'], // Add policie isOwner (supervisor.id == metamethod.id_sup)
},
InstructionController: {
create: ['tokenAuth'], create: ['tokenAuth'],
update: ['tokenAuth'], upload: ['tokenAuth'],
destroy: ['tokenAuth'], add_picto: ['tokenAuth', 'isSupervisorOfStudent'],
// @TODO 357 subscribe: ['tokenAuth'],
find: ['tokenAuth'], unsubscribe: true,
// @TODO 357 vocabulary: true,
findOne: ['tokenAuth'], action: true,
// @TODO 357 config: true,
ws: ['tokenAuth'], actions_batch: ['tokenAuth'],
delete: ['tokenAuth'],
unlink_supervisor: ['tokenAuth'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent']
}, },
WorkingSessionController: {
close: ['tokenAuth'], SupervisorController: {
// @TODO 357 list: ['tokenAuth', 'isAdmin'],
create: ['tokenAuth'], students: ['tokenAuth'],
// @TODO 357 pictos: ['tokenAuth'],
getByEmail: ['tokenAuth'],
update: ['tokenAuth'], update: ['tokenAuth'],
// @TODO 357 create: true,
destroy: ['tokenAuth'], login: true,
// @TODO 357 activate: true,
find: ['tokenAuth'], upload: ['tokenAuth'],
// @TODO 357 subscribe: ['tokenAuth'],
findOne: ['tokenAuth'], unsubscribe: ['tokenAuth']
tries: ['tokenAuth'],
per_year: ['tokenAuth'],
per_month: ['tokenAuth']
}, },
TryController: { TryController: {
create: ['tokenAuth'],
update: ['tokenAuth'], update: ['tokenAuth'],
create: ['tokenAuth']
}, },
ActionController: {
create: ['tokenAuth'], WorkingSessionController: {
createlist: ['tokenAuth'], per_year: ['tokenAuth'],
}, per_month: ['tokenAuth'],
tries: ['tokenAuth'],
close: ['tokenAuth']
}
}; };
# Certificados para el servidor HTTPS
A no ser que se modifique el fichero [local.js][1] para establecer otra ubicación, los certificados
utilizados para ejecutar el servidor con HTTPS deben colocarse en esta ubicación con los nombres:
- bundle.crt
- key.key
- cert.crt
[1]: /softuno/pictogram/blob/master/sails/roles/server/files/local.js
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
"description": "Server side of the Pictogram platform", "description": "Server side of the Pictogram platform",
"keywords": [], "keywords": [],
"dependencies": { "dependencies": {
"async": "^2.0.0-rc.4",
"bcrypt-nodejs": "0.0.3", "bcrypt-nodejs": "0.0.3",
"connect-redis": "3.0.2", "connect-redis": "3.0.2",
"ejs": "^0.8.8", "ejs": "^0.8.8",
...@@ -12,7 +13,6 @@ ...@@ -12,7 +13,6 @@
"include-all": "~0.1.3", "include-all": "~0.1.3",
"jsonwebtoken": "~0.4.0", "jsonwebtoken": "~0.4.0",
"lodash": "^3.10.1", "lodash": "^3.10.1",
"mocha": "^2.3.4",
"rc": "~0.5.0", "rc": "~0.5.0",
"sails": "^0.12.3", "sails": "^0.12.3",
"sails-disk": "~0.10.0", "sails-disk": "~0.10.0",
...@@ -25,7 +25,9 @@ ...@@ -25,7 +25,9 @@
}, },
"scripts": { "scripts": {
"start": "node app.js", "start": "node app.js",
"debug": "node debug app.js" "debug": "node debug app.js",
"test": "mocha test/test-helper.js test/**/*-spec.js",
"test:watch": "npm run test -- --reporter min --watch"
}, },
"main": "app.js", "main": "app.js",
"repository": { "repository": {
...@@ -35,10 +37,14 @@ ...@@ -35,10 +37,14 @@
"author": "emblanco, amontejo", "author": "emblanco, amontejo",
"license": "", "license": "",
"devDependencies": { "devDependencies": {
"eslint": "^2.8.0", "chai": "^3.5.0",
"eslint-config-airbnb": "^7.0.0", "eslint": "^2.9.0",
"eslint-plugin-jsx-a11y": "^1.0.1", "eslint-config-airbnb": "^9.0.1",
"eslint-plugin-react": "^5.0.1", "eslint-plugin-import": "^1.8.0",
"node-inspector": "^0.12.8" "eslint-plugin-jsx-a11y": "^1.2.0",
"eslint-plugin-react": "^5.1.1",
"mocha": "^2.4.5",
"node-inspector": "^0.12.8",
"supertest": "^1.2.0"
} }
} }
...@@ -39,7 +39,6 @@ module.exports = function (grunt) { ...@@ -39,7 +39,6 @@ module.exports = function (grunt) {
'assets/scripts/modules/login/controllers/signin.js', 'assets/scripts/modules/login/controllers/signin.js',
'assets/scripts/modules/login/controllers/login_admin.js', 'assets/scripts/modules/login/controllers/login_admin.js',
'assets/scripts/modules/admin/controllers/admin.js', 'assets/scripts/modules/admin/controllers/admin.js',
'assets/scripts/modules/admin/controllers/devices.js',
'assets/scripts/modules/admin/controllers/offices.js', 'assets/scripts/modules/admin/controllers/offices.js',
'assets/scripts/modules/admin/controllers/supervisors.js', 'assets/scripts/modules/admin/controllers/supervisors.js',
'assets/scripts/modules/supervisor/controllers/supervisor.js', 'assets/scripts/modules/supervisor/controllers/supervisor.js',
......
{
"globals": {
"sails": true,
"describe": true,
"it": true,
"assert": true,
"before": true,
"after": true,
"beforeEach": true,
"afterEach": true,
"publicAgent": true,
"adminAgent": true,
"studentAgent": true,
"supervisorAgent": true,
"cajaIds": true
}
}
To run test, go to root sails folder (pictogram/sails/src) and run:
$ mocha -t 30000 test/**/*.js
describe('Action API', function () {
it('POST /action', function (done) {
studentAgent.post('/action').send({
student: studentAgent.data.id,
type: 'Add',
supervisor: supervisorAgent.data.id,
description: '{ json description }'
})
.expect(200)
.expect((response) => {
assert.isObject(response.body);
assert.isNumber(response.body.id);
delete response.body.id;
})
.expect({
student: studentAgent.data.id,
type: 'Add',
supervisor: supervisorAgent.data.id,
description: '{ json description }',
})
.end(done);
});
it('POST /actions');
});
describe('Admin API', function () {
it('POST /admin/login', function (done) {
publicAgent.post('/admin/login').send({
email: 'testadmin@admin.com',
password: '1234'
})
.expect(200)
.end(done);
});
});
describe('Instruction API', function () {
it('GET /instruction/:id_ins/ws');
it('PUT /instruction/:id', function (done) {
supervisorAgent.put('/instruction/' + cajaIds.instruction).send({
name: 'Changed Test Instruction'
})
.expect(200)
.expect({
id: cajaIds.instruction,
name: 'Changed Test Instruction',
method: cajaIds.method,
begin: null,
end: null,
objective: null,
status: null
})
.end(function (error) {
if (error) {
throw error;
}
supervisorAgent.put('/instruction/' + cajaIds.instruction).send({
name: 'Test Instruction'
})
.expect(200)
.end(done);
});
});
it('POST /instruction', function (done) {
supervisorAgent.post('/instruction').send({
method: cajaIds.method,
name: 'New Instruction',
objective: 'None',
status: 'pending'
})
.expect(200)
.expect(function (response) {
assert.isObject(response.body);
assert.isNumber(response.body.id);
delete response.body.id;
})
.expect({
method: cajaIds.method,
name: 'New Instruction',
objective: 'None',
status: 'pending',
begin: null,
end: null
})
.end(done);
});
it('DELETE /instruction/:id', function (done) {
var instructionId;
supervisorAgent.post('/instruction').send({
method: cajaIds.method,
name: 'New Instruction',
objective: 'None',
status: 'pending'
})
.expect(200)
.expect(function (response) {
assert.isObject(response.body);
assert.isNumber(response.body.id);
instructionId = response.body.id;
})
.end(function (error) {
if (error) {
throw error;
}
supervisorAgent
.delete('/instruction/' + instructionId)
.send()
.expect(200)
.end(done);
});
});
});
describe('Metamethods API', function () {
it('GET /metamethods/:id_sup', function (done) {
supervisorAgent
.get('/metamethods/' + supervisorAgent.data.id)
.send()
.expect(200)
.expect(function (response) {
assert.isArray(response.body);
response.body.forEach(function (metaMethod) {
assert.isObject(metaMethod);
assert.isNumber(metaMethod.id);
assert.isString(metaMethod.name);
try {
assert.isNumber(metaMethod.supervisor);
} catch (error) {
assert.isNull(metaMethod.supervisor);
}
try {
assert.isString(metaMethod.description);
} catch (error) {
assert.isNull(metaMethod.description);
}
});
})
.end(done);
});
});
describe('Method API', function () {
it('PUT /method/:id');
it('POST /method', function (done) {
supervisorAgent.post('/method').send({
id_mmethod: 1,
id_stu: studentAgent.data.id
})
.expect(200)
.expect(function (response) {
assert.isObject(response.body);
assert.isNumber(response.body.id);
assert.isArray(response.body.instructions);
response.body.instructions.forEach(function (instruction) {
assert.isNumber(instruction.id);
assert.equal(instruction.method, response.body.id);
assert.isString(instruction.name);
assert.isString(instruction.objective);
});
delete response.body.id;
delete response.body.instructions;
})
.expect({
name: 'Comunicación Aumentativa y Adaptativa',
description: null
})
.end(done);
});
it('POST /method/new', function (done) {
supervisorAgent.post('/method/new').send({
id_stu: studentAgent.data.id,
name: 'New Method Without Template'
})
.expect(200)
.expect(function (response) {
assert.isObject(response.body);
assert.isNumber(response.body.id);
delete response.body.id;
})
.expect({
student: studentAgent.data.id,
name: 'New Method Without Template'
})
.end(done);
});
it('POST /method/save');
it('DELETE /method/:id');
it('DELETE /method/template/:id_mmet');
});
describe('Office API', function () {
it('GET /office/get_all');
it('GET /office/get/:id');
it('GET /office/get/:id/supervisors');
});
describe('Picto API', function () {
it('POST /picto/upload', function (done) {
var path = require('path');
supervisorAgent
.post('/picto/upload')
.field('owner', supervisorAgent.data.id)
.attach('file', path.join('test', 'test-photo.png'))
.expect(200)
.expect(function (response) {
assert.isObject(response.body);
assert.isNumber(response.body.id);
assert.equal(response.body.owner, supervisorAgent.data.id);
assert.equal(response.body.source, 1);
})
.end(done);
});
it('POST /picto/tag', function (done) {
supervisorAgent.post('/picto/tag').send({
tag: 'test-tag',
lang: 'es-es',
supervisor: supervisorAgent.data.id,
picto: 1234
})
.expect(200)
.expect(function (response) {
assert.isObject(response.body);
assert.equal(response.body.tag, 'test-tag');
assert.equal(response.body.lang, 'es-es');
assert.equal(response.body.supervisor, supervisorAgent.data.id);
assert.equal(response.body.picto, 1234);
})
.end(done);
});
it('POST /picto/exp', function (done) {
supervisorAgent.post('/picto/exp').send({
picto: 1234,
lang: 'es-es',
text: 'test-expression'
})
.expect(200)
.expect(function (response) {
assert.isObject(response.body);
assert.equal(response.body.picto, 1234);
assert.equal(response.body.lang, 'es-es');
assert.equal(response.body.text, 'test-expression');
})
.end(done);
});
it('DELETE /picto/:id', function (done) {
var path = require('path');
var pictoId;
supervisorAgent
.post('/picto/upload')
.field('owner', supervisorAgent.data.id)
.attach('file', path.join('test', 'test-photo.png'))
.expect(function (response) {
pictoId = response.body.id;
})
.end(function (error) {
if (error) {
throw error;
}
supervisorAgent
.delete('/picto/' + pictoId)
.send()
.expect(200)
.end(done);
});
});
it('DELETE /picto/tag/:id_tag', function (done) {
supervisorAgent
.delete('/picto/tag/' + 1234)
.send()
.expect(200)
.end(done);
});
});
describe('Server API', function () {
it('GET /server/ping', function (done) {
publicAgent
.get('/server/ping')
.send()
.expect(200)
.end(done);
});
it('GET /server/ping_session', function (done) {
publicAgent
.get('/server/ping_session')
.send()
.expect(401)
.end(function (error) {
if (error) {
throw error;
}
supervisorAgent
.get('/server/ping_session')
.send()
.expect(200)
.end(done);
});
});
});
describe('Supervisor API', function () {
it('GET /sup/all', function (done) {
adminAgent.get('/sup/all').send()
.expect(200)
.expect(function (response) {
assert.isArray(response.body);
response.body.forEach(function (supervisor) {
assert.isObject(supervisor);
assert.isNumber(supervisor.id);
assert.isString(supervisor.name);
assert.isString(supervisor.surname);
assert.isUndefined(supervisor.password);
});
})
.end(done);
});
it('GET /sup/:id/students', function (done) {
supervisorAgent.get('/sup/' + supervisorAgent.data.id + '/students').send()
.expect(200)
.expect(function (response) {
assert.isArray(response.body);
response.body.forEach(function (student) {
assert.isObject(student);
assert.isNumber(student.id);
assert.isString(student.name);
assert.isString(student.surname);
assert.isUndefined(student.password);
});
})
.end(done);
});
it('GET /sup/:id/pictos', function (done) {
supervisorAgent.get('/sup/' + supervisorAgent.data.id + '/pictos').send()
.expect(200)
.expect(function (response) {
assert.isArray(response.body);
response.body.forEach(function (picto) {
assert.isNumber(picto.source);
assert.isNumber(picto.owner);
assert.isNumber(picto.id);
assert.isString(picto.uri);
assert.isDefined(picto.category);
});
})
.end(done);
});
it('GET /sup/:id/pic_categories/:id_cat', function (done) {
supervisorAgent.get('/sup/' + supervisorAgent.data.id + '/pic_categories/0').send()
.expect(200)
.expect(function (response) {
assert.isArray(response.body);
response.body.forEach(function (pictoCategory) {
assert.isNumber(pictoCategory.id);
assert.isNumber(pictoCategory.id_supercat);
assert.isArray(pictoCategory.exps);
pictoCategory.exps.forEach(function (pictoCategoryExp) {
assert.isNumber(pictoCategoryExp.id);
assert.isNumber(pictoCategoryExp.id_cat);
assert.isString(pictoCategoryExp.exp);
assert.equal(pictoCategoryExp.lang, supervisorAgent.data.lang);
});
});
})
.end(done);
});
it('GET /sup/:id/pic_fromcategory/:id_cat', function (done) {
supervisorAgent.get('/sup/' + supervisorAgent.data.id + '/pic_fromcategory/41').send()
.expect(200)
.expect(function (response) {
assert.isArray(response.body);
response.body.forEach(function (picto) {
assert.isObject(picto);
assert.isNumber(picto.source);
assert.isNumber(picto.owner);
assert.isNumber(picto.id);
assert.isString(picto.uri);
assert.equal(picto.category, 41);
assert.isArray(picto.expressions);
picto.expressions.forEach(function (expression) {
assert.isObject(expression);
assert.isNumber(expression.id);
assert.isString(expression.text);
assert.equal(expression.lang, supervisorAgent.data.lang);
assert.equal(expression.picto, picto.id);
});
});
})
.end(done);
});
it('GET /sup/email/:email', function (done) {
supervisorAgent.get('/sup/email/' + supervisorAgent.data.email).send()
.expect(200)
.expect(function (response) {
var agentData = Object.assign({}, supervisorAgent.data);
delete agentData.exp;
delete agentData.iat;
delete agentData.isSupAdmin;
delete agentData.office;
delete agentData.password;
assert.isObject(response.body);
delete response.body.exp;
delete response.body.iat;
delete response.body.isSupAdmin;
delete response.body.office;
assert.deepEqual(response.body, agentData);
})
.end(done);
});
it('PUT /sup/:id', function (done) {
var agentData = Object.assign({}, supervisorAgent.data);
delete agentData.password;
delete agentData.exp;
delete agentData.iat;
delete agentData.isSupAdmin;
delete agentData.office;
delete agentData.password;
agentData.name = agentData.name + 's';
supervisorAgent.put('/sup/' + supervisorAgent.data.id).send({
name: agentData.name
})
.expect(200)
.expect(function (response) {
assert.isObject(response.body);
delete response.body.exp;
delete response.body.iat;
delete response.body.isSupAdmin;
delete response.body.office;
assert.deepEqual(response.body, agentData);
})
.end(function (error) {
if (error) {
throw error;
}
// Let's undo the changes, we do not want to make breaking changes
supervisorAgent.put('/sup/' + supervisorAgent.data.id).send({
name: supervisorAgent.data.name
})
.expect(200)
.end(done);
});
});
it('POST /sup', function (done) {
publicAgent.post('/sup').send({
name: 'John',
surname: 'Doe',
gender: 'M',
password: '1234',
address: 'Nice street',
country: 'ES',
email: 'john@doe.com',
phone: '+123456789',
lang: 'ES',
ttsEngine: 'IVONA Text-to-Speech HQ'
})
.expect(200)
.expect(function (response) {
assert.isNumber(response.body.user.id);
assert.isString(response.body.token);
delete response.body.user.id;
delete response.body.token;
})
.expect({
user: {
name: 'John',
surname: 'Doe',
gender: 'M',
pic: sails.config.pictogram.urls.getSupervisorAvatarUrl(
sails.config.pictogram.paths.defaultAvatarFileName
),
address: 'Nice street',
country: 'ES',
email: 'john@doe.com',
phone: '+123456789',
lang: 'ES',
ttsEngine: 'IVONA Text-to-Speech HQ'
}
})
.end(done);
});
it('POST /sup/login', function (done) {
publicAgent.post('/sup/login').send({
email: supervisorAgent.data.email,
password: supervisorAgent.data.password
})
.expect(200)
.end(done);
});
it('POST /sup/activate', function (done) {
publicAgent.post('/sup/activate').send({
email: supervisorAgent.data.email,
code: 1234
})
.expect(200)
.end(done);
});
it('POST /sup/upload', function (done) {
var path = require('path');
supervisorAgent
.post('/sup/upload')
.field('id', supervisorAgent.data.id)
.attach('file', path.join('test', 'test-photo.png'))
.expect(200)
.end(done);
});
it('POST /sup/subscribe');
it('POST /sup/unsubscribe');
});
describe('Try API', function () {
it('PUT /try/:id');
it('POST /try');
});
describe('Working Session API', function () {
it('GET /ws/:id_stu/year/:year');
it('GET /ws/:id_stu/month/:month');
it('GET /ws/:id_ws/tries');
it('POST /workingsession/:id_ws/close');
});
var Agent = require('supertest').agent;
/**
* AuthAgent extends supertest.Agent capabilities, allowing logging in and out
* with some shortcut functions:
*
* agent = new AuthAgent(url, authData, sails.hooks.http.app, callback);
* agent
* .post('/url/post') // This post is made with authentication
* .send({ params }) // You can continue the supertest chain
* .expect(200) // Everything works as normal
* .end();
* });
*
* @param {String} authUrl URL where the authentication should be made
* @param {Object} authData Information send for making the authentication
* @param {expressApp} app Express application where the request will be made to
* @param {function} authDone Function executed when the authentication has been made
*/
function AuthAgent(authUrl, authData, app, authDone) {
var me = this;
Agent.call(this, app);
this.post(authUrl).send(authData).expect(200).end(function (responseError, response) {
me.authToken = response.body.token;
me.data = {};
if (response.body.user) {
me.data = response.body.user;
}
if (authData.password) {
me.data.password = authData.password;
}
authDone();
});
return this;
}
AuthAgent.prototype = new Agent();
AuthAgent.prototype.constructor = AuthAgent;
/**
* If there is an authenticacion token (after logging in),
* embeds it inside the request, and then executes the method specified.
* @param {string} method HTTP method to use
* @param {string} url URL of the request
* @return {request} The request will be the same as if you executed agent.post()
* (or any other method). So you can chain the result as normal.
*/
AuthAgent.prototype._embedAuthToken = function (method, url) {
var request = Agent.prototype[method].call(this, url);
return request.set('Authorization', 'bearer ' + this.authToken);
};
// Here we override the get, put, post and delete methods
// from supertest Agent for embedding the authentication token if necesary
['get', 'put', 'post', 'delete'].forEach(function (method) {
AuthAgent.prototype[method] = function (url) {
return this._embedAuthToken(method, url);
};
});
module.exports = AuthAgent;
/* eslint-disable no-console */
var DATABASE_BACKUP_FILE = '/tmp/pictogram_test_backup.sql';
var UPLOAD_FOLDER = '';
var UPLOAD_FOLDER_BACKUP = '';
var Agent = require('supertest').agent;
var AuthAgent = require('./test-auth-agent');
var chai = require('chai');
var childProcess = require('child_process');
var async = require('async');
var Sails = require('sails').Sails;
var sails;
before(function (serverLoadDone) {
this.timeout(30000);
sails = new Sails();
// Backup the whole database
childProcess.execSync('mysqldump -u pictodbuser -pp1KT015 pictodb > ' + DATABASE_BACKUP_FILE);
sails.lift({}, function (error) {
var bcrypt = require('bcrypt-nodejs');
// Backup the sail's upload folder
UPLOAD_FOLDER = sails.config.pictogram.paths.upload;
UPLOAD_FOLDER_BACKUP = UPLOAD_FOLDER + '.backup';
childProcess.execSync('cp -r ' + UPLOAD_FOLDER + ' ' + UPLOAD_FOLDER_BACKUP);
// Publish chai testing methods
global.assert = chai.assert;
// Populate some defined IDs from the CAJA test
global.cajaIds = {
metaMethod: 1,
method: 1,
instruction: 1
};
// Create the publicAgent, adminAgent, studentAgent and supervisorAgent
// for making the different requests
sails.config.pictogram.admin = {
email: 'testadmin@admin.com',
password: bcrypt.hashSync('1234', bcrypt.genSaltSync())
};
global.publicAgent = new Agent(sails.hooks.http.app);
async.series([
function (callback) {
global.adminAgent = new AuthAgent(
'/admin/login', { email: 'testadmin@admin.com', password: '1234' },
sails.hooks.http.app,
callback
);
},
function (callback) {
global.studentAgent = new AuthAgent(
'/stu/login', { username: 'aaa0002', password: 'aaa0002' },
sails.hooks.http.app,
callback
);
},
function (callback) {
global.supervisorAgent = new AuthAgent(
'/sup/login', { email: 'dofer@ujaen.es', password: 'dofer' },
sails.hooks.http.app,
callback
);
}
], function () {
serverLoadDone(error, error ? undefined : sails);
});
});
});
after(function (done) {
// Restore the database and the upload folder
childProcess.execSync('mysql -u pictodbuser -pp1KT015 pictodb < ' + DATABASE_BACKUP_FILE);
childProcess.execSync('rm ' + DATABASE_BACKUP_FILE);
childProcess.execSync('rm -r ' + UPLOAD_FOLDER);
childProcess.execSync('mv ' + UPLOAD_FOLDER_BACKUP + ' ' + UPLOAD_FOLDER);
sails.lower(done);
});
//
// Tests for AdminController
//
// load supertest, which provides useful methods for HTTP requests
require("sails-test-helper");
describe('AdminController', function() {
describe('/admin/login', function() {
it('should return page not found as method GET is invalid', function(done) {
request
.get('/sup/login')
.expect(404, done);
});
it('should return "user not found" error', function(done) {
request
.post('/admin/login')
.send({email: 'jose@gmail.com', password: 'nonvalidpass'})
.expect(401)
.expect({error: 'User not found'}, done);
});
it('should return "invalid password" error', function(done) {
request
.post('/admin/login')
.send({email: 'amontejo@ujaen.es', password: 'nonvalidpass'})
.expect(401)
.expect({error: 'Invalid password'}, done);
});
it('should return connection token and 200 (ok) status code', function(done) {
request
.post('/admin/login')
.send({email: 'amontejo@ujaen.es', password: 'KaTaCR00.oK'})
.expect('Content-Type', /json/)
.expect(function(res) {
if (!res.body.token) throw new Error('no token received');
})
.expect(200, done);
});
});
});
//
// Tests for OfficeController
//
// load supertest, which provides useful methods for HTTP requests
require("sails-test-helper");
describe('OfficeController', function() {
var token;
describe('/admin/login', function() {
it('should return connection token and 200 (ok) status code', function(done) {
request
.post('/admin/login')
.send({email: 'amontejo@ujaen.es', password: 'KaTaCR00.oK'})
.expect('Content-Type', /json/)
.expect(function(res) {
if (!res.body.token) throw new Error('no token received');
token = res.body.token;
})
.expect(200, done);
});
it('should return a list of four offices', function(done) {
request
.get('/office/get_all?token='+token)
.expect('Content-Type', /json/)
.expect(function(res) {
if (res.body.length != 4) throw new Error('expected 4');
})
.expect(200, done);
});
});
});
require("sails-test-helper");
// describe('StudentController tests', function() {
// describe('GET /', function() {
// it('should be successful', function(done) {
// request
// .get("/sample/tomate")
// .expect(200, done);
// });
// });
// });
//
// Tests for SupervisorController
//
// load supertest, which provides useful methods for HTTP requests
require("sails-test-helper");
describe('SupervisorController', function() {
describe('/sup/login', function() {
it('should return page not found as method GET is invalid', function(done) {
request
.get('/sup/login')
.expect(404, done);
});
it('should return "invalid password" error', function(done) {
request
.post('/sup/login')
.send({email: 'jose@gmail.com', password: 'nonvalidpass'})
.expect(401)
.expect({error: 'Invalid password'}, done);
});
it('should return user information, connection token and 200 (ok) status code', function(done) {
request
.post('/sup/login')
.send({email: 'antonio@gmail.com', password: '1234'})
.expect('Content-Type', /json/)
.expect(function(res) {
if (res.body.user.name != 'Antonio') throw new Error('invalid user info received');
if (!res.body.token) throw new Error('no token received');
console.log(res.body.token);
})
.expect(200, done);
});
});
});
<!DOCTYPE html>
<!--
444444444 000000000 333333333333333
4::::::::4 00:::::::::00 3:::::::::::::::33
4:::::::::4 00:::::::::::::00 3::::::33333::::::3
4::::44::::4 0:::::::000:::::::03333333 3:::::3
4::::4 4::::4 0::::::0 0::::::0 3:::::3
4::::4 4::::4 0:::::0 0:::::0 3:::::3
4::::4 4::::4 0:::::0 0:::::0 33333333:::::3
4::::444444::::4440:::::0 000 0:::::0 3:::::::::::3
4::::::::::::::::40:::::0 000 0:::::0 33333333:::::3
4444444444:::::4440:::::0 0:::::0 3:::::3
4::::4 0:::::0 0:::::0 3:::::3
4::::4 0::::::0 0::::::0 3:::::3
4::::4 0:::::::000:::::::03333333 3:::::3
44::::::44 00:::::::::::::00 3::::::33333::::::3
4::::::::4 00:::::::::00 3:::::::::::::::33
4444444444 000000000 333333333333333
This is the default "403: Forbidden" page.
User agents that don't "Accept" HTML will see a JSON version instead.
You can customize the control logic for your needs in `config/403.js`
You can trigger this response from one of your controllers or policies with:
`return res.forbidden( msg );`
(where `msg` is an optional error message to include in the response)
-->
<html>
<head>
<title>Forbidden</title>
<link href='http://sailsjs.org/styles/fonts.css' rel='stylesheet'/>
<style>
/* Styles included inline since you'll probably be deleting or replacing this page anyway */
html,body{text-align:left;font-size:1em}html,body,img,form,textarea,input,fieldset,div,p,div,ul,li,ol,dl,dt,dd,h1,h2,h3,h4,h5,h6,pre,code{margin:0;padding:0}ul,li{list-style:none}img{display:block}a img{border:0}a{text-decoration:none;font-weight:normal;font-family:inherit}*:active,*:focus{outline:0;-moz-outline-style:none}h1,h2,h3,h4,h5,h6,h7{font-weight:normal;font-size:1em}.clearfix:after{clear:both;content:".";display:block;font-size:0;height:0;line-height:0;visibility:hidden}.page .ocean{background:url('http://sailsjs.com/images/waves.png') #0c8da0 no-repeat center 0;height:315px}.page .ocean img{margin-right:auto;margin-left:auto}.page .waves{display:block;padding-top:25px;margin-right:auto;margin-left:auto}.page .main{display:block;margin-top:90px}.page .logo{width:150px;margin-top:3.5em;margin-left:auto;margin-right:auto}.page .fishy{display:block;padding-top:100px}.page .help{padding-top:2em}.page h1{font-family:"Open Sans","Myriad Pro",Arial,sans-serif;font-weight:bold;font-size:1.7em;color:#001c20;text-align:center}.page h2{font-family:"Open Sans","Myriad Pro",Arial,sans-serif;font-weight:300;font-size:1.5em;color:#001c20;text-align:center}.page p{font-family:"Open Sans","Myriad Pro",Arial,sans-serif;font-size:1.25em;color:#001c20;text-align:center}.page a{color:#118798}.page a:hover{color:#b1eef7}
</style>
</head>
<body>
<div class="page">
<div class="ocean">
<img class="fishy" src="http://sailsjs.com/images/image_devInTub.png">
</div>
<div class="main">
<h1>
Forbidden
</h1>
<h2>
<% if (typeof error !== 'undefined') { %>
<%= error %>
<% } else { %>
You don't have permission to see the page you're trying to reach.
<% } %>
</h2>
<p class="help">
<a href="http://en.wikipedia.org/wiki/HTTP_403">Why</a> might this be happening?
</p>
</div>
<div class="logo">
<a href="http://sailsjs.org">
<img src="http://sailsjs.org/images/logo.png">
</a>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<!--
444444444 000000000 444444444
4::::::::4 00:::::::::00 4::::::::4
4:::::::::4 00:::::::::::::00 4:::::::::4
4::::44::::4 0:::::::000:::::::0 4::::44::::4
4::::4 4::::4 0::::::0 0::::::0 4::::4 4::::4
4::::4 4::::4 0:::::0 0:::::0 4::::4 4::::4
4::::4 4::::4 0:::::0 0:::::0 4::::4 4::::4
4::::444444::::4440:::::0 000 0:::::04::::444444::::444
4::::::::::::::::40:::::0 000 0:::::04::::::::::::::::4
4444444444:::::4440:::::0 0:::::04444444444:::::444
4::::4 0:::::0 0:::::0 4::::4
4::::4 0::::::0 0::::::0 4::::4
4::::4 0:::::::000:::::::0 4::::4
44::::::44 00:::::::::::::00 44::::::44
4::::::::4 00:::::::::00 4::::::::4
4444444444 000000000 4444444444
This is the default "404: Not Found" page.
User agents that don't "Accept" HTML will see a JSON version instead.
You can customize the control logic for your needs in `config/404.js`
Sails considers a request to be in a "404: Not Found" state when a user
requests a URL which doesn't match any of your app's routes or blueprints.
You can also trigger this response from one of your controllers or policies with:
`return res.notFound();`
-->
<html>
<head>
<title>Page Not Found</title>
<link href='http://sailsjs.org/styles/fonts.css' rel='stylesheet'/>
<style>
/* Styles included inline since you'll probably be deleting this page anyway */
html,body{text-align:left;font-size:1em}html,body,img,form,textarea,input,fieldset,div,p,div,ul,li,ol,dl,dt,dd,h1,h2,h3,h4,h5,h6,pre,code{margin:0;padding:0}ul,li{list-style:none}img{display:block}a img{border:0}a{text-decoration:none;font-weight:normal;font-family:inherit}*:active,*:focus{outline:0;-moz-outline-style:none}h1,h2,h3,h4,h5,h6,h7{font-weight:normal;font-size:1em}.clearfix:after{clear:both;content:".";display:block;font-size:0;height:0;line-height:0;visibility:hidden}.fourohfour .ocean{background:url('http://sailsjs.com/images/waves.png') #0c8da0 no-repeat center 0;height:315px}.fourohfour .ocean img{margin-right:auto;margin-left:auto}.fourohfour .waves{display:block;padding-top:25px;margin-right:auto;margin-left:auto}.fourohfour .main{display:block;margin-top:90px}.fourohfour .logo{width:150px;margin-top:3.5em;margin-left:auto;margin-right:auto}.fourohfour .fishy{display:block;padding-top:27px}.fourohfour .help{padding-top:2em}.fourohfour h1{font-family:"Open Sans","Myriad Pro",Arial,sans-serif;font-weight:bold;font-size:1.7em;color:#001c20;text-align:center}.fourohfour h2{font-family:"Open Sans","Myriad Pro",Arial,sans-serif;font-weight:300;font-size:1.5em;color:#001c20;text-align:center}.fourohfour p{font-family:"Open Sans","Myriad Pro",Arial,sans-serif;font-size:1.25em;color:#001c20;text-align:center}.fourohfour a{color:#118798}.fourohfour a:hover{color:#b1eef7}
</style>
</head>
<body>
<div class="fourohfour">
<div class="ocean">
<img class="fishy" src="http://sailsjs.org/images/fishy4.png">
</div>
<div class="main">
<h1>
Something's fishy here.
</h1>
<h2>
<% if (typeof error!== 'undefined') { %>
<%= error %>
<% } else { %>
The page you were trying to reach doesn't exist.
<% } %>
</h2>
<p class="help">
<a href="http://en.wikipedia.org/wiki/HTTP_404">Why</a> might this be happening?
</p>
</div>
<div class="logo">
<a href="http://sailsjs.org">
<img src="http://sailsjs.org/images/logo.png">
</a>
</div>
</div>
</body>
</html>
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