Commit fb7fb727 by Fernando Martínez Santiago

working on PCB bugs: upload imgs from PCB(I)

parents 2b1dfc05 e58cd715
Showing with 584 additions and 838 deletions
......@@ -16,7 +16,7 @@ Para comprobar que todo funciona correctamente se ha habilitado un servidor con
comprueba que el código está bien escrito y funciona correctamente (actualmente sólo para el
código JavaScript). Datos del servidor:
- Dirección: [ararat.ujaen.es:9537][5]
- Dirección: [ararat.ujaen.es][5]
- Usuario: `uruk`
- Contraseña: `saruman es et`
......@@ -27,4 +27,4 @@ código JavaScript). Datos del servidor:
[2]: /softuno/pictogram/tree/develop/sails
[3]: /softuno/pictogram/tree/develop/sails/src/assets/app
[4]: /softuno/pictogram/tree/develop/android/Pictogram
[5]: http://ararat.ujaen.es:9537/job/pictogram-dev/
[5]: https://ararat.ujaen.es/jenkins
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="10daeba4-0692-476d-a3da-642b4123cfdd" name="Default" comment="">
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
</list>
<list default="true" id="10daeba4-0692-476d-a3da-642b4123cfdd" name="Default" comment="" />
<ignored path="android.iws" />
<ignored path=".idea/workspace.xml" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
......@@ -38,10 +36,10 @@
</option>
</component>
<component name="ProjectFrameBounds">
<option name="x" value="44" />
<option name="y" value="23" />
<option name="width" value="1397" />
<option name="height" value="877" />
<option name="x" value="65" />
<option name="y" value="24" />
<option name="width" value="1615" />
<option name="height" value="1026" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
<OptionsSetting value="true" id="Add" />
......@@ -57,7 +55,7 @@
<option name="STATE" value="0" />
</component>
<component name="ProjectView">
<navigator currentView="ProjectPane" proportions="" version="1">
<navigator currentView="Scope" currentSubView="Project Files" proportions="" version="1">
<flattenPackages />
<showMembers />
<showModules />
......@@ -71,9 +69,6 @@
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="AndroidView">
<subPane />
</pane>
<pane id="ProjectPane">
<subPane>
<PATH>
......@@ -84,10 +79,13 @@
</PATH>
</subPane>
</pane>
<pane id="PackagesPane">
<subPane />
</pane>
<pane id="Scope">
<subPane subId="Project Files" />
</pane>
<pane id="PackagesPane">
<pane id="AndroidView">
<subPane />
</pane>
<pane id="Scratches" />
......@@ -295,7 +293,7 @@
<servers />
</component>
<component name="ToolWindowManager">
<frame x="44" y="23" width="1397" height="877" extended-state="0" />
<frame x="65" y="24" width="1615" height="1026" extended-state="6" />
<editor active="false" />
<layout>
<window_info id="Palette&#9;" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
......@@ -303,8 +301,8 @@
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.2494465" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.1744186" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24905898" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.17440401" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
......@@ -314,19 +312,19 @@
<window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Android Monitor" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="true" content_ui="tabs" />
<window_info id="Gradle Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="true" content_ui="tabs" />
<window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Memory Monitor" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Android Model" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="true" content_ui="tabs" />
<window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Android Model" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="true" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Captures" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
</layout>
</component>
......
......@@ -38,37 +38,32 @@ android {
resValue "integer", "rows", "5"
resValue "integer", "columns", "10"
}
}
productFlavors {
fernandoFlavor {
resValue "string", "server", "https://pre.yottacode.com"
FernandoFlavor {
resValue "string", "server", "https://127.0.0.1:9944"
applicationId "com.yottacode.pictogrammar"
}
ArturoFlavor {
}
LocalFlavor {
resValue "string", "server", "https://192.168.1.37:1337"
}
DevFlavor {
resValue "string", "server", "https://dev.yottacode.com"
}
DefaultFlavor {
resValue "string", "server", "https://pre.yottacode.com"
signingConfig signingConfigs.release_config
}
ArturoFlavorNoSSL {
resValue "string", "server", "http://192.168.1.37:1337"
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.google.android.gms:play-services:6.5.87'
compile 'com.android.support:appcompat-v7:21.0.3'
compile 'com.github.nkzawa:socket.io-client:0.5.0'
compile 'com.koushikdutta.async:androidasync:2.+'
compile 'com.android.support:support-v4:21.0.+'
compile 'com.koushikdutta.ion:ion:2.+'
//required for upload images
fernandoFlavorCompile files('src/fernandoFlavor/libs/jpgf.jar')
fernandoFlavorCompile fileTree(dir: 'libs')
}
compile 'com.koushikdutta.ion:ion:2.+' //required for upload images
}
#Thu May 26 14:03:38 CEST 2016
#Mon Jun 06 22:38:39 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
......
......@@ -2,11 +2,11 @@
echo "-- Running pictogram server"
if [ -e "src/app.js" ]; then
cd src && npm start
cd src && forever start app.js --debug
elif [ -e "/vagrant/src/app.js" ]; then
cd /vagrant/src && npm start
cd /vagrant/src && forever start app.js --debug
elif [ -e "/home/vagrant/sync/src/app.js" ]; then
cd /home/vagrant/sync/src && npm start
cd /home/vagrant/sync/src && forever start app.js --debug
else
echo "-- app.js not found, cannot run pictogram server"
exit
......
......@@ -6,3 +6,4 @@
roles:
- webapp
- server
......@@ -10,9 +10,9 @@ Los ficheros SQL que importará este rol son los siguientes:
- [init-ignoresymbolstix][2] realiza el mismo proceso que [init][1], pero manteniendo
los datos almacenados por symbolstx.
- [pictodb-schema][3] contiene el esquema de la base de datos.
- [pictodb-data][4] contiene la información básica que la aplicación necesita para funcionar.
- [symbolstx-categories][5] añade las categorías de symbolstx.
- [symbolstix-metadata][6] añade traducciones para symbolstx.
- [pictodb-data][4] contiene la información básica que la aplicación necesita para funcionar. Añade información a las tablas `meta_method`, `meta_instruction`, `source`, `picto_core` y `picto_exp`.
- [symbolstx-categories][5] añade las categorías de symbolstx en las tablas `pictocat` y `catexp`.
- [symbolstix-metadata][6] añade traducciones para symbolstx y los pictos (tablas `picto_exp`, `picto_tag` y `picto`).
- [triggers-enrolments-integrity-constraints][7] añade disparadores para el control de
integridad de inscripciones.
- [triggers-sessions-integrity-constraints][8] añade disparadores para el control de integridad
......
--
-- All data is deleted from the database except symbolstix tables and basic metadata
-- Afterwords, test data can be loaded
--
--
-- TO BE DONE!!!
SET foreign_key_checks=0;
SET @TRIGGER_CHECKS=FALSE;
DELETE FROM picto_tag WHERE `id_sup` IS NOT NULL;
DELETE FROM picto WHERE `id_owner` IS NOT NULL;
TRUNCATE office;
TRUNCATE supervisor;
TRUNCATE student;
TRUNCATE stu_sup;
TRUNCATE stu_picto;
TRUNCATE method;
TRUNCATE instruction;
TRUNCATE try;
TRUNCATE working_session;
DROP TRIGGER IF EXISTS TRG_NEW_STUDENT_MAXENROLMENTS;
DROP TRIGGER IF EXISTS TRG_NEW_STUDENT_UPDATE_ENROLMENTS;
DROP TRIGGER IF EXISTS TRG_MODIFY_STUDENT_ENROLMENTS;
DROP TRIGGER IF EXISTS TRG_DELETE_STUDENT_ENROLMENTS;
DROP TRIGGER IF EXISTS TRG_SESSION_NEW;
DROP TRIGGER IF EXISTS TRG_SESSION_CLOSED;
DROP TRIGGER IF EXISTS TRG_NEW_EVENT_ONSESSION;
DROP TRIGGER IF EXISTS TRG_NEW_EVENT;
DROP TRIGGER IF EXISTS TRG_SESSION_CLOSING;
DROP TRIGGER IF EXISTS TRG_TRY_EVALUATED;
SET @TRIGGER_CHECKS=TRUE;
SET foreign_key_checks=1;
......@@ -51,10 +51,10 @@ INSERT INTO `source` (`id`, `name`, `description`) VALUES
SET foreign_key_checks=0;
--
-- Volcado de datos para la tabla `picto_core_cat`
-- Volcado de datos para la tabla `picto_core`
--
INSERT INTO `picto_core_cat` (`id`, `id_pic`, `id_cat_pic`, `coord_x`, `coord_y`,`color`) VALUES
INSERT INTO `picto_core` (`id`, `id_pic`, `id_cat_pic`, `coord_x`, `coord_y`,`color`) VALUES
(1, 2982, NULL, 0, 0, NULL), -- yes
(2, 4391, NULL, 0, 1, NULL), -- no
(3, 2284, NULL, 0, 2, NULL), -- please
......
The file could not be displayed because it is too large.
......@@ -6,7 +6,7 @@ SET foreign_key_checks = 0;
-- Oficina Autismo Jaen
--
INSERT INTO `office` (
INSERT IGNORE INTO `office` (
`name`,
`address`,
`country`,
......@@ -29,7 +29,7 @@ INSERT INTO `office` (
-- La contraseña es la primera parte del email (ej: manuel.colmenero)
--
INSERT INTO `supervisor` (
INSERT IGNORE INTO `supervisor` (
`name`,
`surname`,
`gender`,
......@@ -65,7 +65,7 @@ UPDATE office
-- La contraseña es la primera parte del email (ej: manuel.colmenero)
--
INSERT INTO `supervisor` (
INSERT IGNORE INTO `supervisor` (
`name`,
`surname`,
`gender`,
......@@ -116,7 +116,7 @@ INSERT INTO `supervisor` (
-- La contraseña es la primera parte del email (ej: manuel.colmenero)
--
INSERT INTO `supervisor` (
INSERT IGNORE INTO `supervisor` (
`name`,
`surname`,
`gender`,
......@@ -163,7 +163,7 @@ INSERT INTO `supervisor` (
-- La contraseña es el nombre de usuario
--
INSERT INTO `student` (
INSERT IGNORE INTO `student` (
`username`,
`password`,
`name`,
......@@ -287,7 +287,7 @@ INSERT INTO `student` (
-- Student pictos
--
INSERT INTO `stu_picto` (
INSERT IGNORE INTO `stu_picto` (
`id_stu`,
`id_pic`,
`attributes`
......@@ -300,7 +300,7 @@ SELECT S.id, P.id_pic, concat('{',
',"highlight":false',
',"color":', if (P.color is null, 'null', concat('"', P.color,'"')),
'}') as attributes
FROM student S, picto_core_cat P
FROM student S, picto_core P
WHERE
S.id_off=(SELECT id
FROM office
......
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
SET foreign_key_checks = 0;
SET @TRIGGER_CHECKS = FALSE;
--
-- Oficina
......@@ -394,7 +395,7 @@ SELECT S.id,P.id_pic, concat('{"id_cat":', if (id_cat_pic is null, 'null',id_cat
',"highlight":false',
',"color":', if (color is null, 'null',concat('"',color,'"')),
'}') as attributes
FROM student S, picto_core_cat P
FROM student S, picto_core P
WHERE S.id_off =(SELECT id from office where name='Comunicación Aumentativa JAén (CAJA)');
--
......@@ -417,4 +418,5 @@ INSERT INTO working_session (id_sup, id_ins) VALUES (
(SELECT id FROM instruction WHERE name='Test Instruction')
);
SET @TRIGGER_CHECKS = TRUE;
SET foreign_key_checks=1;
......@@ -5,11 +5,20 @@ DELIMITER ;;
-- Integrity rule 1: It is not possible to enrol a higer number of student than office.max_enrolments
DROP TRIGGER IF EXISTS TRG_NEW_STUDENT_MAXENROLMENTS;
CREATE TRIGGER TRG_NEW_STUDENT_MAXENROLMENTS
BEFORE INSERT ON student
FOR EACH ROW
BEGIN
DECLARE max_enr,curr_enr INT;
thisTrigger: BEGIN
DECLARE max_enr,curr_enr INT;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_BEFORE_INSERT_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
IF new.id_off IS NOT NULL THEN
SELECT
max_students, current_students INTO max_enr, curr_enr
......@@ -27,10 +36,17 @@ BEGIN
END;;
-- Integrity rule 2: office.current_enrolments updating
DROP TRIGGER IF EXISTS TRG_NEW_STUDENT_UPDATE_ENROLMENTS;
CREATE TRIGGER TRG_NEW_STUDENT_UPDATE_ENROLMENTS
AFTER INSERT ON student
FOR EACH ROW
BEGIN
thisTrigger: BEGIN
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_INSERT_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
UPDATE
office
......@@ -41,10 +57,18 @@ BEGIN
END;;
-- Integrity rule 3: office.current_enrolments and supervisor assigments updating.
DROP TRIGGER IF EXISTS TRG_MODIFY_STUDENT_ENROLMENTS;
CREATE TRIGGER TRG_MODIFY_STUDENT_ENROLMENTS
AFTER UPDATE ON student
FOR EACH ROW
BEGIN
thisTrigger: BEGIN
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_UPDATE_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
IF NOT (old.id_off<=>new.id_off) THEN
IF (old.id_off IS NOT NULL) THEN
UPDATE
......@@ -72,10 +96,18 @@ BEGIN
END;;
-- Integrity rule 4: office.current_enrolments when deleting student. Note that is not required to delete stu_sup because stu_sup.id_stu is a foreign key of student
DROP TRIGGER IF EXISTS TRG_DELETE_STUDENT_ENROLMENTS;
CREATE TRIGGER TRG_DELETE_STUDENT_ENROLMENTS
AFTER DELETE ON student
FOR EACH ROW
BEGIN
thisTrigger: BEGIN
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_DELETE_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
IF old.id_off IS NULL THEN
UPDATE
office
......
......@@ -7,28 +7,30 @@ DELIMITER ;;
--
-- Get the current try for a given session by reading disk-based tables only
--
DROP FUNCTION IF EXISTS getOpenTry;
CREATE FUNCTION getOpenTry(idstu INT)
RETURNS INT
READS SQL DATA
BEGIN
DECLARE id_opentry INT;
DECLARE id_opentry INT;
SELECT T.id INTO id_opentry
FROM
FROM
try T,
working_session WS,
instruction I,
method M
WHERE
T.id_ws=WS.id AND
WS.id_ins=I.id AND
WHERE
T.id_ws=WS.id AND
WS.id_ins=I.id AND
I.id_met=M.id AND
M.id_stu=idstu AND T.end IS NULL;
return id_opentry;
return id_opentry;
END;;
--
-- Memory table in order to recover data about current working sessions
--
DROP TABLE IF EXISTS stu_opentry;
CREATE TABLE stu_opentry (
id int(11) NOT NULL AUTO_INCREMENT,
id_stu int(11) NOT NULL,
......@@ -51,12 +53,13 @@ FOREIGN KEY (id_ws) REFERENCES working_session(id) ON DELETE CASCADE
-- It creates a new try and notes down the try into the STU_OPENTRY memory table
-- additional notes: For the sake of efficiency, memory table STU_OPENTRY is updated
--
DROP PROCEDURE IF EXISTS newTry;
CREATE PROCEDURE newTry(idstu INT, idsup INT, idws INT)
MODIFIES SQL DATA
BEGIN
DECLARE idopentry int;
INSERT INTO try(`id_ws`)
INSERT INTO try(`id_ws`)
VALUES (idws);
SET idopentry=LAST_INSERT_ID();
......@@ -67,45 +70,54 @@ BEGIN
idws,
idopentry,
0,
NOW()
NOW()
)
ON DUPLICATE KEY UPDATE id_stu=idstu, id_sup=idsup, id_ws=idws, id_opentry=idopentry;
ON DUPLICATE KEY UPDATE id_stu=idstu, id_sup=idsup, id_ws=idws, id_opentry=idopentry;
END;;
--
-- It deletes current try for a given session
DROP PROCEDURE IF EXISTS deleteOpenTry;
CREATE PROCEDURE deleteOpenTry(ws INT)
BEGIN
BEGIN
DECLARE idopentry INT;
SELECT id_opentry INTO idopentry
FROM
FROM
stu_opentry
WHERE
id_ws = ws;
IF (idopentry IS NOT NULL) THEN
DELETE FROM try
WHERE id = idopentry;
WHERE
id_ws = ws;
IF (idopentry IS NOT NULL) THEN
DELETE FROM try
WHERE id = idopentry;
END IF;
END;;
-- Integrity rule 1: A new session begins and in turn a new try is created
-- Integrity rule 8: Any instruction with a new session has a "started" state
-- when: state COM, event a2
DROP TRIGGER IF EXISTS TRG_SESSION_NEW;
CREATE TRIGGER TRG_SESSION_NEW
AFTER INSERT ON working_session
FOR EACH ROW
BEGIN
thisTrigger: BEGIN
DECLARE idstu INT;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_INSERT_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
SELECT DISTINCT M.id_stu INTO idstu
FROM
FROM
instruction I,
method M
WHERE
I.id=new.id_ins AND
WHERE
I.id=new.id_ins AND
I.id_met=M.id;
UPDATE instruction
SET status='started'
WHERE id=new.id_ins;
......@@ -113,15 +125,23 @@ BEGIN
CALL newTry(idstu, new.id_sup, new.id);
END;;
-- Integrity rule 2: when a session is closed, last try must be discharged
-- when: state COM, event a4
-- current is to NULL (integrity rule 6)
--
DROP TRIGGER IF EXISTS TRG_SESSION_CLOSED;
CREATE TRIGGER TRG_SESSION_CLOSED
AFTER UPDATE ON working_session
FOR EACH ROW
BEGIN
thisTrigger: BEGIN
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_UPDATE_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
IF ((old.end IS NULL) and (new.end IS NOT NULL)) THEN
CALL deleteOpenTry(new.id);
END IF;
......@@ -131,118 +151,133 @@ END;;
-- Integrity rule 3: every event is required to have the id try whenver a try happens
-- when: state COM, event a4
--
DROP TRIGGER IF EXISTS TRG_NEW_EVENT_ONSESSION;
CREATE TRIGGER TRG_NEW_EVENT_ONSESSION
BEFORE INSERT ON action
FOR EACH ROW
BEGIN
thisTrigger: BEGIN
DECLARE idstu INT;
DECLARE idtry INT;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_BEFORE_INSERT_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
SET idstu=NEW.id_stu;
SELECT id_opentry INTO idtry
FROM
FROM
stu_opentry
WHERE
id_stu = idstu;
WHERE
id_stu = idstu;
IF (idtry IS NOT NULL) THEN
SET NEW.id_try=idtry;
END IF;
END;;
-- Integrity rule 7: when a sentence is finished, previous try is closed
-- Integrity rule 7: when a sentence is finished, previous try is closed
-- and new try is created in case of working session happening
-- when: state COM, event a4
-- Integrity rule 5: when a session is continued after a pause and new try is created
-- when: state PAU, event a3
-- when: state COM, event a4
-- Integrity rule 5: when a session is continued after a pause and new try is created
-- when: state PAU, event a3
-- Integrity rule 4: when a session is paused, last try must be discharged
-- when: state SES, event a3
-- when: state SES, event a3
DROP TRIGGER IF EXISTS TRG_NEW_EVENT;
CREATE TRIGGER TRG_NEW_EVENT
AFTER INSERT ON action
FOR EACH ROW
BEGIN
thisTrigger: BEGIN
DECLARE idopentry INT;
DECLARE idsup_ws INT;
DECLARE idws INT;
DECLARE idsup_ws INT;
DECLARE idws INT;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_INSERT_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
CASE NEW.type
WHEN 'Show' THEN
WHEN 'Show' THEN
SELECT id_ws, id_sup, id_opentry INTO idws, idsup_ws, idopentry
FROM
FROM
stu_opentry
WHERE
id_stu = NEW.id_stu;
IF (idopentry IS NOT NULL and NEW.id_sup IS NULL) THEN
WHERE
id_stu = NEW.id_stu;
IF (idopentry IS NOT NULL and NEW.id_sup IS NULL) THEN
UPDATE `try`
SET end=NOW()
WHERE id=idopentry;
SET end=NOW()
WHERE id=idopentry;
call newTry(new.id_stu, idsup_ws, idws);
END IF;
WHEN 'Pause' THEN
END IF;
WHEN 'Pause' THEN
SELECT id_ws, id_opentry INTO idws, idopentry
FROM
stu_opentry
WHERE
id_stu = NEW.id_stu;
IF (idopentry IS NULL) THEN
id_stu = NEW.id_stu;
IF (idopentry IS NULL) THEN
call newTry(new.id_stu, new.id_sup,idws);
ELSE
call deleteOpenTry(idws);
END IF;
ELSE BEGIN END;
END CASE;
ELSE
call deleteOpenTry(idws);
END IF;
ELSE BEGIN END;
END CASE;
END;;
-- Integrity rule 6: It is not possible to open a new session when a previous session is opened for a given supervisor
-- when: state SES and PAU, event a2
--
ALTER TABLE `working_session`
ADD CONSTRAINT `idx_ws_supcur` UNIQUE (id_sup, current);;
-- Integrity rule 2: when a session is closed, last try must be discharged
-- when: state COM, event a4
-- current is to NULL (integrity rule 6)
--
DROP TRIGGER IF EXISTS TRG_SESSION_CLOSING;
CREATE TRIGGER TRG_SESSION_CLOSING
BEFORE UPDATE ON working_session
FOR EACH ROW
BEGIN
IF ((new.end IS NOT NULL) AND (new.current IS NOT NULL)) THEN
thisTrigger: BEGIN
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_BEFORE_UPDATE_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
IF ((new.end IS NOT NULL) AND (new.current IS NOT NULL)) THEN
SET new.current=NULL;
END IF;
END IF;
END;;
-- Integrity rule 8: Every action requires a valid try or null
-- when: state SES, event a3 and a5
--
ALTER TABLE `action`
ADD CONSTRAINT `fk_try_act` FOREIGN KEY (`id_try`) REFERENCES `try` (`id`) ON DELETE SET NULL;;
--
-- Required for not closed sessions policy retrieving
--
DROP TRIGGER IF EXISTS TRG_TRY_EVALUATED;
CREATE TRIGGER TRG_TRY_EVALUATED
AFTER UPDATE ON try
FOR EACH ROW
BEGIN
DECLARE idopentry INT;
DECLARE idws INT;
DECLARE ws_end DATE;
thisTrigger: BEGIN
DECLARE idopentry INT;
DECLARE idws INT;
DECLARE ws_end DATE;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_UPDATE_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
SELECT id_ws, id_opentry,end INTO idws, idopentry, ws_end
FROM
stu_opentry
WHERE
id_ws = NEW.id_ws;
id_ws = NEW.id_ws;
IF ( (old.result IS NULL) and (new.result IS NOT NULL) and (new.end>ws_end)) THEN
UPDATE stu_opentry
SET end=new.end, total_tries=total_tries+1
WHERE id_ws=idws;
END IF;
END IF;
END;;
DELIMITER ;
......@@ -7,6 +7,7 @@
name: all
state: import
target: "{{ server_path }}/{{ database_files_relative_path }}/init.sql"
tags: reset-test-database
- name: Imports the pictodb Schema
mysql_db:
......@@ -15,6 +16,8 @@
name: "{{ database_name }}"
state: import
target: "{{ server_path }}/{{ database_files_relative_path }}/pictodb-schema.sql"
tags:
- reset-test-database
- name: Imports symbolstx categories and metadata
mysql_db:
......@@ -23,6 +26,8 @@
name: "{{ database_name }}"
state: import
target: "{{ server_path }}/{{ database_files_relative_path }}/symbolstx-{{ item }}.sql"
tags:
- reset-test-database
with_items:
- categories
- metadata
......@@ -34,6 +39,8 @@
name: "{{ database_name }}"
state: import
target: "{{ server_path }}/{{ database_files_relative_path }}/pictodb-data.sql"
tags:
- reset-test-database
- name: Imports selected tests
mysql_db:
......@@ -42,6 +49,8 @@
name: "{{ database_name }}"
state: import
target: "{{ server_path }}/{{ database_files_relative_path }}/test-{{ item }}.sql"
tags:
- reset-test-database
with_items: "{{ database_tests }}"
- name: Creates triggers
......@@ -51,6 +60,8 @@
name: "{{ database_name }}"
state: import
target: "{{ server_path }}/{{ database_files_relative_path }}/triggers-{{ item }}.sql"
tags:
- reset-test-database
with_items:
- enrolments-integrity-constraints
- sessions-integrity-constraints
......@@ -4,4 +4,4 @@ database_root_passwd: root
database_name: pictodb
database_user: pictodbuser
database_user_passwd: p1KT015
database_tests: [caja, autismojaen] # can be empty
database_tests: [caja] #[caja, autismojaen] # can be empty
/* global sails, Picto, Supervisor, PictoCat, PictoTagSup, PictoExp */
/* global sails, Picto, Supervisor, PictoCat, PictoTag, PictoExp */
/**
* PictoController
......@@ -125,14 +125,14 @@ module.exports = {
throw new Error('Picto not found');
}
PictoTagSup.create({
PictoTag.create({
tag: params.tag,
lang: params.lang,
picto: picto.id,
supervisor: supervisor.id
}).then(function (pictoTagSup) {
if (pictoTagSup) {
res.ok(pictoTagSup);
}).then(function (pictoTag) {
if (pictoTag) {
res.ok(pictoTag);
} else {
res.serverError();
}
......@@ -153,16 +153,19 @@ module.exports = {
/**
* Removes a picto tag created by the supervisor
* @param {request} req {} (with pictoTagId specified in parameters)
* @param {request} {
* "id_tag": 1234,
* "id_sup": 123
* }
* @param {response} res {}
*/
del_tag: function (req, res) {
var params = req.params.all();
if (!params.id_tag) {
if (!params.id_tag || !params.id_sup) {
res.badRequest();
} else {
PictoTagSup.destroy({ id: params.id_tag }).then(function () {
PictoTag.destroy({ id: params.id_tag, id_sup: params.id_sup }).then(function () {
res.ok();
})
.catch(function () {
......@@ -171,17 +174,26 @@ module.exports = {
}
},
// Destroy don't delete the picto, it removes the owner to students still having it
/**
* Destroy don't delete the picto, it removes the link to students
* @param {request} {
* "id": 2343
* }
* @param {response} res {}
*/
destroy: function(req, res) {
var params = req.params.all();
if (!params.id) {
return res.json(500, {error: "No id picto defined"});
}
Picto.update({ id: params.id }, { owner: null}).exec(function (err, updated) {
if (err) throw err;
return res.json(updated[0]);
});
res.badRequest();
} else {
Picto.update({ id: params.id }, { owner: null}).then(function (updated) {
res.ok(updated[0]);
})
.catch(function() {
res.serverError();
});
}
},
/**
......
/* global Student, PictoCoreCat, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails,
/* global Student, PictoCore, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails,
Picto */
/**
......@@ -41,7 +41,6 @@ module.exports = {
*/
login: function (req, res) {
var bcrypt = require('bcrypt-nodejs');
Student.findOne({
username: req.body.username
})
......@@ -113,7 +112,7 @@ module.exports = {
}
res.ok(student);
})
.catch(function () {
.catch(function (error) {
res.serverError();
});
} else {
......@@ -141,34 +140,34 @@ module.exports = {
sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created));
// Assign the initial collection of pictos to the student
PictoCoreCat.find()
.exec(function (pictoCoreCatError, pictoCoreCat) {
PictoCore.find()
.exec(function (pictoCoreError, pictoCore) {
var i;
if (pictoCoreCatError || !pictoCoreCat || pictoCoreCat.length === 0) {
sails.log.debug('PictoCoreCat: ' + pictoCoreCatError);
if (pictoCoreError || !pictoCore || pictoCore.length === 0) {
sails.log.debug('PictoCore: ' + pictoCoreError);
return;
}
sails.log.debug('PictoCoreCat Length: ' + pictoCoreCat.length);
sails.log.debug(pictoCoreCat);
sails.log.debug('PictoCore Length: ' + pictoCore.length);
sails.log.debug(pictoCore);
// Every picto from 'picto_core_cat' is going to be created
// in 'stu_picto'
for (i = 0; i < pictoCoreCat.length; i++) {
for (i = 0; i < pictoCore.length; i++) {
sails.log.debug('Loop: ' + i);
sails.log.debug('Picto Category: ' + pictoCoreCat[i].category);
sails.log.debug('Picto Category: ' + pictoCore[i].category);
sails.log.debug('User id: ' + created.id);
StuPicto.create({
student: created.id,
picto: pictoCoreCat[i].picto,
picto: pictoCore[i].picto,
attributes: {
id_cat: pictoCoreCat[i].category,
coord_x: pictoCoreCat[i].coord_x,
coord_y: pictoCoreCat[i].coord_y,
id_cat: pictoCore[i].category,
coord_x: pictoCore[i].coord_x,
coord_y: pictoCore[i].coord_y,
status: 'invisible', // Default, the pictos don't appear to the user
color: pictoCoreCat[i].color
color: pictoCore[i].color
}
})
.exec(function (stuPictoError, added) {
......@@ -217,34 +216,30 @@ module.exports = {
// Updates student information
//
update: function (req, res) {
if (!req.params.id_stu) {
return res.json(500, {
error: 'No student defined'
});
res.badRequest();
}
Student.findOne(req.params.id_stu)
.exec(function (err, stu) {
var k;
if (err || !stu)
return res.json(500, {
error: "No student found"
});
if (!req.body.password) {
delete req.body.password;
}
Student.findOne(req.params.id_stu).then(function(stu) {
var k;
// copy attributes
for (k in req.body) stu[k] = req.body[k];
stu.save(function (stuSaveError, saved) {
if (stuSaveError) {
return res.json(500, {
error: 'Error when saving student'
});
}
return res.json(stu);
});
// copy attributes
for (k in req.body) stu[k] = req.body[k];
if (!req.body.password) // to avoid change password when no one is provided
delete stu.password;
stu.save().then(function (saved) {
res.ok(stu);
})
.catch(function(err) {
res.severError();
});
})
.catch(function (err) {
res.notFound();
});
},
......@@ -947,26 +942,13 @@ module.exports = {
var action = req.param('action');
var attributes = req.param('attributes');
var roomName = 'studentRoom' + attributes.id_stu;
sails.log.debug("Inside /stu/subscribe. Action: " + action);
if (req.isSocket) {
sails.log.debug("Inside /stu/subscribe - isSocket");
sails.sockets.join(req.socket, roomName);
sails.io.sockets.in(roomName)
.clients(function (err, ids) {
sails.log.debug("number of clients in room: " + ids.length);
if (!err)
sails.io.to(roomName)
.emit('update_peers', {
count: ids.length
});
});
res.json({
msg: "Subscribed to student " + roomName
});
sails.hooks.rooms.subscribeToRoom(
sails.hooks.rooms.student(attributes.id_stu),
req.socket
);
}
res.ok({msg: "Subscribed to student "});
},
//
......@@ -976,10 +958,7 @@ module.exports = {
var action = req.param('action');
//var attributes = req.param('attributes');
sails.log.debug("Inside /stu/unsubscribe. Action: " + action);
if (req.isSocket) {
sails.log.debug("Inside /stu/unsubscribe - isSocket");
var rooms = sails.sockets.socketRooms(req.socket);
console.log("Subscribed rooms in socket: " + JSON.stringify(rooms));
......@@ -1027,17 +1006,18 @@ module.exports = {
action: function (req, res) {
var action = req.param('action');
var attributes = req.param('attributes');
var roomName = 'studentRoom' + attributes.id_stu;
sails.log.debug("Inside action. Student:" + attributes.id_stu);
if (req.isSocket) {
sails.log.debug("websockets - room " + roomName);
sails.log.debug("websockets - room " + sails.hooks.rooms.student(attributes.id_stu));
// BROADCAST to everyone subscribed to this student
sails.sockets.broadcast(roomName, 'action', {
"action": action,
"attributes": attributes
});
const socketToOmit = (req.isSocket) ? req.socket : undefined;
sails.hooks.events.broadcastEvent(
sails.hooks.rooms.student(attributes.id_stu),
sails.hooks.events.actionPerformed(action, attributes),
socketToOmit
);
var sup = null;
if (attributes.supervisor) sup = attributes.supervisor;
......@@ -1054,8 +1034,10 @@ module.exports = {
description: desc
})
.exec(function (err, created) {
if (err)
if (err) {
sails.log.error(err.details);
res.serverError(err.details);
}
else if (created)
res.json({
action: created
......@@ -1067,6 +1049,8 @@ module.exports = {
msg: "Action "+ action +" action from student " + attributes.id_stu
});
*/
} else {
sails.log.debug("No socket request for action");
}
},
......@@ -1077,20 +1061,21 @@ module.exports = {
config: function (req, res) {
var action = req.param('action');
var attributes = req.param('attributes');
var roomName = 'studentRoom' + attributes.id_stu;
sails.log.debug("Inside config");
if (req.isSocket) {
sails.log.debug("Inside config - isSocket");
sails.sockets.broadcast(roomName, 'config', {
"action": action,
"attributes": attributes
});
res.json({
const socketToOmit = (req.isSocket) ? req.socket : undefined;
sails.hooks.events.broadcastEvent(
sails.hooks.rooms.student(attributes.id_stu),
'action',
{
"action": action,
"attributes": attributes
},
socketToOmit
);
} else {
res.ok({
msg: "Config " + action + " action from student " + attributes.id_stu
});
}
......
// @TODO 357
module.exports = {
// Mostrar etiquetas propias del supervisor para un pictograma
// Blueprint
// GET /supervisor/:idSup/pictos/:idAclPicto/tags -> Tutor.find
// NO BORRAR: Necesario cuando hay más de 2 niveles en la URL
find: function(req, res){
var idAclPicto = req.param('idAclPicto');
// Comprobación de que se envían los campos
if(!idAclPicto){
return res.json(401, {err: 'Required field: ID of picto permission'});
}
// Crear tutor (en tabla tutor y supervisor)
SupPictoTag.find({
idAclPicto: idAclPicto
}).exec(
function (err, tags) {
if(err){
res.json(err.status, {err: err});
return;
}else{
res.json({tags: tags});
}
}
);
}
};
// @TODO 357
module.exports = {
// Crear teacher/supervisor
create: function(req, res){
var name = req.param('name');
var surname = req.param('surname');
var contactEmail = req.param('contactEmail');
var preferedLanguage = req.param('preferedLanguage');
var idOff = req.param('idOff');
// Comprobación de que se envían ambos campos
if(!name || !surname || !contactEmail || !preferedLanguage || !idOff){
return res.json(401, {err: 'Required fields: Name, surname, contact email, prefered language and Office ID'});
}
// Crear teacher (en tabla teacher y supervisor)
Teacher.create({
// id: "17", Es autoincrement
idOff: idOff,
supervisor:{
name: name,
surname: surname,
contactEmail: contactEmail,
preferedLanguage: preferedLanguage
}
}).exec(
function (err, teacher) {
if(err){
res.json(err.status, {err: err});
return;
}else{
res.json({teacher: teacher});
}
}
);
},
// Elimina teacher/supervisor
// CUSTOM Blueprint
// DELETE /teacher/:idSup -> Teacher.destroy
destroy: function(req, res){
var idSup = req.param('idSup');
// Comprobación de que se envían los campos
if(!idSup){
return res.json(400, {err: 'Required fields: Teacher/Supervisor ID'});
}
// Eliminar entrada de tutor
Teacher.destroy(
{"supervisor": idSup}
).exec(
function (err, teacher) {
if(err){
res.json(err.status, {err: err});
return;
}else{
// Eliminar entrada de supervisor
Supervisor.destroy(
idSup
).exec(
function (err, supervisor) {
if(err){
res.json(err.status, {err: err});
return;
}else{
res.json({
teacher: teacher,
supervisor: supervisor
});
}
}
);
}
}
);
}
};
// @TODO 357
module.exports = {
// create action
// adds a try
//
create: function(req, res) {
var params = req.allParams();
if (!params.ws) return res.json(500, {error: "No workingSession defined"});
if (!params.begin) return res.json(500, {error: "No begin defined"});
if (!params.end) return res.json(500, {error: "No end defined"});
if (!params.actions) return res.json(500, {error: "No actions in try defined"});
if (!params.supervisor) return res.json(500, {error: "No supervisor in try defined"});
if (!params.student) return res.json(500, {error: "No student in try defined"});
Try.create({
"workingSession":params.ws,
"begin": params.begin,
"end": params.end
}).exec(function(err, tr){
if(err || !tr){
sails.log.debug("Creating new Try: " + err);
return res.json(500, {error: 'Try not created'});
}
if(tr){
var l_actions = [];
// with .eachSeries the order of resulting array will be equal
// to the original array
async.eachSeries(params.actions, function(a, callback) {
sails.log.debug("Loop adding actions: " + a.action + " to try " + tr.id);
var desc = null;
if(a.attributes.picto) desc = a.attributes.picto; // select, add and delete actions data
if(a.attributes.pictos) desc = a.attributes.pictos; // show action data
Action.create({
type: a.action,
timestamp: a.attributes.timestamp,
supervisor: params.supervisor,
student: params.student,
description: desc,
_try: tr.id
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new "+ a.action +" action: " + err);
if(action){
sails.log.debug("Action Created: " + action.type);
l_actions.push(action);
}
callback();
});
// Finish function when each callback is done
// Optionaly it can be passed and err parameter
}, function(err){
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('An error ocurred with an action');
} else {
console.log('All actions have been processed successfully');
// Return the try
// with the array of actions
return res.json({
"id": tr.id,
"workingSession": tr.workingSession,
"begin": tr.begin,
"end": tr.end,
"actions": l_actions
});
}
});
/*
// InitSession Action
Action.create({
"type": "InitSession",
"timestamp": ws.begin,
"supervisor": ws.supervisor,
"student": ws.student,
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new Action InitSession: " + err);
if(action) sails.log.debug("Created Action: " + action.type);
});
// TryInit Action
Action.create({
"type": "TryInit",
"timestamp": ws.begin,
"supervisor": ws.supervisor,
"student": ws.student,
"_try": tr.id
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new Action TryInit: " + err);
if(action){
sails.log.debug("Created Action: " + action.type);
// Return the working session created
// with the array of one try (the first)
// with the array of one action (the first too)
return res.json({
"id": ws.id,
"begin": ws.begin,
"student": ws.student,
"supervisor": ws.supervisor,
"tries": [
{
"id": tr.id,
"instruction": tr.instruction,
"begin": tr.begin,
"workingSession": tr.workingSession,
"actions": [ action ]
}
]
});
}
});
*/
}
});
}
// create action
// adds a try
//
create: function(req, res) {
var params = req.allParams();
if (!params.ws) return res.json(500, {error: "No workingSession defined"});
if (!params.begin) return res.json(500, {error: "No begin defined"});
if (!params.end) return res.json(500, {error: "No end defined"});
if (!params.actions) return res.json(500, {error: "No actions in try defined"});
if (!params.supervisor) return res.json(500, {error: "No supervisor in try defined"});
if (!params.student) return res.json(500, {error: "No student in try defined"});
Try.create({
"workingSession":params.ws,
"begin": params.begin,
"end": params.end
}).exec(function(err, tr){
if(err || !tr){
sails.log.debug("Creating new Try: " + err);
return res.json(500, {error: 'Try not created'});
}
if(tr){
var l_actions = [];
// with .eachSeries the order of resulting array will be equal
// to the original array
async.eachSeries(params.actions, function(a, callback) {
sails.log.debug("Loop adding actions: " + a.action + " to try " + tr.id);
var desc = null;
if(a.attributes.picto) desc = a.attributes.picto; // select, add and delete actions data
if(a.attributes.pictos) desc = a.attributes.pictos; // show action data
Action.create({
type: a.action,
timestamp: a.attributes.timestamp,
supervisor: params.supervisor,
student: params.student,
description: desc,
_try: tr.id
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new "+ a.action +" action: " + err);
if(action){
sails.log.debug("Action Created: " + action.type);
l_actions.push(action);
}
callback();
});
// Finish function when each callback is done
// Optionaly it can be passed and err parameter
}, function(err){
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('An error ocurred with an action');
} else {
console.log('All actions have been processed successfully');
// Return the try
// with the array of actions
return res.json({
"id": tr.id,
"workingSession": tr.workingSession,
"begin": tr.begin,
"end": tr.end,
"actions": l_actions
});
}
});
/*
// InitSession Action
Action.create({
"type": "InitSession",
"timestamp": ws.begin,
"supervisor": ws.supervisor,
"student": ws.student,
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new Action InitSession: " + err);
if(action) sails.log.debug("Created Action: " + action.type);
});
// TryInit Action
Action.create({
"type": "TryInit",
"timestamp": ws.begin,
"supervisor": ws.supervisor,
"student": ws.student,
"_try": tr.id
}).exec(function(err, action){
if(err || !action) sails.log.debug("Creating new Action TryInit: " + err);
if(action){
sails.log.debug("Created Action: " + action.type);
// Return the working session created
// with the array of one try (the first)
// with the array of one action (the first too)
return res.json({
"id": ws.id,
"begin": ws.begin,
"student": ws.student,
"supervisor": ws.supervisor,
"tries": [
{
"id": tr.id,
"instruction": tr.instruction,
"begin": tr.begin,
"workingSession": tr.workingSession,
"actions": [ action ]
}
]
});
}
});
*/
}
});
}
};
// @TODO 357
module.exports = {
// Crear tutor/supervisor
// Blueprint
// POST /tutor -> Tutor.create
create: function(req, res){
var name = req.param('name');
var surname = req.param('surname');
var contactEmail = req.param('contactEmail');
var preferedLanguage = req.param('preferedLanguage');
// Comprobación de que se envían ambos campos
if(!name || !surname || !contactEmail || !preferedLanguage){
return res.json(401, {err: 'Required fields: Name, surname, contact email and prefered language'});
}
// Crear tutor (en tabla tutor y supervisor)
Tutor.create({
// id: "17", Es autoincrement
supervisor:{
name: name,
surname: surname,
contactEmail: contactEmail,
preferedLanguage: preferedLanguage
}
}).exec(
function (err, tutor) {
if(err){
res.json(err.status, {err: err});
return;
}else{
res.json({tutor: tutor});
}
}
);
},
// Elimina tutor/supervisor
// CUSTOM Blueprint
// DELETE /tutor/:idSup -> Tutor.destroy
destroy: function(req, res){
var idSup = req.param('idSup');
// Comprobación de que se envían los campos
if(!idSup){
return res.json(400, {err: 'Required fields: Tutor/Supervisor ID'});
}
// Eliminar entrada de tutor
Tutor.destroy(
{"supervisor": idSup}
).exec(
function (err, tutor) {
if(err){
res.json(err.status, {err: err});
return;
}else{
// Eliminar entrada de supervisor
Supervisor.destroy(
idSup
).exec(
function (err, supervisor) {
if(err){
res.json(err.status, {err: err});
return;
}else{
res.json({
tutor: tutor,
supervisor: supervisor
});
}
}
);
}
}
);
}
};
......@@ -100,6 +100,23 @@ module.exports = function eventsHook(sails) {
count: subscriberCount
}
};
},
/**
* A new action is performed by the user in the tablet
* @param {action} type of the action
* @param {attributes} attributes of the action (e.g. picto attributes when
* clicking on it)
* @return {Object} {name, data}
*/
actionPerformed: function (action, attributes) {
return {
name: 'action',
data: {
action: action,
attributes: attributes
}
};
}
};
};
/**
* License.js
*
* @description :: TODO: You might write a short summary of how this model works and what it represents here.
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
tableName : 'license',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
supervisor: { // relation 1 supervisor to N licences
type: 'integer',
required: true,
model: 'Supervisor',
columnName: 'id_sup'
},
number: {
type: 'string',
required: true
},
maxStu: { // maximum number of students that can be associated with this license
type: 'integer',
required: true,
columnName: 'max_stu'
},
duration: { // number of days per student that the license lasts
type: 'integer',
required: true
},
created: { // date when the license was created
type: 'date',
required: true
},
activations: {
collection: 'LicenseActivation',
via: 'license'
}
}
};
/**
* LicenseActivation.js
*
* @description :: Activations of terapeuthical access to students by spending license
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
identity : 'LicenseActivation',
tableName : 'license_activation',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
stuSup: {
columnName: "id_stu_sup",
required: true,
type: "integer",
model: "StuSup"
},
license: {
columnName: "id_lic",
required: true,
type: "integer",
model: "License"
},
activation: {
columnName: 'activation',
type: 'date',
required: false
},
expiration: {
columnName: 'expiration',
type: 'date',
required: false
}
}
}
\ No newline at end of file
/**
* PendingRegistration.js
*
* @description :: This are official devices sold by us
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
tableName : 'pending_registration',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
idSup: {
columnName: 'id_sup',
type: "integer",
size: 11
},
hash: {
type: 'integer',
size: 32
},
timestamp: {
type: 'date'
}
}
};
......@@ -52,10 +52,6 @@ module.exports = {
collection: 'PictoTag',
via: 'picto'
},
tagsSup: {
collection: 'PictoTagSup',
via: 'picto'
},
pictoAcls: { // 1 Picto to N PictoAcl
collection: 'PictoAcl',
via: 'picto'
......
/**
* PictoAcl.js
*
* @description :: TODO: Write a short summary of how this model works and what it represents here.
* @description :: THIS CLASS IS NOT BEING USED (candidate for removal)
* @docs :: http://sailsjs.org/#!documentation/models
*/
......@@ -12,7 +12,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -41,4 +41,4 @@ module.exports = {
type: "datetime"
}
}
};
\ No newline at end of file
};
......@@ -12,7 +12,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -26,6 +26,12 @@ module.exports = {
required: true,
model: 'Picto'
},
category: {
columnName: 'id_cat_pic',
type: 'integer',
required: false,
model: 'Picto'
},
coord_x: {
type: 'integer',
required: false
......@@ -40,4 +46,3 @@ module.exports = {
}
}
};
/**
* PictoCoreCat.js
*
* @description :: This are the pictos that represent a category.
* This model is to store pos x and y when picto is presented as category
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
tableName : 'picto_core_cat',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
picto: {
columnName: 'id_pic',
type: 'integer',
required: true,
model: 'Picto'
},
category: {
columnName: 'id_cat_pic',
type: 'integer',
required: true,
model: 'Picto'
},
coord_x: {
type: 'integer',
required: false
},
coord_y: {
type: 'integer',
required: false
},
color:{
type: 'integer',
required: false
}
}
};
......@@ -12,7 +12,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -26,6 +26,12 @@ module.exports = {
type: "integer",
model: "Picto"
},
supervisor:{ // FK de Tag. 1 a N
columnName: "id_sup",
required: false,
type: "integer",
model: "Supervisor"
},
tag: { // FK de Tag. 1 a N
columnName: "tag",
required: true,
......@@ -39,4 +45,4 @@ module.exports = {
required: true
}
}
};
\ No newline at end of file
};
/**
* PictoTagSup.js
*
* @description :: TODO: Write a short summary of how this model works and what it represents here.
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
tableName : 'picto_tag_sup',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
picto:{ // FK de Picto. 1 a N
columnName: "id_pic",
required: true,
type: "integer",
model: 'Picto'
},
supervisor:{ // FK de Tag. 1 a N
columnName: "id_sup",
required: true,
type: "integer",
model: "Supervisor"
},
tag:{
type: "string",
size: 20,
required: true
},
lang:{
type: "string",
size: 2,
required: true
}
}
};
\ No newline at end of file
/**
* StuOpenTry.js
*
* @description :: TODO: Write a short summary of how this model works and what it represents here.
* @description :: This model is the Active Record of the table stu_opentry,
* which is defined in triggers-sessions-integrity-constraints.sql. It is used
* to avoid losing initiated tries within a session.
*
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
......@@ -11,7 +14,7 @@ module.exports = {
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
......@@ -25,25 +28,25 @@ module.exports = {
id_sup: {
type: "integer",
},
id_ws: {
type: "integer",
id_ws: {
type: "integer",
},
openTry: {
openTry: {
columnName: "id_opentry",
type: "integer",
unique: true
},
total_tries: {
total_tries: {
columnName: "total_tries",
type: "integer",
type: "integer",
},
begin: {
begin: {
columnName: "begin",
type: "datetime",
type: "datetime",
},
end: {
end: {
columnName: "end",
type: "datetime",
type: "datetime",
}
}
}
\ No newline at end of file
}
......@@ -240,7 +240,10 @@ module.exports = {
beforeUpdate: function (attrs, next) {
delete attrs.username;
attrs.attributes = Student.getValidAttributes(attrs.attributes);
attrs.password = bcrypt.hashSync(attrs.password, bcrypt.genSaltSync());
if (attrs.password) {
sails.log.debug('password changed');
attrs.password = bcrypt.hashSync(attrs.password, bcrypt.genSaltSync());
}
next();
},
......
......@@ -80,6 +80,7 @@
"enlarge": "Enlarge",
"enormous": "Enormous",
"error_adding_picto": "Error adding picto",
"error_deleting_picto": "Error deleting picto",
"error_downloading_supervisors": "Error downloading supervisors",
"error_downloading_offices": "Error downloading offices",
"error_only_support_images": "Only images are supported (JPG, PNG or GIF files)",
......@@ -249,6 +250,7 @@
"supervisor_updated": "Supervisor updated",
"supervisors": "Therapist",
"surname": "Surname",
"tag_deleted": "Tag deleted",
"tape_background": "Tape background",
"time_instruction_method": "Time instructions of method",
"time_hours": "Time: {{hours}} hours",
......
......@@ -83,6 +83,7 @@
"expand_navigation": "Desplegar navegación",
"expression": "Expresión:",
"error_adding_picto": "Error al añadir el picto",
"error_deleting_picto": "Error borrando el picto",
"error_downloading_supervisors": "Error al descargar los supervisores",
"error_downloading_offices": "Error al descargar las oficinas",
"error_only_support_images": "Sólo se soportan imágenes (ficheros JPG, PNG o GIF)",
......@@ -250,6 +251,7 @@
"supervisor_updated": "Supervisor actualizado",
"supervisors": "Terapeutas",
"surname": "Apellidos",
"tag_deleted": "Etiqueta borrada",
"tape_background": "Fondo de la cinta",
"time_hours": "Tiempo: {{hours}} horas",
"time_instruction_method": "Tiempo instrucciones del método",
......
......@@ -180,7 +180,7 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
$scope.close_ws = function (){
$http
.post(config.backend+ '/workingsession/'+$scope.wsessions[0].id+'/close')
.post(config.backend+ '/ws/'+$scope.wsessions[0].id+'/close')
.then(
function(data, status, headers, config) {
......@@ -203,7 +203,7 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
$scope.sessionRunning = true;
$http
.post(config.backend+'/workingsession', {
.post(config.backend+'/ws', {
"id_sup": $scope.user.id,
"id_stu": $scope.studentData.id,
"id_ins": $scope.selectedIns
......@@ -239,7 +239,7 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
$scope.update_ws = function (ws){
$http
.put(config.backend+'/workingsession/' + ws.id, { "description" : ws.description })
.put(config.backend+'/ws/' + ws.id, { "description" : ws.description })
.then(function(data, status, headers, config) {
......@@ -259,7 +259,7 @@ dashboardControllers.controller('StudentSessionCtrl', function StudentSessionCtr
$scope.ws.end = new Date();
$http
.put(config.backend+'/workingsession/' + $scope.ws.id, { "end": $scope.ws.end,
.put(config.backend+'/ws/' + $scope.ws.id, { "end": $scope.ws.end,
"id_stu": $scope.studentData.id
})
.success(function(data, status, headers, config) {
......
......@@ -48,16 +48,20 @@ dashboardControllers.controller('TagsCtrl', function TagsCtrl(
$scope.tagToAdd = '';
})
.error(function () {
// TODO show error with ngToast
$translate('error_adding_tag').then(function (translation) {
ngToast.danger({ content: translation });
});
});
};
// Destroy own tag
$scope.del = function (tag) {
$http.delete(config.backend + '/picto/tag/' + tag.id)
$http.delete(config.backend + '/picto/' + $scope.sup.id + '/tag/' + tag.id)
.success(function () {
var i;
// TODO show success with ngToast
$translate('tag_deleted').then(function (translation) {
ngToast.success({ content: translation });
});
// Eliminar de la vista: Se recorre el array de objetos json para buscarlo
for (i = 0; i < $scope.ownTags.length; i++) {
if (tag.id === $scope.ownTags[i].id) {
......@@ -66,7 +70,9 @@ dashboardControllers.controller('TagsCtrl', function TagsCtrl(
}
})
.error(function () {
// TODO show error with ngToast
$translate('error_deleting_tag').then(function (translation) {
ngToast.danger({ content: translation });
});
});
};
......
......@@ -26,7 +26,7 @@ customLogger.add(winston.transports.File, {
json: true,
tailable: true,
maxsize: 5 * 1024 * 1024, // 5 MegaByte
filename: path.resolve(__dirname, '..', 'logs', 'silly.json')
filename: path.resolve(__dirname, '../..', 'logs', 'silly.json')
});
customLogger.add(winston.transports.File, {
......@@ -39,7 +39,7 @@ customLogger.add(winston.transports.File, {
json: true,
tailable: true,
maxsize: 5 * 1024 * 1024, // 5 MegaByte
filename: path.resolve(__dirname, '..', 'logs', 'debug.json')
filename: path.resolve(__dirname, '../..', 'logs', 'debug.json')
});
customLogger.add(winston.transports.File, {
......@@ -52,7 +52,7 @@ customLogger.add(winston.transports.File, {
json: true,
tailable: true,
maxsize: 5 * 1024 * 1024, // 5 MegaByte
filename: path.resolve(__dirname, '..', 'logs', 'error.json')
filename: path.resolve(__dirname, '../..', 'logs', 'error.json')
});
module.exports.log = {
......
......@@ -50,7 +50,7 @@ module.exports.routes = {
'POST /picto/tag': 'PictoController.add_tag',
'POST /picto/exp': 'PictoController.change_exp',
'DELETE /picto/:id': 'PictoController.destroy',
'DELETE /picto/tag/:id_tag': 'PictoController.del_tag',
'DELETE /picto/:id_sup/tag/:id_tag': 'PictoController.del_tag',
'GET /server/ping': 'ServerController.ping',
'GET /server/ping_session': 'ServerController.ping_session',
......@@ -103,7 +103,7 @@ module.exports.routes = {
'GET /ws/:id_stu/year/:year': 'WorkingSessionController.per_year',
'GET /ws/:id_stu/month/:month': 'WorkingSessionController.per_month',
'GET /ws/:id_ws/tries': 'WorkingSessionController.tries',
'PUT /workingsession/:id': 'WorkingSessionController.update',
'POST /workingsession': 'WorkingSessionController.create',
'POST /workingsession/:id_ws/close': 'WorkingSessionController.close'
'PUT /ws/:id': 'WorkingSessionController.update',
'POST /ws': 'WorkingSessionController.create',
'POST /ws/:id_ws/close': 'WorkingSessionController.close'
};
......@@ -70,9 +70,9 @@ describe('Picto API', function () {
.end(done);
});
});
it('DELETE /picto/tag/:id_tag', function (done) {
it('DELETE /picto/:id_sup/tag/:id_tag', function (done) {
supervisorAgent
.delete('/picto/tag/' + 1234)
.delete('/picto/'+supervisorAgent.data.id+'/tag/' + 1234)
.send()
.expect(200)
.end(done);
......
......@@ -9,13 +9,17 @@ describe('Student API', function () {
delete studentAgentData.password;
studentAgentData.current_method = 'Test Method';
studentAgentData.current_instruction = 'Test Instruction';
supervisorAgent
.get('/stu/' + studentAgent.data.id)
.send()
.expect(200)
.expect(studentAgentData)
.end(done);
.end((error) => {
if (error) {
throw error;
};
done();
});
});
it('GET /stu/:id_stu/supervisors', function (done) {
supervisorAgent
......
......@@ -71,6 +71,7 @@ describe('Supervisor API', function () {
.expect(200)
.expect(function (response) {
assert.isArray(response.body);
assert.isAtLeast(response.body.length, 1, 'category 41 is empty');
response.body.forEach(function (picto) {
assert.isObject(picto);
assert.isNumber(picto.source);
......
/* eslint-disable no-console */
var DATABASE_BACKUP_FILE = '/tmp/pictogram_test_backup.sql';
var DATABASE_RESET_FILE = '../roles/database/files/init-ignoresymbolstix.sql'
var DATABASE_SESSION_TRIGGERS_FILE = '../roles/database/files/triggers-sessions-integrity-constraints.sql'
var DATABASE_ENROLMENT_TRIGGERS_FILE = '../roles/database/files/triggers-enrolments-integrity-constraints.sql'
var DATABASE_TESTDATA_FILE = '../roles/database/files/test-caja.sql'
var UPLOAD_FOLDER;
var UPLOAD_FOLDER_BACKUP;
var Agent = require('supertest').agent;
......@@ -16,14 +20,32 @@ before(function (serverLoadDone) {
sails = new Sails();
// Backup the whole database
console.log('-- Backing up database');
childProcess.execSync('mysqldump -u pictodbuser -pp1KT015 pictodb > ' + DATABASE_BACKUP_FILE);
// Prepare with test data
console.log('-- Preparing test database');
childProcess.execSync('mysql -u pictodbuser -pp1KT015 pictodb < ' + DATABASE_RESET_FILE);
childProcess.execSync('mysql -u pictodbuser -pp1KT015 pictodb < ' + DATABASE_TESTDATA_FILE);
childProcess.execSync('mysql -u pictodbuser -pp1KT015 pictodb < ' + DATABASE_SESSION_TRIGGERS_FILE);
childProcess.execSync('mysql -u pictodbuser -pp1KT015 pictodb < ' + DATABASE_ENROLMENT_TRIGGERS_FILE);
console.log('-- Lifting Sails');
sails.lift({}, function (error) {
if (error) {
console.log(error.stack);
throw error;
}
console.log('-- Importing bcrypt ');
var bcrypt = require('bcrypt-nodejs');
// Backup the sail's upload folder
UPLOAD_FOLDER = sails.config.pictogram.paths.upload;
UPLOAD_FOLDER_BACKUP = UPLOAD_FOLDER + '.backup';
console.log('-- Backing up ' + UPLOAD_FOLDER);
childProcess.execSync('cp -r ' + UPLOAD_FOLDER + ' ' + UPLOAD_FOLDER_BACKUP);
// Publish chai testing methods
......@@ -72,9 +94,10 @@ before(function (serverLoadDone) {
});
after(function (done) {
console.log('-- Restoring backups');
// Restore the database and the upload folder
if (UPLOAD_FOLDER && UPLOAD_FOLDER_BACKUP) {
childProcess.execSync('mysql -u pictodbuser -pp1KT015 pictodb < ' + DATABASE_BACKUP_FILE);
childProcess.execSync('mysql -u root -proot pictodb < ' + DATABASE_BACKUP_FILE);
childProcess.execSync('rm ' + DATABASE_BACKUP_FILE);
childProcess.execSync('rm -r ' + UPLOAD_FOLDER);
childProcess.execSync('mv ' + UPLOAD_FOLDER_BACKUP + ' ' + UPLOAD_FOLDER);
......
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