Commit c5e73e2d by Arturo Montejo Ráez

conflicts fixed

parents 5bee4510 f781c996
Showing with 3093 additions and 2670 deletions
......@@ -62,13 +62,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
......@@ -76,22 +69,23 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 24 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
......
-- phpMyAdmin SQL Dump
-- version 4.1.14
-- http://www.phpmyadmin.net
-- MySQL dump 10.13 Distrib 5.7.13, for Linux (x86_64)
--
-- Servidor: 127.0.0.1
-- Tiempo de generación: 11-03-2015 a las 03:31:50
-- Versión del servidor: 5.6.17
-- Versión de PHP: 5.5.12
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
-- Host: localhost Database: pictodb
-- ------------------------------------------------------
-- Server version 5.7.13
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Base de datos: `pictodb`
--
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `action`
-- Table structure for table `action`
--
CREATE TABLE IF NOT EXISTS `action` (
DROP TABLE IF EXISTS `action`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `action` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(20) COLLATE utf8_unicode_ci NOT NULL CHECK (type IN ('Add','Select','Delete','Show','Unshow','Pause','tryinit','tryend','initsession','endsession','pausesession','resumesession')),
`timestamp` timestamp(3) DEFAULT CURRENT_TIMESTAMP(3),
`type` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`timestamp` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`id_sup` int(11) DEFAULT NULL,
`id_stu` int(11) NOT NULL,
`id_try` int(11) DEFAULT NULL,
......@@ -35,19 +33,137 @@ CREATE TABLE IF NOT EXISTS `action` (
`gps_lat` float DEFAULT NULL,
`gps_lon` float DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT uq_stuact UNIQUE (id_stu,timestamp),
CONSTRAINT uq_supact UNIQUE (id_sup,timestamp),
UNIQUE (id_stu,timestamp),
UNIQUE KEY `uq_stuact` (`id_stu`,`timestamp`),
UNIQUE KEY `id_stu` (`id_stu`,`timestamp`),
UNIQUE KEY `uq_supact` (`id_sup`,`timestamp`),
KEY `fk_sup_act` (`id_sup`),
KEY `fk_stu_act` (`id_stu`),
KEY `id_try` (`id_try`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="This table registers and action performed by a user at a given time, all information of the action is in JSON format in the 'description' column and the operation performed is one of the possible for the 'type' column. NOTE: timestamps must support fractional seconds, so MySQL versions >= 5.6.4 are required.";
KEY `id_try` (`id_try`),
CONSTRAINT `fk_stu_act` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`),
CONSTRAINT `fk_sup_act` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`),
CONSTRAINT `fk_try_act` FOREIGN KEY (`id_try`) REFERENCES `try` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='This table registers and action performed by a user at a given time, all information of the action is in JSON format in the ''description'' column and the operation performed is one of the possible for the ''type'' column. NOTE: timestamps must support fractional seconds, so MySQL versions >= 5.6.4 are required.';
/*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_NEW_EVENT_ONSESSION
BEFORE INSERT ON action
FOR EACH ROW
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;
SELECT id_opentry INTO idtry
FROM
stu_opentry
WHERE
id_stu = NEW.id_stu;
IF (idtry IS NOT NULL) THEN
SET NEW.id_try = idtry;
END IF;
IF (NEW.type = 'resumesession')
THEN
SET NEW.id_try=NULL;
END IF;
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_NEW_EVENT
AFTER INSERT ON action
FOR EACH ROW
thisTrigger: BEGIN
DECLARE idopentry INT;
DECLARE idws INT;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_INSERT_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
SELECT id_ws, id_opentry INTO idws, idopentry
FROM
stu_opentry
WHERE
id_stu = NEW.id_stu;
IF (NEW.id_try IS NOT NULL) THEN
UPDATE `try`
SET
end = NEW.timestamp
WHERE
id = idopentry;
END IF;
CASE NEW.type
WHEN 'Show' THEN
INSERT INTO try(`id_ws`)
VALUES (idws);
WHEN 'pausesession' THEN
IF (idopentry IS NOT NULL) THEN
UPDATE try
SET
result = 'DISCARDED'
WHERE
id = idopentry;
END IF;
WHEN 'resumesession' THEN
INSERT INTO try(`id_ws`)
VALUES (idws);
ELSE BEGIN END;
END CASE;
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `catexp`
-- Table structure for table `catexp`
--
DROP TABLE IF EXISTS `catexp`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `catexp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_cat` int(11) NOT NULL,
......@@ -55,113 +171,117 @@ CREATE TABLE `catexp` (
`exp` varchar(30) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `exp` (`exp`,`lang`)
) ENGINE=InnoDB AUTO_INCREMENT=27958 DEFAULT CHARSET=utf8 COMMENT='Stores the expressions available in several languages for a given category (id_cat)';
-- --------------------------------------------------------
) ENGINE=InnoDB AUTO_INCREMENT=27958 DEFAULT CHARSET=latin1 COMMENT='Stores the expressions available in several languages for a given category (id_cat)';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `method`
-- Table structure for table `instruction`
--
CREATE TABLE IF NOT EXISTS `method` (
DROP TABLE IF EXISTS `instruction`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `instruction` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`id_stu` int(11) NOT NULL,
`registration` date DEFAULT NULL,
`notes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`id_met` int(11) NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`objective` varchar(512) COLLATE utf8_unicode_ci DEFAULT NULL,
`status` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
`begin` timestamp(3) NULL DEFAULT NULL,
`end` timestamp(3) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_stu_met` (`id_stu`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="Information for a method. A method is composed by a set of instructions";
-- --------------------------------------------------------
KEY `fk_met_ins` (`id_met`),
KEY `ix_instruction_begin` (`begin`),
CONSTRAINT `fk_met_ins` FOREIGN KEY (`id_met`) REFERENCES `method` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='An instruction is a ''phase'' in a method for learning AAC';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `instruction`
-- Table structure for table `license`
--
CREATE TABLE IF NOT EXISTS `instruction` (
DROP TABLE IF EXISTS `license`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `license` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_met` int(11) NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`objective` varchar(512) COLLATE utf8_unicode_ci DEFAULT NULL,
`status` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL CHECK (status IN ('started','finished')),
`begin` timestamp(3) NULL,
`end` timestamp(3) NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="An instruction is a 'phase' in a method for learning AAC";
-- CREATE INDEX ix_instruction_begin ON instruction (`begin`);
-- --------------------------------------------------------
`id_stu` int(11) DEFAULT NULL,
`number` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`creation_ts` datetime DEFAULT CURRENT_TIMESTAMP,
`activation_ts` datetime DEFAULT NULL,
`expiration_ts` datetime DEFAULT NULL,
`duration` int(11) DEFAULT '0',
`creator` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
`type` enum('trial','official') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'official',
PRIMARY KEY (`id`),
UNIQUE KEY `number` (`number`),
KEY `id_stu` (`id_stu`)
) ENGINE=InnoDB AUTO_INCREMENT=147 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Student license number';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `meta_instruction`
-- Table structure for table `meta_instruction`
--
CREATE TABLE IF NOT EXISTS `meta_instruction` (
DROP TABLE IF EXISTS `meta_instruction`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `meta_instruction` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`objective` varchar(512) COLLATE utf8_unicode_ci DEFAULT NULL,
`id_met` tinyint(4) NOT NULL,
`lang` char(5) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="One in a set of instructions predefined or stored by users. They are related to a metamethod (id_met)";
-- --------------------------------------------------------
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='One in a set of instructions predefined or stored by users. They are related to a metamethod (id_met)';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `meta_method`
-- Table structure for table `meta_method`
--
CREATE TABLE IF NOT EXISTS `meta_method` (
DROP TABLE IF EXISTS `meta_method`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `meta_method` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT,
`name` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`id_sup` INT( 11 ) DEFAULT NULL,
`id_sup` int(11) DEFAULT NULL,
`lang` char(5) COLLATE utf8_unicode_ci NOT NULL,
UNIQUE(name,id_sup),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="Methods predefined in the platform or stored by users for cloning";
-- --------------------------------------------------------
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`,`id_sup`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Methods predefined in the platform or stored by users for cloning';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `office`
-- Table structure for table `method`
--
CREATE TABLE IF NOT EXISTS `office` (
DROP TABLE IF EXISTS `method`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `method` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
`logo_url` varchar(240) COLLATE utf8_unicode_ci NOT NULL,
`address` varchar(180) COLLATE utf8_unicode_ci NOT NULL,
`postal_code` char(10) COLLATE utf8_unicode_ci NOT NULL,
`country` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`contact_person` varchar(80) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Contact person, main responsible',
`email` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
`phone1` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`phone2` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`admin` int(11) DEFAULT NULL COMMENT 'Teacher administrator, able to associate students to teachers',
`max_students` int(4) DEFAULT 10 COMMENT 'Maximun number of enrolments for a given office',
`current_students` int(4) DEFAULT 0 COMMENT 'calculable attr: current number of enrolments',
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`id_stu` int(11) NOT NULL,
`registration` date DEFAULT NULL,
`notes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
KEY `fk_admin_tea` (`admin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=383
COMMENT="Information about a therapists' office (cabinet)";
-- --------------------------------------------------------
KEY `fk_stu_met` (`id_stu`),
CONSTRAINT `fk_stu_met` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Information for a method. A method is composed by a set of instructions';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `picto`
-- Table structure for table `picto`
--
CREATE TABLE IF NOT EXISTS `picto` (
DROP TABLE IF EXISTS `picto`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `picto` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uri` varchar(250) COLLATE utf8_unicode_ci NOT NULL,
`id_src` tinyint(4) NOT NULL,
......@@ -170,80 +290,77 @@ CREATE TABLE IF NOT EXISTS `picto` (
PRIMARY KEY (`id`),
UNIQUE KEY `ck_pic` (`id_owner`,`id_src`,`uri`),
KEY `fk_sou_pic` (`id_src`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=104142
COMMENT="Main information about a pictogram, either coming from a source like Symbolstix or added by a supervisor. It can belongs to a category (id_cat)";
) ENGINE=InnoDB AUTO_INCREMENT=130774 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Main information about a pictogram, either coming from a source like Symbolstix or added by a supervisor. It can belongs to a category (id_cat)';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `picto_acl`
-- NOT IN USE (candidate for removal)
-- Table structure for table `picto_acl`
--
CREATE TABLE IF NOT EXISTS `picto_acl` (
DROP TABLE IF EXISTS `picto_acl`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `picto_acl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_sup` int(11) NOT NULL DEFAULT '0',
`id_pic` int(11) NOT NULL DEFAULT '0',
`privilege` varchar(1) COLLATE utf8_unicode_ci NOT NULL,
`timestamp` timestamp(3),
`timestamp` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
KEY `k_pic_aclp` (`id_pic`),
KEY `k_sup_aclp` (`id_sup`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="Stablish access rights to pictos";
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `pictocat`
--
CREATE TABLE IF NOT EXISTS `pictocat`(
`id` int(11) PRIMARY KEY,
`id_supercat` int(11) DEFAULT NULL
)
ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT="Identifies a category, which, itself, may belong to another category";
-- --------------------------------------------------------
KEY `k_sup_aclp` (`id_sup`),
CONSTRAINT `fk_pic_aclp` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`),
CONSTRAINT `fk_sup_aclp` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Stablish access rights to pictos';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `picto_core`
-- Table structure for table `picto_core`
--
CREATE TABLE IF NOT EXISTS `picto_core` (
DROP TABLE IF EXISTS `picto_core`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `picto_core` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_pic` int(11) DEFAULT NULL COMMENT 'This is the id of the pictogram',
`id_cat_pic` int(11) DEFAULT NULL COMMENT 'This is the id of the pictogram that represents the category this entry belongs to',
`coord_x` tinyint(4) NOT NULL,
`coord_y` tinyint(4) NOT NULL,
`color`varchar(9) NULL, -- 9 for a #RRGGBBAA color
`color` varchar(9) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_pic` (`id_pic`),
KEY `id_cat_pic` (`id_cat_pic`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=124
COMMENT="Default pictos and categories available for a newly created student with default coordinates";
-- --------------------------------------------------------
KEY `id_cat_pic` (`id_cat_pic`),
CONSTRAINT `picto_core_ibfk_1` FOREIGN KEY (`id_cat_pic`) REFERENCES `picto` (`id`),
CONSTRAINT `picto_core_ibfk_2` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=233 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Default pictos and categories available for a newly created student with default coordinates';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `picto_exp`
-- Table structure for table `picto_exp`
--
CREATE TABLE IF NOT EXISTS `picto_exp` (
DROP TABLE IF EXISTS `picto_exp`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `picto_exp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_pic` int(11) NOT NULL,
`lang` char(5) COLLATE utf8_unicode_ci NOT NULL,
`text` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `id_pic` (`id_pic`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=72565
COMMENT="Expression (text label) for a picto (or a category) in different languages. This is used by the TTS engine";
-- --------------------------------------------------------
) ENGINE=InnoDB AUTO_INCREMENT=270859 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Expression (text label) for a picto (or a category) in different languages. This is used by the TTS engine';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `picto_tag`
-- Table structure for table `picto_tag`
--
CREATE TABLE IF NOT EXISTS `picto_tag` (
DROP TABLE IF EXISTS `picto_tag`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `picto_tag` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_sup` int(11) DEFAULT NULL COMMENT 'If NULL then is a default tag',
`id_pic` int(11) NOT NULL,
......@@ -251,80 +368,114 @@ CREATE TABLE IF NOT EXISTS `picto_tag` (
`lang` char(5) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `id_pic` (`id_pic`),
KEY `id_sup` (`id_sup`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="Labels assigned to pictos by default or by supervisors";
-- --------------------------------------------------------
KEY `id_sup` (`id_sup`),
CONSTRAINT `fk_con_pt` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`),
CONSTRAINT `picto_tag_ibfk_1` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`),
CONSTRAINT `picto_tag_ibfk_2` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=37052 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Labels assigned to pictos by default or by supervisors';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `source`
-- Table structure for table `pictocat`
--
CREATE TABLE IF NOT EXISTS `source` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT,
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
DROP TABLE IF EXISTS `pictocat`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `pictocat` (
`id` int(11) NOT NULL,
`id_supercat` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2
COMMENT="Contains all possible sources of pictos";
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Identifies a category, which, itself, may belong to another category';
/*!40101 SET character_set_client = @saved_cs_client */;
-- --------------------------------------------------------
--
-- Table structure for table `pictocattree`
--
DROP TABLE IF EXISTS `pictocattree`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `pictocattree` (
`id_cat` int(11) NOT NULL,
`id_ancestor` int(11) NOT NULL,
PRIMARY KEY (`id_cat`,`id_ancestor`),
KEY `id_ancestor` (`id_ancestor`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `student`
-- Table structure for table `scene`
--
CREATE TABLE IF NOT EXISTS `student` (
DROP TABLE IF EXISTS `scene`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `scene` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`surname` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`birthdate` date NOT NULL,
`gender` char(1) COLLATE utf8_unicode_ci NOT NULL,
`country` char(2) COLLATE utf8_unicode_ci NOT NULL,
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'defaultAvatar.jpg',
`notes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`attributes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Attributes describing student along with his/her configuration',
`id_off` int(11) DEFAULT NULL,
`id_active_scene` int(11) DEFAULT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`active` tinyint(1) NOT NULL DEFAULT '0',
`categories` tinyint(1) NOT NULL DEFAULT '0',
`id_sup` int(11) DEFAULT NULL,
`id_stu` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
KEY `id_off` (`id_off`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=19
COMMENT="Students information";
KEY `id_sup` (`id_sup`),
KEY `id_stu` (`id_stu`),
CONSTRAINT `scene_ibfk_1` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`),
CONSTRAINT `scene_ibfk_2` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=161 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Scene table information. Every scene is related to some stu_pictos';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `source`
--
-- --------------------------------------------------------
DROP TABLE IF EXISTS `source`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `source` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT,
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Contains all possible sources of pictos';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `license`
-- Table structure for table `stu_opentry`
--
CREATE TABLE IF NOT EXISTS `license` (
DROP TABLE IF EXISTS `stu_opentry`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `stu_opentry` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_stu` int(11) DEFAULT NULL,
`number` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`creation_ts` datetime DEFAULT CURRENT_TIMESTAMP,
`activation_ts` datetime NULL,
`expiration_ts` datetime NULL,
`duration` int(11) DEFAULT 0,
`creator` varchar(40) DEFAULT NULL,
`id_stu` int(11) NOT NULL,
`id_sup` int(11) NOT NULL,
`id_ws` int(11) NOT NULL,
`id_opentry` int(11) DEFAULT NULL,
`total_tries` int(11) DEFAULT '0',
`begin` timestamp(3) NULL DEFAULT NULL,
`end` timestamp(3) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `number` (`number`),
KEY `id_stu` (`id_stu`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=19
COMMENT="Student license number";
-- --------------------------------------------------------
UNIQUE KEY `id_stu` (`id_stu`),
UNIQUE KEY `id_sup` (`id_sup`),
UNIQUE KEY `id_ws` (`id_ws`),
KEY `id_opentry` (`id_opentry`),
CONSTRAINT `stu_opentry_ibfk_1` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`),
CONSTRAINT `stu_opentry_ibfk_2` FOREIGN KEY (`id_opentry`) REFERENCES `try` (`id`) ON DELETE SET NULL,
CONSTRAINT `stu_opentry_ibfk_3` FOREIGN KEY (`id_ws`) REFERENCES `working_session` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `stu_picto`
-- Table structure for table `stu_picto`
--
CREATE TABLE IF NOT EXISTS `stu_picto` (
DROP TABLE IF EXISTS `stu_picto`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `stu_picto` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_stu` int(11) NOT NULL,
`id_pic` int(11) NOT NULL,
......@@ -332,314 +483,538 @@ CREATE TABLE IF NOT EXISTS `stu_picto` (
`id_scene` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_picto` (`id_pic`),
KEY `id_stu` (`id_stu`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="This table relates a student with the pictos in her vocabulary";
-- --------------------------------------------------------
KEY `id_stu` (`id_stu`),
KEY `stu_picto_scene_fk` (`id_scene`),
CONSTRAINT `fk_picto` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`),
CONSTRAINT `stu_picto_ibfk_1` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`),
CONSTRAINT `stu_picto_scene_fk` FOREIGN KEY (`id_scene`) REFERENCES `scene` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7010 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='This table relates a student with the pictos in her vocabulary';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `stu_sup`
-- Table structure for table `stu_sup`
--
CREATE TABLE IF NOT EXISTS `stu_sup` (
DROP TABLE IF EXISTS `stu_sup`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `stu_sup` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_stu` int(11) NOT NULL,
`id_sup` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `fk_stu_sup_ss` (`id_stu`,`id_sup`),
KEY `fk_sup_ss` (`id_sup`),
KEY `id_stu` (`id_stu`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=26
COMMENT="This table relates students and supervisors";
KEY `id_stu` (`id_stu`),
CONSTRAINT `stu_sup_ibfk_1` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`) ON DELETE CASCADE,
CONSTRAINT `stu_sup_ibfk_2` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=92 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='This table relates students and supervisors';
/*!40101 SET character_set_client = @saved_cs_client */;
-- --------------------------------------------------------
--
-- Table structure for table `student`
--
DROP TABLE IF EXISTS `student`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`name` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
`surname` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
`birthdate` date DEFAULT NULL,
`gender` char(1) COLLATE utf8_unicode_ci DEFAULT NULL,
`country` char(2) COLLATE utf8_unicode_ci DEFAULT NULL,
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'defaultAvatar.jpg',
`notes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci DEFAULT NULL,
`attributes` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Attributes describing student along with his/her configuration',
`id_active_scene` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
KEY `fk_active_scene` (`id_active_scene`),
CONSTRAINT `fk_active_scene` FOREIGN KEY (`id_active_scene`) REFERENCES `scene` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=67 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Students information';
/*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_NEW_STUDENT_UPDATE_ENROLMENTS
AFTER INSERT ON student
FOR EACH ROW
thisTrigger: BEGIN
DECLARE LID INT;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_INSERT_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
INSERT INTO scene (id_stu,id_sup,name,categories) VALUES (NEW.id, null, 'with_categories', TRUE);
SET LID = LAST_INSERT_ID();
CALL scene_create_core(LID,new.id);
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_DELETE_STUDENT_ENROLMENTS
AFTER DELETE ON student
FOR EACH ROW
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
SET
current_students=current_students-1
WHERE
office.id=old.id_off;
END IF;
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
--
-- Table structure for table `sup_off`
--
DROP TABLE IF EXISTS `sup_off`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `sup_off` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_sup` int(11) NOT NULL,
`id_off` int(11) DEFAULT NULL,
KEY `fk_sup_off` (`id_sup`),
KEY `fk_off_sup` (`id_off`),
PRIMARY KEY(`id`),
UNIQUE KEY `idx_sup_off` (`id_sup`,`id_off`),
CONSTRAINT `fk_off_sup` FOREIGN KEY (`id_off`) REFERENCES `supervisor` (`id`),
CONSTRAINT `fk_sup_off` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `supervisor`
-- Table structure for table `supervisor`
--
CREATE TABLE IF NOT EXISTS `supervisor` (
DROP TABLE IF EXISTS `supervisor`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `supervisor` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`surname` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`gender` char(1) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
`surname` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
`gender` char(1) COLLATE utf8_unicode_ci DEFAULT NULL,
`pic` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'defaultAvatar.jpg',
`address` varchar(180) COLLATE utf8_unicode_ci DEFAULT NULL,
`postal_code` char(10) COLLATE utf8_unicode_ci NOT NULL,
`country` varchar(2) COLLATE utf8_unicode_ci DEFAULT NULL,
`email` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
`phone` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci DEFAULT NULL,
`tts_engine` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`password` varchar(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'Encrypted password using the BCrypt algorithm',
`id_off` int(11) DEFAULT NULL,
`active` boolean DEFAULT FALSE,
`arasaac_license` boolean DEFAULT FALSE,
`active` tinyint(1) DEFAULT '0',
`postal_code` char(10) COLLATE utf8_unicode_ci DEFAULT NULL,
`arasaac_license` tinyint(1) DEFAULT '0',
`role` enum('tutor','therapist','office','admin') COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
KEY `id_off` (`id_off`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=23
COMMENT="Supervisors information";
-- --------------------------------------------------------
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Supervisors information';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Estructura de tabla para la tabla `try`
-- Table structure for table `try`
--
CREATE TABLE IF NOT EXISTS `try` (
DROP TABLE IF EXISTS `try`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `try` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_ws` int(11) NOT NULL,
`begin` timestamp(3) DEFAULT CURRENT_TIMESTAMP(3),
`end` timestamp(3) NULL,
`result` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL CHECK (result IN ('SUCCESS','SPONTANEUS SUCCESS', 'SUPERVISED SUCCESS', 'FAIL','DISCARDED','MODEL')),
`description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_ws` (`id_ws`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="This table contains tries information (they belong to a working session)";
-- CREATE INDEX ix_try_begin ON try (`begin`);
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `working_session`
--
-- NOTA: current es un atributo derivado que es necesario porque MySQL 5.1
-- no soporta correctamente indices con valor unico donde un campo es NULL
-- Trabaja en combinación al índice unico (id_sup,current) (idx_ws_supcur)
--
CREATE TABLE IF NOT EXISTS `working_session` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_sup` int(11) NOT NULL,
`id_ins` int(11) NOT NULL,
`begin` timestamp(3) DEFAULT CURRENT_TIMESTAMP(3),
`end` timestamp(3) NULL,
`current` boolean NULL DEFAULT 1,
`begin` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`end` timestamp(3) NULL DEFAULT NULL,
`result` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_sup` (`id_sup`),
KEY `id_ins` (`id_ins`),
-- 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
-- (see triggers-sessions-integrity-constraints for the rest of rules)
--
CONSTRAINT `idx_ws_supcur` UNIQUE (id_sup, current)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="This table stores working session information. Every working session is related to one instruction and one supervisor (and the instruction is related to one method which is related to one student)";
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `scene`
--
CREATE TABLE IF NOT EXISTS `scene` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`categories` boolean NOT NULL DEFAULT 0,
`id_sup` int(11) DEFAULT NULL,
`id_stu` int(11) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`),
FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="Scene table information. Every scene is related to some stu_pictos";
-- CREATE INDEX ix_ws_begin ON working_session (`begin`);
--
-- Restricciones para tablas volcadas
--
--
-- Filtros para la tabla `action`
--
ALTER TABLE `action`
ADD CONSTRAINT `fk_stu_act` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`),
ADD CONSTRAINT `fk_sup_act` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`);
-- Integrity rule 8: Every action requires a valid try or null
-- when: state SES, event a3 and a5
-- (see triggers-sessions-integrity-constraints for the rest of rules)
--
ALTER TABLE `action`
ADD CONSTRAINT `fk_try_act` FOREIGN KEY (`id_try`) REFERENCES `try` (`id`) ON DELETE SET NULL;;
--
-- Filtros para la tabla `method`
--
ALTER TABLE `method`
ADD CONSTRAINT `fk_stu_met` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`);
--
-- Filtros para la tabla `instruction`
--
ALTER TABLE `instruction`
ADD CONSTRAINT `fk_met_ins` FOREIGN KEY (`id_met`) REFERENCES `method` (`id`);
--
-- Filtros para la tabla `meta_instruction`
--
ALTER TABLE `meta_instruction`
ADD CONSTRAINT `fk_ins_met` FOREIGN KEY (`id_met`) REFERENCES `meta_method` (`id`);
--
-- Filtros para la tabla `meta_method`
--
ALTER TABLE `meta_method`
ADD CONSTRAINT `fk_met_sup` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`);
--
-- Filtros para la tabla `office`
--
ALTER TABLE `office`
ADD CONSTRAINT `office_ibfk_1` FOREIGN KEY (`admin`) REFERENCES `supervisor` (`id`);
--
-- Filtros para la tabla `picto`
--
--
-- Filtros para la tabla `picto_acl`
--
ALTER TABLE `picto_acl`
ADD CONSTRAINT `fk_pic_aclp` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`),
ADD CONSTRAINT `fk_sup_aclp` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`);
--
-- Filtros para la tabla `picto_core_cat`
--
ALTER TABLE `picto_core`
ADD CONSTRAINT `picto_core_ibfk_1` FOREIGN KEY (`id_cat_pic`) REFERENCES `picto` (`id`),
ADD CONSTRAINT `picto_core_ibfk_2` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`);
--
-- Filtros para la tabla `picto_tag`
--
ALTER TABLE `picto_tag`
ADD CONSTRAINT `fk_con_pt` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`);
--
-- Filtros para la tabla `picto_tag_sup`
--
ALTER TABLE `picto_tag`
ADD CONSTRAINT `picto_tag_ibfk_1` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`),
ADD CONSTRAINT `picto_tag_ibfk_2` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`);
--
-- Filtros para la tabla `stu_picto`
--
ALTER TABLE `stu_picto`
ADD CONSTRAINT `fk_picto` FOREIGN KEY (`id_pic`) REFERENCES `picto` (`id`),
ADD CONSTRAINT `stu_picto_ibfk_1` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`),
ADD CONSTRAINT `stu_picto_scene_fk` FOREIGN KEY (`id_scene`) REFERENCES `scene` (`id`) ON DELETE CASCADE;
--
-- Filtros para la tabla `stu_sup`
--
ALTER TABLE `stu_sup`
ADD CONSTRAINT `stu_sup_ibfk_1` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `stu_sup_ibfk_2` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`);
KEY `id_ws` (`id_ws`),
KEY `ix_try_begin` (`begin`),
CONSTRAINT `try_ibfk_1` FOREIGN KEY (`id_ws`) REFERENCES `working_session` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='This table contains tries information (they belong to a working session)';
/*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_NEW_TRY
AFTER INSERT ON try
FOR EACH ROW
thisTrigger: BEGIN
DECLARE idstu INT;
DECLARE idsup 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,W.id_sup INTO idstu, idsup
FROM
instruction I,
method M,
working_session W
WHERE
NEW.id_ws=W.id AND
W.id_ins=I.id AND
I.id_met=M.id;
INSERT INTO stu_opentry(id_stu,id_sup,id_ws,id_opentry, total_tries,begin)
VALUES (
idstu,
idsup,
NEW.id_ws,
NEW.id,
0,
NOW(3)
)
ON DUPLICATE KEY UPDATE id_stu=idstu, id_sup=idsup, id_ws=NEW.id_ws, id_opentry=NEW.id;
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_TRY_EVALUATED
AFTER UPDATE ON try
FOR EACH ROW
thisTrigger: BEGIN
DECLARE idws INT;
DECLARE ws_end DATE;
DECLARE ws_old_end DATE;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_UPDATE_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
SELECT end INTO ws_end
FROM
stu_opentry
WHERE
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 = NEW.id_ws;
END IF;
SELECT end INTO ws_old_end
FROM
working_session
WHERE
id = NEW.id_ws;
--
-- Filtros para la tabla `student`
--
ALTER TABLE `student`
ADD CONSTRAINT `student_ibfk_1` FOREIGN KEY (`id_off`) REFERENCES `office` (`id`);
IF (ws_old_end < NEW.end) THEN
UPDATE working_session
SET end = NEW.end
WHERE id = NEW.id_ws;
END IF;
--
-- Filtros para la tabla `license`
--
ALTER TABLE `license`
ADD CONSTRAINT `license_fk_1` FOREIGN KEY (`id_stu`) REFERENCES `student` (`id`) ON DELETE CASCADE;
--
-- Filtros para la tabla `supervisor`
--
ALTER TABLE `supervisor`
ADD CONSTRAINT `supervisor_ibfk_1` FOREIGN KEY (`id_off`) REFERENCES `office` (`id`);
--
-- Filtros para la tabla `try`
--
ALTER TABLE `try`
ADD CONSTRAINT `try_ibfk_1` FOREIGN KEY (`id_ws`) REFERENCES `working_session` (`id`) ON DELETE CASCADE;
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
--
-- Filtros para la tabla `working_session`
-- Temporary view structure for view `v_stu_last_instruction`
--
ALTER TABLE `working_session`
ADD CONSTRAINT `fk_ins_ws` FOREIGN KEY (`id_ins`) REFERENCES `instruction` (`id`),
ADD CONSTRAINT `working_session_ibfk_1` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`);
DROP TABLE IF EXISTS `v_stu_last_instruction`;
/*!50001 DROP VIEW IF EXISTS `v_stu_last_instruction`*/;
SET @saved_cs_client = @@character_set_client;
SET character_set_client = utf8;
/*!50001 CREATE VIEW `v_stu_last_instruction` AS SELECT
1 AS `id_ws`,
1 AS `ws_begin`,
1 AS `ws_end`,
1 AS `ws_description`,
1 AS `ins_name`,
1 AS `met_name`,
1 AS `id_stu`*/;
SET character_set_client = @saved_cs_client;
--
-- Estructura para la vista `v_stu_last_instruction`
-- Temporary view structure for view `v_stu_last_ws_time`
--
CREATE ALGORITHM=UNDEFINED
VIEW `v_stu_last_ws_time` AS
SELECT M.`id_stu` AS id_stu,
MAX(WS.begin) AS time
FROM
`working_session` AS WS join
`instruction` AS I join
`method` AS M
WHERE
WS.`id_ins` =I.`id`
and I.`id_met` = M.`id`
group by M.`id_stu`;
CREATE ALGORITHM=UNDEFINED
VIEW `v_stu_last_instruction` AS
select
WS.`id` AS `id_ws`,
WS.`begin` AS `ws_begin`,
WS.`end` AS `ws_end`,
WS.`description` AS `ws_description`,
I.`name` AS `ins_name`,
M.`name` AS `met_name`,
M.`id_stu` AS `id_stu`
FROM
`working_session` AS WS join
`instruction` AS I join
`method` AS M join
`v_stu_last_ws_time` AS LAST_WS
WHERE
LAST_WS.time = WS.begin and
LAST_WS.id_stu = M.`id_stu` and
WS.`id_ins` =I.`id`
and I.`id_met` = M.`id`;
DROP TABLE IF EXISTS `v_stu_last_ws_time`;
/*!50001 DROP VIEW IF EXISTS `v_stu_last_ws_time`*/;
SET @saved_cs_client = @@character_set_client;
SET character_set_client = utf8;
/*!50001 CREATE VIEW `v_stu_last_ws_time` AS SELECT
1 AS `id_stu`,
1 AS `time`*/;
SET character_set_client = @saved_cs_client;
--
-- VIEW `v_stu_last_instruction`
-- Datos: Ninguna
-- Table structure for table `working_session`
--
--
-- Vista materializada mv_stu_last_working_session_detail
-- Mantenida por
-- Utilizada por SAILS:StudentController.lasttries
--
--
-- CREATE TABLE mv_stu_last_working_session_detail IF NOT EXISTS `mv_stu_last_working_session_detail` (
-- `id` int(11) NOT NULL AUTO_INCREMENT,
-- PRIMARY KEY (`id`),
-- KEY `id_sup` (`id_sup`),
-- KEY `id_ins` (`id_ins`)
-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
DROP TABLE IF EXISTS `working_session`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `working_session` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_sup` int(11) NOT NULL,
`id_ins` int(11) NOT NULL,
`begin` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`end` timestamp(3) NULL DEFAULT NULL,
`current` tinyint(1) DEFAULT '1',
`description` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_ws_supcur` (`id_sup`,`current`),
KEY `id_sup` (`id_sup`),
KEY `id_ins` (`id_ins`),
KEY `ix_ws_begin` (`begin`),
CONSTRAINT `fk_ins_ws` FOREIGN KEY (`id_ins`) REFERENCES `instruction` (`id`),
CONSTRAINT `working_session_ibfk_1` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='This table stores working session information. Every working session is related to one instruction and one supervisor (and the instruction is related to one method which is related to one student)';
/*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_SESSION_NEW
AFTER INSERT ON working_session
FOR EACH ROW
thisTrigger: BEGIN
DECLARE idstu INT;
DECLARE ins_begin DATE;
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_INSERT_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
SELECT begin INTO ins_begin
FROM instruction
WHERE id = NEW.id_ins;
IF (ins_begin IS NULL) THEN
UPDATE instruction
SET
begin = NOW(3),
end = NOW(3)
WHERE
id = NEW.id_ins;
END IF;
UPDATE instruction
SET
status='started',
end = NOW(3)
WHERE
id = NEW.id_ins;
INSERT INTO try(`id_ws`)
VALUES (new.id);
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_SESSION_CLOSING
BEFORE UPDATE ON working_session
FOR EACH ROW
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;
DELETE FROM stu_opentry
WHERE id_ws = new.id;
DELETE FROM `try`
WHERE
end = NULL AND
id_ws = new.id;
END IF;
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client = utf8 */ ;
/*!50003 SET character_set_results = utf8 */ ;
/*!50003 SET collation_connection = utf8_general_ci */ ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER TRG_SESSION_CLOSED
AFTER UPDATE ON working_session
FOR EACH ROW
thisTrigger: BEGIN
IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_UPDATE_CHECKS = FALSE))
AND (USER() = 'root@localhost')
THEN
LEAVE thisTrigger;
END IF;
IF (OLD.end < NEW.end) THEN
UPDATE instruction
SET
end = NEW.end
WHERE
id = NEW.id_ins;
END IF;
IF ((old.end IS NULL) and (new.end IS NOT NULL)) THEN
CALL deleteOpenTry(new.id);
END IF;
END */;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
/*!50003 SET character_set_client = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection = @saved_col_connection */ ;
--
-- Final view structure for view `v_stu_last_instruction`
--
/*!50001 DROP VIEW IF EXISTS `v_stu_last_instruction`*/;
/*!50001 SET @saved_cs_client = @@character_set_client */;
/*!50001 SET @saved_cs_results = @@character_set_results */;
/*!50001 SET @saved_col_connection = @@collation_connection */;
/*!50001 SET character_set_client = utf8 */;
/*!50001 SET character_set_results = utf8 */;
/*!50001 SET collation_connection = utf8_general_ci */;
/*!50001 CREATE ALGORITHM=UNDEFINED */
/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */
/*!50001 VIEW `v_stu_last_instruction` AS select `WS`.`id` AS `id_ws`,`WS`.`begin` AS `ws_begin`,`WS`.`end` AS `ws_end`,`WS`.`description` AS `ws_description`,`I`.`name` AS `ins_name`,`M`.`name` AS `met_name`,`M`.`id_stu` AS `id_stu` from (((`working_session` `WS` join `instruction` `I`) join `method` `M`) join `v_stu_last_ws_time` `LAST_WS`) where ((`LAST_WS`.`time` = `WS`.`begin`) and (`LAST_WS`.`id_stu` = `M`.`id_stu`) and (`WS`.`id_ins` = `I`.`id`) and (`I`.`id_met` = `M`.`id`)) */;
/*!50001 SET character_set_client = @saved_cs_client */;
/*!50001 SET character_set_results = @saved_cs_results */;
/*!50001 SET collation_connection = @saved_col_connection */;
--
-- Final view structure for view `v_stu_last_ws_time`
--
/*!50001 DROP VIEW IF EXISTS `v_stu_last_ws_time`*/;
/*!50001 SET @saved_cs_client = @@character_set_client */;
/*!50001 SET @saved_cs_results = @@character_set_results */;
/*!50001 SET @saved_col_connection = @@collation_connection */;
/*!50001 SET character_set_client = utf8 */;
/*!50001 SET character_set_results = utf8 */;
/*!50001 SET collation_connection = utf8_general_ci */;
/*!50001 CREATE ALGORITHM=UNDEFINED */
/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */
/*!50001 VIEW `v_stu_last_ws_time` AS select `M`.`id_stu` AS `id_stu`,max(`WS`.`begin`) AS `time` from ((`working_session` `WS` join `instruction` `I`) join `method` `M`) where ((`WS`.`id_ins` = `I`.`id`) and (`I`.`id_met` = `M`.`id`)) group by `M`.`id_stu` */;
/*!50001 SET character_set_client = @saved_cs_client */;
/*!50001 SET character_set_results = @saved_cs_results */;
/*!50001 SET collation_connection = @saved_col_connection */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2017-08-10 11:20:52
......@@ -4,434 +4,46 @@ SET foreign_key_checks = 0;
SET @TRIGGER_CHECKS = FALSE;
--
-- Oficina
-- Dumping data for table `supervisor`
--
INSERT INTO `office` (
`name`,
`address`,
`country`,
`contact_person`,
`email`,
`phone1`,
`lang`,
`postal_code`
) VALUES (
'Comunicación Aumentativa JAén (CAJA)',
'Paraje Las Lagunillas, Ed A3, primera plata, 23071. Jaén',
'ES',
'Fernando Martínez Santiago',
'dofer@ujaen.es',
'+34 953 21 28 88',
'es-es',
'23071'
);
LOCK TABLES `supervisor` WRITE;
/*!40000 ALTER TABLE `supervisor` DISABLE KEYS */;
INSERT INTO `supervisor` VALUES (-1,'none','none','M','defaultAvatar.jpg',NULL,'',NULL,'',NULL,'es-es',NULL,'',0,0,'tutor'),(23,'Comunicación Aumentativa JAén (CAJA)','','M','test_caja_dofer.jpg',NULL,'23071',NULL,'dofer@ujaen.es','+34953212888','es-es',NULL,'$2a$10$Q4jHNlC58.ptfl/5wZeHfOIvpJslJHKOFNZO3bWs4it7TifQPQnEa',1,0,'office'),(24,'Miguel Ángel','García Cumbreras','M','test_caja_miguel.jpg',NULL,'23071',NULL,'magc@ujaen.es','+34953212420','es-es',NULL,'$2a$04$XQvWUwGTvjR47ChPwd3f6ukx8Zg.7o1N4Kf6P.zqhVtQxVNArOsXi',1,0,'therapist'),(25,'Arturo','Montejo Ráez','M','test_caja_arturo.jpg',NULL,'23071',NULL,'amontejo@ujaen.es','+34953212882','es-es',NULL,'$2a$04$yoBXAMSgCVGSIr2pnuIOw.J8UCm8f2XkATu5rqsMJiEmlxBHs5.cO',1,0,'therapist'),(26,'Alfonso','Ureña López','M','test_caja_alfonso.jpg',NULL,'23071',NULL,'laurena@ujaen.es','+34953212895','es-es',NULL,'$2a$04$zVGHJFafoZa60wo1yBqF/Oi3RXV/qS2cq0/j/W3Dkf4P1ad0e7.iS',1,0,'therapist'),(27,'Jesús','Navarro Moreno','M','defaultAvatar.jpg',NULL,'23071',NULL,'jnavarro@ujaen.es','+34953211912','es-es',NULL,'$2a$04$8O3Jd5j9/nM/KC.b1a8qRevyUwWUx6XGU3Gm754Y/8PpLO2jv.i76',1,0,'therapist'),(28,'Don Fernando','Padre Fernandito','M','defaultAvatar.jpg','C/ Mayor, 13. Jaén','23071','ES','donfernando@gmail.com','+34 232 232 232','es-es',NULL,'$2a$04$DMOX/cZ4h6cNJW9VlCou7O266q4YDYuS6p0QzP.gBHd08.QnFQWD.',1,0,'tutor'),(29,'Don Arturo','Padre Arturito','M','defaultAvatar.jpg','Avda. Andalucía 1. Jaén','23071','ES','donarturo@gmail.com',NULL,'es-es',NULL,'$2a$04$V2ods9MMmOFvdLTaHJqk3ejKEYdf28gvfDhaBkOSLCFJOC02TweFK',1,0,'tutor'),(30,'Don Miguel','Padre Miguelito','F','defaultAvatar.jpg','C/ Calatrava, 13. Córdoba','23071','ES','donmiguel@gmail.com',NULL,'es-es',NULL,'$2a$04$1UCak614LKz6WpDBtOblQeqFF41tOMy6ERMnP2OuGVZffe8Yi0mJq',1,0,'tutor'),(31,'Don Alfonso','Padre Alfonsito','M','defaultAvatar.jpg','Avda. Andalucía 1. Jaén','23071','ES','donalfonso@gmail.com',NULL,'es-es',NULL,'$2a$06$UtyBV4tLlT7xSqIt8LKPBucGvZ.Wgf7RgGE0fRcjEBDwjxjHlsP3K',1,0,'tutor'),(32,'Doña Alfonsa','Madre Alfonsita','F','defaultAvatar.jpg','C/ Calatrava, 13. Córdoba','23071','ES','doñaalfonsa@gmail.com',NULL,'es-es',NULL,'$2a$04$ALDmQ1oRhRZKUEi1b0eK1ehQmSZiFkhzx48ZBwER0J4vakvlYc5VS',1,0,'tutor'),(33,'Don Jesús','Padre Jesusito','M','defaultAvatar.jpg','Avda. Andalucía 1. Jaén','23071','ES','donjesus@gmail.com',NULL,'es-es',NULL,'$2a$04$Psuu6IMPUj1sbzR.uxq3EOgX1/4dFNmccjkv76LhKp35JzpiCE.fm',1,0,'tutor');
/*!40000 ALTER TABLE `supervisor` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Supervisores
-- Dumping data for table `sup_off`
--
INSERT INTO `supervisor` (
`name`,
`surname`,
`gender`,
`address`,
`email`,
`phone`,
`lang`,
`password`,
`active`,
`postal_code`,
`id_off`,
`pic`
) VALUES (
'Fernando',
'Martínez Santiago',
'M',
NULL,
'dofer@ujaen.es',
'+34953212888',
'es-es',
'$2a$10$Q4jHNlC58.ptfl/5wZeHfOIvpJslJHKOFNZO3bWs4it7TifQPQnEa',
true,
'23071',
(SELECT id from office where email='dofer@ujaen.es'),
'test_caja_dofer.jpg'
), (
'Miguel Ángel',
'García Cumbreras',
'M',
NULL,
'magc@ujaen.es',
'+34953212420',
'es-es',
'$2a$04$XQvWUwGTvjR47ChPwd3f6ukx8Zg.7o1N4Kf6P.zqhVtQxVNArOsXi',
true,
'23071',
(SELECT id from office where email='dofer@ujaen.es'),
'test_caja_miguel.jpg'
), (
'Arturo',
'Montejo Ráez',
'M',
NULL,
'amontejo@ujaen.es',
'+34953212882',
'es-es',
'$2a$04$yoBXAMSgCVGSIr2pnuIOw.J8UCm8f2XkATu5rqsMJiEmlxBHs5.cO',
true,
'23071',
(SELECT id from office where email='dofer@ujaen.es'),
'test_caja_arturo.jpg'
), (
'Alfonso',
'Ureña López',
'M',
NULL,
'laurena@ujaen.es',
'+34953212895',
'es-es',
'$2a$04$zVGHJFafoZa60wo1yBqF/Oi3RXV/qS2cq0/j/W3Dkf4P1ad0e7.iS',
true,
'23071',
(SELECT id from office where email='dofer@ujaen.es'),
'test_caja_alfonso.jpg'
), (
'Jesús',
'Navarro Moreno',
'M',
NULL,
'jnavarro@ujaen.es',
'+34953211912',
'es-es',
'$2a$04$8O3Jd5j9/nM/KC.b1a8qRevyUwWUx6XGU3Gm754Y/8PpLO2jv.i76',
true,
'23071',
(SELECT id from office where email='dofer@ujaen.es'),
'defaultAvatar.jpg'
);
LOCK TABLES `sup_off` WRITE;
/*!40000 ALTER TABLE `sup_off` DISABLE KEYS */;
INSERT INTO `sup_off` VALUES (-1,NULL),(28,NULL),(29,NULL),(30,NULL),(31,NULL),(32,NULL),(33,NULL),(23,23),(24,23),(25,23),(26,23),(27,23);
/*!40000 ALTER TABLE `sup_off` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Tutores
-- Dumping data for table `stu_sup`
--
INSERT INTO `supervisor` (
`name`,
`surname`,
`gender`,
`address`,
`country`,
`email`,
`phone`,
`lang`,
`password`,
`active`,
`postal_code`
) VALUES (
'Don Fernando',
'Padre Fernandito',
'M',
'C/ Mayor, 13. Jaén',
'ES',
'donfernando@gmail.com',
'+34 232 232 232',
'es-es',
'$2a$04$DMOX/cZ4h6cNJW9VlCou7O266q4YDYuS6p0QzP.gBHd08.QnFQWD.',
true,
'23071'
), (
'Don Arturo',
'Padre Arturito',
'M',
'Avda. Andalucía 1. Jaén',
'ES',
'donarturo@gmail.com',
NULL,
'es-es',
'$2a$04$V2ods9MMmOFvdLTaHJqk3ejKEYdf28gvfDhaBkOSLCFJOC02TweFK',
true,
'23071'
), (
'Don Miguel',
'Padre Miguelito',
'F',
'C/ Calatrava, 13. Córdoba',
'ES',
'donmiguel@gmail.com',
NULL,
'es-es',
'$2a$04$1UCak614LKz6WpDBtOblQeqFF41tOMy6ERMnP2OuGVZffe8Yi0mJq',
true,
'23071'
), (
'Don Alfonso',
'Padre Alfonsito',
'M',
'Avda. Andalucía 1. Jaén',
'ES',
'donalfonso@gmail.com',
NULL,
'es-es',
'$2a$06$UtyBV4tLlT7xSqIt8LKPBucGvZ.Wgf7RgGE0fRcjEBDwjxjHlsP3K',
true,
'23071'
), (
'Doña Alfonsa',
'Madre Alfonsita',
'F',
'C/ Calatrava, 13. Córdoba',
'ES',
'doñaalfonsa@gmail.com',
NULL,
'es-es',
'$2a$04$ALDmQ1oRhRZKUEi1b0eK1ehQmSZiFkhzx48ZBwER0J4vakvlYc5VS',
true,
'23071'
), (
'Don Jesús',
'Padre Jesusito',
'M',
'Avda. Andalucía 1. Jaén',
'ES',
'donjesus@gmail.com',
NULL,
'es-es',
'$2a$04$Psuu6IMPUj1sbzR.uxq3EOgX1/4dFNmccjkv76LhKp35JzpiCE.fm',
true,
'23071'
);
LOCK TABLES `stu_sup` WRITE;
/*!40000 ALTER TABLE `stu_sup` DISABLE KEYS */;
INSERT INTO `stu_sup` VALUES (27,19,23),(30,19,28),(28,20,23),(48,21,23),(31,21,24),(35,21,30),(49,22,23),(32,22,24),(34,22,25),(29,23,23),(33,23,24),(36,23,25),(38,23,29),(26,24,23),(37,24,25),(39,24,27),(50,25,23),(44,25,26),(47,25,32),(51,26,23),(43,26,26),(46,26,31),(52,27,23),(41,27,27),(53,28,23),(45,28,26),(40,28,27),(42,28,33);
/*!40000 ALTER TABLE `stu_sup` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Actualización de `office` con el id del supervisor admin
-- Dumping data for table `student`
--
UPDATE office
SET admin=(SELECT id FROM supervisor where email='dofer@ujaen.es')
WHERE email='dofer@ujaen.es';
LOCK TABLES `student` WRITE;
/*!40000 ALTER TABLE `student` DISABLE KEYS */;
INSERT INTO `student` VALUES (19,'faf0001','$2a$10$oy98CXG9YWbjATOESXelDu8HVjDHFPVpX5kmfdQSbkNC965Z2zPkC','Fernandito','Alumno Fernando','2009-12-10','M','ES','test_caja_juan.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"es\" }',NULL),(20,'faf0002','$2a$10$FOJ2fmJaHyI5sWe1tQojFuhoPpqHSTVPwvHPTpWEftFPI28VdyYNq','Fernandita','Alumna Fernando','2009-12-10','F','GB','test_caja_kate.jpg',NULL,'en-gb','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"en\" }',NULL),(21,'mam0001','$2a$10$zygC/WviDviyZQsMsNqK8.tSUI4Qr/dLlLrw0i5kR1bbN4SeU5ACq','Miguelín','Alumno Miguel','2009-12-10','M','ES','test_caja_carlos.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"es\" }',NULL),(22,'mam0002','$2a$10$xbyNUhf9rqhdXDBrvUSiOuJIzUVOyyz9ToQMCByFThiiiPwO0PWgK','Miguelita','Alumna Miguel','2009-12-10','F','ES','test_caja_rocio.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"en\" }',NULL),(23,'aaa0001','$2a$10$koWKIn42UNSi1N67akxjpOuJNwpXJ/vOe6biD2xkjrUz6dr3g.Wa.','Arturito','Alumno Arturo','2009-12-10','M','ES','test_caja_samuel.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"es\" }',NULL),(24,'aaa0002','$2a$10$ffAjZjWN0UKja0JO7ko6qup4x2phbY3VpC66TmpMnGdWUutBFeWY2','Arturita','Alumna Arturo','2009-12-10','F','ES','test_caja_adela.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"en\" }',NULL),(25,'aaa0003','$2a$10$glc5A6vyPve5.4407Vdkau5CHF3GOpA0Uo6rxMDdIopIWTJK0nBse','Alfonsita','Alumna Alfonso','2009-12-10','F','ES','test_caja_adela.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"en\" }',NULL),(26,'aaa0004','$2a$10$tezK07jq5ZMdQbCboubEBeHiXWJisZPAbgN301n5kRLXkq8xOlb4O','Alfonsito','Alumno Alfonso','2009-12-10','M','ES','test_caja_juan.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"en\" }',NULL),(27,'jaj0001','$2a$10$UQYGXOOE8mxxOjvgo8cjwOpsv5jCtRXpMTLpbD3TzMBiUIv3hXlnO','Jesusita','Alumna Jesús','2009-12-10','F','ES','test_caja_adela.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"en\" }',NULL),(28,'jaj0002','$2a$10$tVy3Wfu35l4B6bFpnjJCE.ckjncq6YCKMGW4B9abesbiFVeyGu2Dy','Jesusito','Alumno Jesús','2009-12-10','M','ES','test_caja_samuel.jpg',NULL,'es-es','{ \"categories\" : \"on\", \"input feedback\" : [ \"vibration\", \"tts\" ], \"input selection\" : \"click\", \"pictogram size\" : \"medium\", \"tts engine\" : \"IVONA Text-to-Speech HQ\", \"tts voice\": \"en\" }',NULL);
/*!40000 ALTER TABLE `student` ENABLE KEYS */;
UNLOCK TABLES;
--
-- CAJA Students
--
INSERT INTO `student` (
`username`,
`password`,
`name`,
`surname`,
`birthdate`,
`gender`,
`country`,
`pic`,
`notes`,
`lang`,
`attributes`
) VALUES (
'faf0001',
'$2a$10$oy98CXG9YWbjATOESXelDu8HVjDHFPVpX5kmfdQSbkNC965Z2zPkC',
'Fernandito',
'Alumno Fernando',
'2009-12-10',
'M',
'ES',
'test_caja_juan.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }'
), (
'faf0002',
'$2a$10$FOJ2fmJaHyI5sWe1tQojFuhoPpqHSTVPwvHPTpWEftFPI28VdyYNq',
'Fernandita',
'Alumna Fernando',
'2009-12-10',
'F',
'GB',
'test_caja_kate.jpg',
NULL,
'en-gb',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'mam0001',
'$2a$10$zygC/WviDviyZQsMsNqK8.tSUI4Qr/dLlLrw0i5kR1bbN4SeU5ACq',
'Miguelín',
'Alumno Miguel',
'2009-12-10',
'M',
'ES',
'test_caja_carlos.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }'
), (
'mam0002',
'$2a$10$xbyNUhf9rqhdXDBrvUSiOuJIzUVOyyz9ToQMCByFThiiiPwO0PWgK',
'Miguelita',
'Alumna Miguel',
'2009-12-10',
'F',
'ES',
'test_caja_rocio.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'aaa0001',
'$2a$10$koWKIn42UNSi1N67akxjpOuJNwpXJ/vOe6biD2xkjrUz6dr3g.Wa.',
'Arturito',
'Alumno Arturo',
'2009-12-10',
'M',
'ES',
'test_caja_samuel.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }'
), (
'aaa0002',
'$2a$10$ffAjZjWN0UKja0JO7ko6qup4x2phbY3VpC66TmpMnGdWUutBFeWY2',
'Arturita',
'Alumna Arturo',
'2009-12-10',
'F',
'ES',
'test_caja_adela.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'aaa0003',
'$2a$10$glc5A6vyPve5.4407Vdkau5CHF3GOpA0Uo6rxMDdIopIWTJK0nBse',
'Alfonsita',
'Alumna Alfonso',
'2009-12-10',
'F',
'ES',
'test_caja_adela.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'aaa0004',
'$2a$10$tezK07jq5ZMdQbCboubEBeHiXWJisZPAbgN301n5kRLXkq8xOlb4O',
'Alfonsito',
'Alumno Alfonso',
'2009-12-10',
'M',
'ES',
'test_caja_juan.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'jaj0001',
'$2a$10$UQYGXOOE8mxxOjvgo8cjwOpsv5jCtRXpMTLpbD3TzMBiUIv3hXlnO',
'Jesusita',
'Alumna Jesús',
'2009-12-10',
'F',
'ES',
'test_caja_adela.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'jaj0002',
'$2a$10$tVy3Wfu35l4B6bFpnjJCE.ckjncq6YCKMGW4B9abesbiFVeyGu2Dy',
'Jesusito',
'Alumno Jesús',
'2009-12-10',
'M',
'ES',
'test_caja_samuel.jpg',
NULL,
'es-es',
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
);
--
-- CAJA student-supervisor
--
INSERT INTO `stu_sup` (
id_stu,
id_sup
) VALUES (
(SELECT id FROM student WHERE username='aaa0002'),
(SELECT id FROM supervisor WHERE email='dofer@ujaen.es')
);
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Fernandito' and B.name='Fernando';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Fernandita' and B.name='Fernando';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Arturito' and B.name='Fernando';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Fernandito' and B.name='Don Fernando';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Miguelín' and B.name='Miguel Ángel';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Miguelita' and B.name='Miguel Ángel';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Arturito' and B.name='Miguel Ángel';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Miguelita' and B.name='Arturo';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Miguelín' and B.name='Don Miguel';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Arturito' and B.name='Arturo';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Arturita' and B.name='Arturo';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Arturito' and B.name='Don Arturo';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Arturita' and B.name='Jesús';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Jesusito' and B.name='Jesús';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Jesusita' and B.name='Jesús';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Jesusito' and B.name='Don Jesús';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Alfonsito' and B.name='Alfonso';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Alfonsita' and B.name='Alfonso';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Jesusito' and B.name='Alfonso';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Alfonsito' and B.name='Don Alfonso';
INSERT INTO `stu_sup`(id_stu,id_sup) SELECT DISTINCT A.id, B.id FROM student A, supervisor B WHERE A.name='Alfonsita' and B.name='Doña Alfonsa';
--
-- Student's CAJA offices
--
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Fernando') WHERE student.name='Fernandito';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Miguel Ángel') WHERE student.name='Miguelín';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Arturo') WHERE student.name='Arturito';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Fernando') WHERE student.name='Fernandita';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Miguel Ángel') WHERE student.name='Miguelita';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Arturo') WHERE student.name='Arturita';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Alfonso') WHERE student.name='Alfonsito';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Alfonso') WHERE student.name='Alfonsita';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Jesús') WHERE student.name='Jesusito';
UPDATE student SET id_off=(SELECT id_off FROM supervisor WHERE supervisor.name='Jesús') WHERE student.name='Jesusita';
// select a.name,b.attributes,text from student a, stu_picto b, picto c, picto_exp d where a.id=b.id_stu and b.id_pic=c.id and c.id=d.id_pic and a.id=23 and a.lang=d.lang;
--
-- CAJA Core vocabulary
--
--
-- INSERT INTO stu_picto(id_stu,id_pic,scene,attributes)
-- SELECT S.id,P.id_pic, concat('{"id_cat":', if (id_cat_pic is null, 'null',id_cat_pic),
-- ',"coord_x":',coord_x,
-- ',"coord_y":',coord_y,
-- ',"status":"invisible"',
-- ',"highlight":false',
-- ',"color":', if (color is null, 'null',concat('"',color,'"')),
-- '}') as attributes
-- FROM student S, picto_core P
-- WHERE S.id_off =(SELECT id from office where name='Comunicación Aumentativa JAén (CAJA)');
--
-- Test method
--
-- INSERT INTO meta_method(name) VALUES (
-- 'Test MetaMethod'
-- );
-- INSERT INTO method(name, id_stu) VALUES (
-- 'Test Method',
-- (SELECT id FROM student WHERE username='aaa0002')
-- );
-- INSERT INTO instruction(name, id_met) VALUES (
-- 'Test Instruction',
-- (SELECT id FROM method WHERE name='Test Method')
-- );
-- INSERT INTO working_session (id_sup, id_ins) VALUES (
-- (SELECT id FROM supervisor WHERE email='dofer@ujaen.es'),
-- (SELECT id FROM instruction WHERE name='Test Instruction')
-- );
SET @TRIGGER_CHECKS = TRUE;
SET foreign_key_checks=1;
......@@ -84,27 +84,26 @@ 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
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
DELETE
stu_sup
FROM
stu_sup INNER JOIN supervisor ON (stu_sup.id_sup=supervisor.id)
WHERE
id_stu=new.id AND old.id_off=supervisor.id_off;
END IF;
END IF;
END;;
DELIMITER ;
-- CREATE TRIGGER TRG_MODIFY_STUDENT_ENROLMENTS
-- AFTER UPDATE ON student
-- FOR EACH ROW
-- 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
-- DELETE
-- stu_sup
-- FROM
-- stu_sup INNER JOIN supervisor ON (stu_sup.id_sup=supervisor.id)
-- WHERE
-- id_stu=new.id AND old.id_off=supervisor.id_off;
-- END IF;
-- END IF;
-- END;;
SET foreign_key_checks = 0;
ALTER TABLE supervisor ADD role enum('tutor','therapist','office','admin') NOT NULL;
ALTER TABLE supervisor MODIFY name VARCHAR(40) DEFAULT NULL;
ALTER TABLE supervisor MODIFY surname VARCHAR(60) DEFAULT NULL;
ALTER TABLE supervisor MODIFY gender CHAR(1) DEFAULT NULL;
ALTER TABLE supervisor MODIFY postal_code CHAR(10) DEFAULT NULL;
ALTER TABLE supervisor MODIFY lang VARCHAR(5) DEFAULT NULL;
ALTER TABLE student MODIFY name VARCHAR(40) DEFAULT NULL;
ALTER TABLE student MODIFY surname VARCHAR(60) DEFAULT NULL;
ALTER TABLE student MODIFY birthdate DATE DEFAULT NULL;
ALTER TABLE student MODIFY gender CHAR(1) DEFAULT NULL;
ALTER TABLE student MODIFY country CHAR(2) DEFAULT NULL;
ALTER TABLE student MODIFY lang VARCHAR(5) DEFAULT NULL;
ALTER TABLE license ADD type enum('trial', 'official') NOT NULL DEFAULT 'official';
CREATE TABLE `sup_off` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_sup` int(11) NOT NULL,
`id_off` int(11) DEFAULT NULL,
KEY `fk_sup_off` (`id_sup`),
KEY `fk_off_sup` (`id_off`),
PRIMARY KEY(`id`),
UNIQUE KEY `idx_sup_off` (`id_sup`,`id_off`),
CONSTRAINT `fk_off_sup` FOREIGN KEY (`id_off`) REFERENCES `supervisor` (`id`),
CONSTRAINT `fk_sup_off` FOREIGN KEY (`id_sup`) REFERENCES `supervisor` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
UPDATE supervisor
SET role = 'office'
WHERE id IN (SELECT admin FROM office WHERE admin IS NOT NULL);
UPDATE supervisor
SET role = 'therapist'
WHERE id NOT IN (SELECT admin FROM office WHERE admin IS NOT NULL);
UPDATE supervisor
SET role = 'tutor'
WHERE id_off IS NULL;
UPDATE license
SET type = 'official'
WHERE type is not 'trial';
DELIMITER $$
DROP PROCEDURE IF EXISTS supervisor_adapt $$
CREATE PROCEDURE supervisor_adapt()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE id_admin INT;
DECLARE id_off_actual INT;
DECLARE name_sup VARCHAR(80);
DECLARE office CURSOR FOR SELECT id,name,admin FROM pictodb.office;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN office;
read_loop: LOOP
FETCH office INTO id_off_actual,name_sup,id_admin;
IF done THEN
LEAVE read_loop;
END IF;
UPDATE supervisor SET name = name_sup, surname = '',role = 'office'
WHERE id = id_admin;
UPDATE student SET id_off = id_admin WHERE id_off = id_off_actual;
UPDATE supervisor SET id_off = id_admin WHERE id_off = id_off_actual;
END LOOP;
CLOSE office;
END $$
DELIMITER ;
CALL supervisor_adapt();
INSERT IGNORE INTO stu_sup (id_stu,id_sup)
SELECT id,id_off
FROM student;
INSERT INTO sup_off (id_sup, id_off)
SELECT id, id_off
FROM supervisor;
ALTER TABLE student DROP FOREIGN KEY student_ibfk_1;
ALTER TABLE student DROP COLUMN id_off;
ALTER TABLE supervisor DROP FOREIGN KEY supervisor_ibfk_1;
ALTER TABLE supervisor DROP COLUMN id_off;
DROP TABLE office;
......@@ -5,10 +5,8 @@ the version of AngularJS used. In order to do show, type `bower install` from
*assets/app* directory.
## Database
Para actualizar instalaciones antiguas ejecutar en vagrant/roles/database/files
Create new tables
mysql -u root -p pictodb < upgrade.sql
Destroy *office* table: `drop table office`
Relanzar trigger-enrolments-integrity-constraints
......@@ -43,46 +43,10 @@ module.exports = {
var params = req.allParams();
function get_new_random_license (callback) {
function random_license () {
var length = 16;
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var result = '';
for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
return result;
}
var license;
var found = true;
var maxtries = 10;
async.doWhilst(
function (cb) {
license = random_license();
License.findOne({number: license})
.then((l) => {
if (!l)
found = false;
cb();
})
.catch((err) => {
found = false;
cb();
});
},
function () {
return found;
},
function () {
callback(license);
}
);
}
if (!params.duration || params.duration < 0)
return res.badRequest();
get_new_random_license(function (license) {
License.genLicenseNumber(function (license) {
License.create({
number: license,
duration: params.duration,
......
......@@ -2,11 +2,11 @@
Picto */
/**
/* StudentController
*
* @description :: Server-side logic for managing students
* @help :: See http://links.sailsjs.org/docs/controllers
*/
/* StudentController
*
* @description :: Server-side logic for managing students
* @help :: See http://links.sailsjs.org/docs/controllers
*/
module.exports = {
......@@ -61,7 +61,7 @@ module.exports = {
if (bcrypt.compareSync(req.body.password, student.password)) {
student.isStudent = true;
if (!student.license || !student.license[0]) {
sails.log.error(`Tried to login with non valid license ${req.body.username}`);
sails.log.error('Tried to login with non valid license ${req.body.username}');
res.unauthorized("Student has an invalid license");
} else {
var hasExpired = student.license[0].hasExpired();
......@@ -75,17 +75,16 @@ module.exports = {
});
}
} else {
sails.log.error(`Invalid student login: user ${student.username}, password\
"${req.body.password}"`);
sails.log.error('Invalid student login: user ${student.username}, password "${req.body.password}"');
res.unauthorized("Invalid username/password");
}
} else {
sails.log.error(`Tried to login as non-existing student ${req.body.username}`);
sails.log.error('Tried to login as non-existing student ${req.body.username}');
res.notFound("Student not found");
}
})
.catch(function (err) {
sails.log.error(`Error getting student ${req.body.username} for login: ` + err);
sails.log.error('Error getting student ${req.body.username} for login: ' + err);
res.serverError("Error when connecting to database");
});
},
......@@ -148,30 +147,15 @@ module.exports = {
.then(function (stu_sup) {
return stu_sup;
})
.error(err => {throw err});
.catch(function (err) { throw err });
return [student, stu_sup];
})
.spread(function (student, stu_sup) {
// requester has no relation
student.supervision = -1;
if (!stu_sup && req.token.office && student.office == req.token.office.id && req.token.isSupAdmin)
student.supervision = 0; // requester is admin of the office
else if (stu_sup && !req.token.office)
student.supervision = 1; // requester is tutor of the studend
else if (stu_sup && req.token.office)
student.supervision = 2; // requester is supervisor of student
else if (req.token.isStudent && req.token.id == student.id)
student.supervision = 3 // requester is the student himself
if (student.supervision == -1) // should not hace access!!!
return res.forbidden("Access to this student should not be granted to you");
// Promisify asynchronous call to Student.supervisors
var supervisors = new Promise(function(resolve, reject) {
Student.supervisors(student.id, (err, ss) => {
var supervisors = new Promise(function (resolve, reject) {
Student.validSupervisors(student.id, req.token.id, function (err, ss) {
if (err) return reject(err);
return resolve(ss);
});
......@@ -179,10 +163,9 @@ module.exports = {
return [student, supervisors];
})
.spread((student, supervisors) => {
.spread(function (student, supervisors) {
student = student.toJSON();
student.supervisors = supervisors;
console.log(JSON.stringify(supervisors));
console.log(JSON.stringify(student.supervisors));
return res.ok(student);
})
.catch(function (err) {
......@@ -190,31 +173,82 @@ module.exports = {
});
},
//
// Adds a new student into the database
//
/**
* Adds a new student into the database
* It inmediatly related to the supervisor who created it
* If no license is specified, a test one will be created
* @param {request} req {
* username,
* password,
* id_sup,
* lang
* license (optional)
* }
*/
create: function (req, res) {
var params = req.params.all();
License.isActivable(params.license_number, function(err) {
if (err)
return res.serverError(err);
var params = req.allParams();
Student.create(params)
.then(function(created) {
sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created));
License.activate(params.license_number, created.id, function(err, license) {
//
// License number, if passed is used, otherwise, a trial one is generated
//
new Promise(function(resolve, reject) {
if (params.license_number)
resolve(params.license_number);
else {
License.newTrial(params.id_sup, function(err, license) {
console.log(license.number);
if (err)
return res.serverError(err);
created = created.toJSON();
created.license = license.toObject();
return res.ok(created);
reject(err);
else
resolve(license.number);
});
}
})
.then((license_number) => {
// Check license
License.isActivable(license_number, function(err) {
if (err) {
return res.badRequest(err.message);
}
// Create student
Student.create(params)
.then(function(created) {
sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created));
// Activate license
License.activate(license_number, created.id, function(err, license) {
if (err) {
Student.destroy({id: created.id});
return res.badRequest(err);
}
created = created.toJSON();
created.license = license.toObject();
// Link to supervisor
StuSup.create({student: created.id, supervisor: params.id_sup})
.then((stu_sup) => {
if (!stu_sup) {
Student.destroy({id: created.id});
return res.serverError("Unable to link to supervisor");
}
return res.ok(created);
})
.catch((err) => {
Student.destroy({id: created.id});
throw err
});
});
})
.catch(function(err) {
sails.log.debug(err.message);
return res.serverError(err.message);
});
})
.error(function(err) {
sails.log.debug(err.message);
return res.serverError(err.message);
});
});
})
.catch((err) => {res.serverError(err)});
},
/**
......@@ -301,7 +335,7 @@ module.exports = {
/**
* Return all existing supervisor and therapist from a given student
* Return all existing supervisors for a given student that are in our office
* @param {request} req {} (with studentId as url parameter)
* @param {response} res
* [
......@@ -329,106 +363,89 @@ module.exports = {
error: 'No student defined'
});
}
Student.supervisors(req.params.id_stu, function (err, sups) {
Student.validSupervisors(req.params.id_stu, req.token.id, function (err, sups) {
if (err) throw err;
return res.json(sups);
});
},
/**
* Return all existing therapists from a given student
* @param {request} req {} (with studentId as url parameter)
* @param {response} res
* [
* {
* id: therapistId,
* name: 'John',
* surname: 'Doe',
* gender: 'M/F',
* pic: 'supervisor/avatar.jpg',
* address: 'My Address, n1',
* country: 'ES',
* email: 'john@doe.es',
* phone: '+123123123',
* lang: 'es-es',
* active: true,
* ttsEngine: 'IVONA-Text',
* office: officeId
* },
* ...
* ]
*/
therapists: function (req, res) {
if (!req.params.id_stu) {
return res.json(500, {
error: 'No student defined'
});
}
Student.therapists(req.params.id_stu, function (err, sups) {
if (err) throw err;
return res.json(sups);
});
},
/**
* Return all existing tutors from a given student
* @param {request} req {} (with studentId as url parameter)
* @param {response} res
* [
* {
* id: tutorId,
* name: 'John',
* surname: 'Doe',
* gender: 'M/F',
* pic: 'supervisor/avatar.jpg',
* address: 'My Address, n1',
* country: 'ES',
* email: 'john@doe.es',
* phone: '+123123123',
* lang: 'es-es',
* active: true,
* ttsEngine: 'IVONA-Text',
* office: officeId
* },
* ...
* ]
*/
tutors: function (req, res) {
if (!req.params.id_stu) {
return res.json(500, {
error: 'No student defined'
});
}
Student.tutors(req.params.id_stu, function (err, sups) {
if (err) throw err;
return res.json(sups);
});
},
/**
* Creates a relation between the student and a given supervisor.
* It broadcasts the event linkSupervisorToStudent to both the student room
* and the supervisor room.
* @param {request} { (with id_stu and id_sup as url parameters)
* asTherapist: true/false (optional) // assigns supervisor to student's office is true, set id_off to null otherwise
* @param {request} { (with id_stu and id_sup as url parameters or with license and id_sup)
* }
* @param {response} {}
*/
link_supervisor: function (req, res) {
StuSup.create({
student: req.param('id_stu'),
supervisor: req.param('id_sup')
var params = req.allParams();
// Check input parameters coherence
if (!params.id_sup || !params.id_stu && !params.license)
return res.badRequest("Invalid params");
var stu, stuSup;
//
// Get student ID either because we got it or through a license
// As it can be resolved through two possibilities, better to use promises!
//
var getStudent = new Promise(function(resolve, reject) {
if (!params.id_stu && params.license) {
// get student, license attribute will be completed
License.getStudent(params.license, function(err, s) {
if (err)
reject(err);
else
resolve(s);
});
} else
Student.findOne(params.id_stu)
.populate('license')
.then((s) => {
if (!s)
throw new Error("Student not found");
resolve(s);
})
.catch((err) => {reject(err)});
});
getStudent
.then((s) => {
stu = s;
//
// Let's check it is not already linked
//
return StuSup.findOne({ student: stu.id, supervisor: params.id_sup });
})
.then(function (stuSup) {
if (!stuSup)
.then((ss) => {
if (ss)
throw new Error('Student already linked');
return StuSup.create({
student: stu.id,
supervisor: params.id_sup
});
})
.then((ss) => {
if (!ss)
throw new Error('stusup not created');
stuSup = ss;
//
// Send sockets messages
//
const socketToOmit = (req.isSocket) ? req.socket : undefined;
const linkSupervisorToStudentEvent = sails.hooks.events.linkSupervisorToStudent(
stuSup.supervisor,
stuSup.student
);
sails.hooks.events.broadcastEvent(
sails.hooks.rooms.supervisor(stuSup.supervisor),
linkSupervisorToStudentEvent,
......@@ -440,40 +457,14 @@ module.exports = {
socketToOmit
);
return stuSup;
//
// Done!
//
return res.ok(stu);
})
.catch((err) => {
StuSup.findOne({ student: req.param('id_stu'), supervisor: req.param('id_sup') })
.then((stuSup) => {
// It was already there!
if (stuSup)
return stuSup;
else
throw err;
});
})
.then((stuSup) => {
// update supervisor office if it is linked as therapist
Supervisor.findOne({id: req.param('id_sup')})
.then((sup) => {
if (sup && !sup.office) {
Student.findOne({id: req.param('id_stu')})
.then((stu) => {
if (stu) {
if (req.body.asTherapist)
sup.office = stu.office;
else
sup.office = null;
delete sup.password;
sup.save();
}
});
}
});
return res.ok();
})
.catch((err) => {
return res.serverError("Error: " + err);
console.log("Error " + err.message);
return res.serverError(err);
});
},
......@@ -838,28 +829,27 @@ module.exports = {
* @param {response} res {}
*/
getActiveScene: function(req, res){
if (typeof req.params.id_stu == 'undefined' || !req.params.id_stu)
return res.badRequest("id_stu not defined");
Student.findOne({id:req.params.id_stu}).then(function(student){
Scene.findOne({id: student.id_active_scene})
.then(function(scene){
if(!scene)
return res.badRequest("Scene not found");
else
Scene.pictos(scene.id, function(err, pictos){
if (err){
return res.serverError("Error obtaining pictos: "+ err);
}
scene.active = true;
scene.pictos=pictos;
return res.ok(scene);
});
}).catch(function (err){
return res.serverError("Error finding scene "+err);
});
}).catch(function(err){
return res.badRequest("Student not found");
if (typeof req.params.id_stu == 'undefined' || !req.params.id_stu)
return res.badRequest("id_stu not defined");
Student.findOne(req.params.id_stu)
.then(function(student) {
if (!student)
throw new Error("Student not found")
return Scene.findOne({id: student.id_active_scene});
})
.then(function(scene){
if(!scene)
throw new Error("Scene not found");
Scene.pictos(scene.id, function(err, pictos){
if (err)
return res.serverError("Error obtaining pictos: "+ err);
scene.active = true;
scene.pictos=pictos;
return res.ok(scene);
});
}).catch(function(err){
return res.badRequest(err.message);
});
},
/**
......@@ -1000,7 +990,7 @@ module.exports = {
})
.then((student) => {
if (!student) {
sails.log.error(`Student ${params.id_stu} not found`);
sails.log.error('Student ${params.id_stu} not found');
throw new Error("Student not found");
}
......@@ -1013,7 +1003,7 @@ module.exports = {
})
.spread((picto, student) => {
if (!picto) {
sails.log.error(`Picto ${params.id_picto} not found`);
sails.log.error('Picto ${params.id_picto} not found');
throw new Error("Picto not found");
}
......
......@@ -58,7 +58,6 @@ module.exports = {
* - 400 (Bad request) with error message "Missing parameters"
* - 401 (Unauthorized) with error message "Invalid email/password"
* - 404 (Not found) with error message "Supervisor not found"
* - 401 (Unauthorized) with error message "Supervisor without students"
* - 500 (Server error) with error message "Error when connecting to database"
*/
login: function (req, res) {
......@@ -83,35 +82,12 @@ module.exports = {
}).then(function (supervisor) {
var stuSup = StuSup.findOne({id_sup: supervisor.id})
.then(function (stuSup) {
return stuSup;
});
var office = Office.findOne({id: supervisor.office})
.then(function (office) {
return office;
});
return [office, stuSup, supervisor];
}).spread(function(office, stuSup, supervisor) {
if (office) {
supervisor.office = office;
supervisor.isSupAdmin = (office.admin === supervisor.id);
}
if (!supervisor.isSupAdmin && !stuSup)
throw new Error("Supervisor without students");
supervisor.isSup = true;
return res.ok({
user: supervisor,
server_time: (new Date()).getTime(),
token: sailsTokenAuth.issueToken(supervisor, sails.config.jwt.expiresInMinutes)
});
})
.catch(function (err) {
return res.badRequest(err.message);
......@@ -155,31 +131,6 @@ module.exports = {
delete supervisor.password;
supervisor.save();
// an email has to be sent to office administrators
if (token.role == 'tutor_office' || token.role === 'therapist_office') {
Office.findOne(token.id_off)
.populate('admin')
.then((off) => {
if (!off)
throw new Error("Office not found: ");
var message = sails.__({
phrase: token.role + '_request',
locale: supervisor.lang
}, {name: supervisor.name + " " + supervisor.surname, email: supervisor.email});
mailService.mailer()
.send({
to: off.admin.email,
text: message
})
.then(() => {})
.catch((err) => {throw err});
})
.catch((err) => {throw err;});
}
// welcome message is returned
return res.view('accountActivated', {
welcome_msg1: sails.__({
......@@ -247,59 +198,88 @@ module.exports = {
* }
*/
getByEmail: function (req, res) {
Supervisor.findOne({ email: req.params.email }).then(function (supervisor) {
if (supervisor) {
res.ok(supervisor);
} else {
res.notFound();
}
// Find supervisor
Supervisor.findOne({ email: req.params.email })
.then((s) => {
if (!s)
throw new Error("Not found");
res.ok(s);
})
.catch(function () {
res.serverError();
.catch(function (err) {
res.serverError(err);
});
},
/**
* Creates a new Supervisor instance
* Important: The user's email needs to be validated after registering in order to use
* the new account.
* @param {request} req
* Gets a supervisor by his email (only those that are related to us)
* @param {request} req {} (width email 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"
* "address": "Nice street" (optional)
* "country": "ES/UK/..." (optional)
* "phone": "+123456789" (optional)
* "lang": "ES/EN/..." (optional)
* "ttsEngine: "IVONA Text-to-Speech HQ" (optional)
* "phone": "+123456789"
* "lang": "ES/EN/..."
* "ttsEngine: "IVONA Text-to-Speech HQ"
* }
*/
getFromOfficeByEmail: function (req, res) {
// Find supervisor
Supervisor.findOne({ email: req.params.email })
.then((s) => {
if (!s)
throw new Error("Not found");
// Check is in our office
return SupOff.findOne({supervisor: s.id, office: req.token.id}).populate('supervisor');
})
.then((so) => {
if (!so)
throw new Error("Not in our office");
res.ok(so.supervisor);
})
.catch(function (err) {
res.serverError(err);
});
},
/**
* Creates a new Supervisor instance
* Important: The user's email needs to be validated after registering in order to use
* the new account.
* @param {request} req
* {
* "email": "john@doe.com"
* "password": "2nsodncoiaw3r4"
* "lang": "es-es"
* "role": "tutor"
* }
* @param {response} res
* {
* "user": {
* "id": 123
* "name": "John"
* "gender": "M"
* ... (same information specified in the request, without password)
* "email": "john@doe.com"
* "role": "tutor"
* "lang": "es-es"
* },
* "token": "...as892..."
* }
*/
create: function (req, res) {
var params = req.params.all();
var supervisor;
// Send email confirmation
function sendConfirmationMail(cb) {
console.log("mail------------\n" + JSON.stringify(supervisor));
// Send email confirmation --------------------------------
function sendConfirmationMail(supervisor, cb) {
var token = sailsTokenAuth.issueToken({
id_sup: supervisor.id,
role: params.role,
id_off: params.id_off,
}, 60*24*7); // expires in 1 week
var message = sails.__({
......@@ -317,70 +297,32 @@ module.exports = {
})
.then(() => {cb();})
.catch((err) => {cb(err);});
} // /sendConfirmationEmail()
} // ------------------------------ /sendConfirmationEmail()
sails.log.debug("Creating supervisor with params " + JSON.stringify(params));
if (!params.name || !params.surname || !params.gender || !params.password || !params.email )
if (!params.password || !params.email )
return res.badRequest("Invalid params");
var supData = {
name: params.name,
surname: params.surname,
gender: params.gender,
role: params.role,
name: typeof params.name == 'undefined' ? '' : params.name,
password: params.password,
email: params.email,
pic: sails.config.pictogram.paths.defaultAvatarFileName,
address: params.address || '',
postal_code: params.postalCode || '',
country: params.country || '',
phone: params.phone || '',
lang: params.lang || 'es-es',
};
if (params.id_off && params.role == 'therapist_office')
supData.id_off = params.id_off;
console.log(JSON.stringify(supData));
Supervisor.create(supData)
.then(function (sup) {
if (!sup)
return res.serverError("Supervisor created but returned null");
supervisor = sup;
if (params.role === 'therapist_office' || params.role === 'tutor_office') {
sendConfirmationMail((err) => {
if (err) throw err;
return res.ok();
});
} else if (params.role === 'therapist_nooffice' || params.role === 'tutor_nooffice') {
Office.create(params.office)
.then((off) => {
// link supervisor with office
console.log("supervisor: \n" + JSON.stringify(sup));
sup.id_off = off.id;
delete sup.password;
sup.save();
console.log("supervisor: \n" + JSON.stringify(sup));
// set supervisor as admin in the office
off.admin = sup.id;
off.save();
supervisor = sup;
sendConfirmationMail((err) => {
if (err) return res.serverError("Confirmation mail could not be sent: " + err);
return res.ok();
});
})
.catch((err) => {
return res.serverError("Supervisor could not be created: " + err);
});
} else
return res.badRequest("Invalid role");
sendConfirmationMail(sup, (err) => {
if (err) throw err;
return res.ok();
});
}).catch(function (err) {
return res.serverError("Supervisor could not be created: " + err);
});
......@@ -484,7 +426,6 @@ module.exports = {
delete supervisor.password;
if (req.body.password && req.body.password.length > 0)
supervisor.password = req.body.password;
console.log(supervisor.password);
supervisor.name = req.body.name || supervisor.name;
supervisor.surname = req.body.surname || supervisor.surname;
supervisor.gender = req.body.gender || supervisor.gender;
......@@ -496,7 +437,6 @@ module.exports = {
supervisor.phone = req.body.phone || supervisor.phone;
supervisor.lang = req.body.lang || supervisor.lang;
supervisor.ttsEngine = req.body.ttsEngine || supervisor.ttsEngine;
supervisor.office = req.body.office || supervisor.office;
supervisor.save(function (error) {
if (error) throw error;
return res.ok(supervisor);
......@@ -539,7 +479,144 @@ module.exports = {
});
},
/**
/**
* Get all supervisors in the database that are linked to the user as office.
* @param {request} req //
* {
id {ID} ID of the office (as a GET parameter)
}
* @param {response} res
* [
* {
* "id": 123,
* "name": "John"
* "surname": "Doe"
* "gender": "F/M"
* "password": "1234"
* "pic": "url/to/photo.jpg" (optional)
* "address": "Nice street" (optional)
* "country": "ES/UK/..." (optional)
* "email": "john@doe.com" (optional)
* "phone": "+123456789" (optional)
* "lang": "ES/EN/..." (optional)
* "tts_engine": "IVONA Text-to-Speech HQ" (optional)
* },
* ...
* ]
*/
supervisors: function (req, res) {
if (!req.params.id)
return res.badRequest("Supervisor ID missing");
var enriched_sups = [];
SupOff.find({office: req.params.id})
.populate('supervisor')
.then(function (supOffs) {
var sups = supOffs.map(so => so.supervisor);
async.eachSeries(sups, function (sup, next) {
if (!sup) return next();
Supervisor.commonStudents(sup.id, req.params.id, function (err, stus) {
if (err)
return next(err);
sup = sup.toJSON();
if (!stus || stus.length == 0)
sup.students = [];
else
sup.students = stus;
enriched_sups.push(sup);
next();
});
},
function (err) {
if (err) throw err;
else res.ok(enriched_sups);
});
})
.catch(function (err) {
res.serverError(err);
});
},
/**
* Links a new supervisor to the office
*
*/
link_supervisor: function (req, res) {
if (!req.params.id_off || !req.params.id_sup)
return res.badRequest();
if (req.params.id_off == req.params.id_sup)
return res.badRequest("Link to yourself is not allowed");
// Check that both ids are valid
Supervisor.findOne(req.params.id_sup)
.then((sup) => {
if (!sup)
throw new Error("Supervisor not found");
return [sup, Supervisor.findOne(req.params.id_off)];
})
.spread((sup, off) => {
if (!off)
throw new Error("Office not found");
return [sup, off, SupOff.create({supervisor: sup.id, office: off.id})];
})
.spread((sup, off, so) => {
if (!so)
throw new Error("Unable to perform linking");
console.log("SUP.LANG:" + sup.lang);
// An notification is sent to added supervisor
mailService.mailer()
.send({
to: sup.email,
text: sails.__({
phrase: 'office_link',
locale: sup.lang || 'es-es'
}, {name: off.name, email: off.email})
})
.then(() => {res.ok()})
.catch((err) => {throw err});
})
.catch((err) => {
res.badRequest(err.message);
});
},
/**
* Unlinks a supervisor from an office
*
*/
unlink_supervisor: function (req, res) {
if (!req.params.id_off || !req.params.id_sup)
return res.badRequest();
// Check that both ids are valid
Supervisor.findOne(req.params.id_sup)
.then((s) => {
if (!s)
throw new Error("Supervisor not found");
return Supervisor.findOne(req.params.id_off);
})
.then((s) => {
if (!s)
throw new Error("Supervisor not found");
return SupOff.destroy({supervisor: req.params.id_sup, office: req.params.id_off});
})
.then((sos) => {
if (!sos)
throw new Error("No link exists");
res.ok();
})
.catch((err) => {
res.badRequest(err.message);
});
},
/**
* Get the list of students linked to this supervisor.
* The extra supervision attribute indicates the existing relationship between the supervisor and
* the student:
......@@ -585,6 +662,19 @@ module.exports = {
});
},
/*
Returns all the common students associated to both supervisors
*/
commonStudents: function (req, res) {
if (!req.params.id_sup || !req.params.id_off)
return res.badRequest();
Supervisor.commonStudents(req.params.id_sup, req.params.id_off, function (err, stus) {
if (err) throw err;
return res.ok(stus);
});
},
/**
* Get the pictos owned by this supervisor
* @param {request} req {}
......
......@@ -48,6 +48,11 @@ module.exports = {
size: 16,
unique: true
},
type: {
type: "string",
enum: ['trial', 'official'],
columnName: 'type'
},
creator: {
columnName: "creator",
type: "string",
......@@ -64,6 +69,110 @@ module.exports = {
/**
Class methods
*/
hasExpired: function (license) {
return (new Date(license.expiration_ts) - new Date() < 0);
},
/**
* Generates a new trial license
* @param {ID} id_sup ID of the supervisor who creates the license
* @param {function} callback Callback function: (err, license)
*/
newTrial: function(id_sup, callback) {
var now = new Date();
License.genLicenseNumber(function(number) {
if (!number)
callback(new Error("Unable to generate new license"), null);
License.create({
type: 'trial',
creation_ts: now,
duration: sails.config.pictogram.trial_license_duration,
number: number
})
.then((l) => {
if (!l) throw new Error("Unable to create license");
callback(null, l);
})
.catch((err) => {
callback(err, null);
});
});
},
/**
* Generates a random license number (checking that is not duplicated)
* @param {function} callback Prototype: function(license) returns the create number
*/
genLicenseNumber: function(callback) {
function random_license () {
var length = 16;
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var result = '';
for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
return result;
}
var license;
var found = true;
var maxtries = 10;
async.doWhilst(
function (cb) {
license = random_license();
License.findOne({number: license})
.then((l) => {
if (!l)
found = false;
cb();
})
.catch((err) => {
found = false;
cb();
});
},
function () {
return found;
},
function () {
callback(license);
}
);
},
/**
* Get the student associated to the license
* If the license is not active or doesn't exist, and error is returned
* @param {number} number License number
* @param {function} callback Callback function: err, student
*/
getStudent: function(number, callback) {
License.findOne({ number: number })
.then((l) => {
if (!l || !l.activation_ts || !l.student)
throw new Error("Invalid license: " + number);
// License ok, check student
Student.findOne(l.student)
.then((s) => {
if (!s)
throw new Error("Student not found");
// convert model to normal object to be able to add attributes
s = s.toJSON();
s.license = l;
callback(null, s);
})
.catch((err) => {
throw err;
});
})
.catch((err) => {
callback(err, null);
});
},
/**
Activates a license
......@@ -72,6 +181,10 @@ module.exports = {
@param {function} callback Callback function with prototype: function(err, license)
*/
activate: function(number, id_stu, callback) {
if (!number || number.length < 16)
callback(new Error("Invalid license number"));
// Check license
License.findOne({ number: number })
.then((l) => {
......@@ -127,6 +240,7 @@ module.exports = {
* Callback function gets instantiated error if not available
*/
isActivable: function(number, cb) {
License.findOne({number: number})
.then ((l) => {
if (!l)
......
/**
* office.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 = {
connection : 'localMysql',
tableName : 'office',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
name: {
required: true,
type: "string",
size: 80
},
logoUrl: {
columnName: 'logo_url',
type: "string",
size: 240
},
address: {
required: true,
type: "string",
size: 80
},
country: {
type: "string",
size: 5,
required: true
},
lang: {
required: true,
type: "string",
size: 5
},
contactPerson: {
columnName: "contact_person",
required: true,
type: "string",
size: 80
},
email: {
required: true,
type: "string",
size: 80,
unique: true
},
phone1: {
required: true,
type: "string",
size: 20
},
phone2: {
type: "string",
size: 20
},
admin: {
columnName: 'admin',
type: 'integer',
model: 'Supervisor'
},
postalCode: {
columnName: 'postal_code',
required: true,
type: "string",
size: 10
},
// Relación con Teacher. [1 Office to N Teacher]
supervisors: {
collection: "Supervisor",
via: 'office'
},
// Relación con Student. [1 Office to N Student]
students: {
collection: "Student",
via: 'office'
},
toJSON: function() {
var office = this.toObject();
if (!office.logoUrl)
office.logoUrl = '/app/img/logo_pictogram.png';
return office;
}
},
beforeCreate: function (attrs, next) {
if (!attrs.logoUrl)
attrs.logoUrl = '/app/img/logo_pictogram.png';
next();
}
};
......@@ -31,21 +31,17 @@ module.exports = {
size: 40
},
name: {
required: true,
type: 'string',
size: 40
},
surname: {
required: true,
type: 'string',
size: 60
},
birthdate: {
required: true,
type: 'date'
},
gender: {
required: true,
type: 'string',
size: 1
},
......@@ -63,16 +59,9 @@ module.exports = {
},
lang: {
columnName: 'lang',
required: true,
type: 'string',
size: 2
},
office: {
columnName: 'id_off',
type: 'integer',
required: false,
model: 'Office'
},
id_active_scene: {
columnName: 'id_active_scene',
type: 'integer',
......@@ -120,8 +109,12 @@ module.exports = {
toJSON: function () {
var student = this.toObject();
student.pic = sails.config.pictogram.urls.getStudentAvatarUrl(student.pic);
if (student.license)
if (student.license) {
student.license = student.license[0] ? student.license[0] : null;
student.license.isValid = !License.hasExpired(student.license);
student.license.isTrial = student.license.type == 'trial';
student.license.isOfficial = student.license.type == 'official';
}
student.attributes = Student.getValidAttributes(student.attributes);
delete student.password;
return student;
......@@ -296,70 +289,56 @@ module.exports = {
},
//
// Class method for getting the list of supervisors (therapist + tutors) associated to a given
// student
supervisors: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
if (err)
return callback(err, []);
// Class method for getting the list of supervisors associated to a given
// student and where the requester is related office
validSupervisors: function(id_stu, id_sup, callback) {
// Get all supervisors
StuSup.find({id_stu: id_stu})
.populate('supervisor')
.then((stuSups) => {
if (!stuSups || stuSups.length == 0)
return callback(null, []);
throw new Error("No supervisors");
var sups = stuSups.map((st) => {return st.supervisor});
return callback(null, sups);
});
},
// return supervisors and related supervisors to the office
return [stuSups, SupOff.find({office: id_sup}).populate('supervisor')]
})
.spread((stuSups, supOffs) => {
//
// Class method for getting the list of therapists associated to a given
// student
// NOTE: A therapist is a supervisor assigned to an office
therapists: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
async.eachSeries(stuSups,
function(stuSup, next) {
// stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor
if (stuSup.supervisor && stuSup.supervisor.office && stuSup.supervisor.id > 0) {
l.push(stuSup.supervisor);
}
next();
},
function (err) {
return callback(err, l);
}
);
if (!supOffs || supOffs.length == 0)
throw new Error("No supervisors");
// filter null entries and map them to the supervisor object
var ss = _.compact(_.compact(stuSups).map(x => x.supervisor));
var so = _.compact(_.compact(supOffs).map(x => x.supervisor));
// filter from the second list those found in the first list
var sups = so.filter(a => ss.findIndex(b => b.id == a.id) >= 0);
return callback(null, sups);
})
.catch((err) => {
return callback(err, []);
});
},
//
// Class method for getting the list of tutors associated to a given
// Class method for getting the list of all the supervisors associated to a given
// student
// NOTE: A tutor is a supervisor not assigned to any office
tutors: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
async.eachSeries(stuSups,
function(stuSup, next) {
// stuSup.supervisor.id > 0 for not retrieving the -1 default supervisor
if (stuSup.supervisor && !stuSup.supervisor.office && stuSup.supervisor.id > 0) {
l.push(stuSup.supervisor);
}
next();
},
function (err) {
return callback(err, l);
}
);
allSupervisors: function(id_stu, callback) {
// Get all supervisors
StuSup.find({id_stu: id_stu})
.populate('supervisor')
.then((stuSups) => {
if (!stuSups || stuSups.length == 0)
throw new Error("No supervisors");
var ss = _.compact(stuSups).map(x => x.supervisor);
return callback(null, ss);
})
.catch((err) => {
return callback(err, []);
});
},
......@@ -536,7 +515,10 @@ module.exports = {
});
},
// Removes logically a student
/**
* Removes logically a student
* The user name is set with a random prefix and the license is removed
*/
logical_delete: function(id_stu, cb) {
Student.findOne(id_stu).exec(function(err, student) {
if (err || !student)
......@@ -544,7 +526,6 @@ module.exports = {
Student.update(id_stu,
{
username: Math.floor((Math.random() * 100000000) + 1) + "_" + student.username,
id_off: null
})
.then((updated) => {
License.destroy({id_stu: id_stu}).exec(cb);
......
/**
* StuSup.js
*
* @description :: TODO: Write a short summary of how this model works and what it represents here.
* @docs :: http://sailsjs.org/#!documentation/models
*/
/**
* This model relates tutors and therapists with offices
*/
module.exports = {
tableName : 'sup_off',
migrate : 'safe',
schema : true,
autoPK : false,
autoCreatedAt : false,
autoUpdatedAt : false,
attributes: {
id: {
type: "integer",
autoIncrement: true,
primaryKey: true,
unique: true
},
supervisor: { // FK de Supervisor. 1 a N
columnName: "id_sup",
required: true,
type: "integer",
model: "Supervisor"
},
office: { // FK de Supervisor. 1 a N
columnName: "id_off",
type: "integer",
model: "Supervisor"
}
}
}
......@@ -30,17 +30,18 @@ module.exports = {
size: 40
},
name: {
required: true,
type: "string",
size: 40
},
surname: {
required: true,
type: "string",
size: 60
},
role: {
type: "string",
enum: ['tutor', 'therapist', 'office', 'admin']
},
gender: {
required: true,
type: "string",
size: 1
},
......@@ -88,12 +89,6 @@ module.exports = {
type: 'boolean',
columnName: 'arasaac_license'
},
office: {
columnName: 'id_off',
type: 'integer',
required: false,
model: 'Office'
},
// Relación con WorkingSession. [1 Supervisor to N WorkingSession]
workingSessions:{
collection: "WorkingSession",
......@@ -143,7 +138,6 @@ module.exports = {
//
beforeCreate: function (attrs, next) {
var async = require('async');
console.log("-->\n" + JSON.stringify(attrs));
async.series(
[
function (cb) {
......@@ -226,7 +220,6 @@ module.exports = {
var l = [];
Supervisor.findOne(id)
.populate('office')
.then(function (sup) {
if (!sup)
throw new Error("Not a valid supervisor")
......@@ -247,64 +240,76 @@ module.exports = {
})
.spread(function (sup, stuSups) {
async.eachSeries(stuSups, function(stuSup, next_cb) {
// Filter logically deleted students
if (stuSup.student.office == null)
return next_cb();
// set current method and instruction if any
Student.findOne(stuSup.student.id)
.populate('lastInstruction')
.populate('license')
.then(function (s) {
if (!s)
return next_cb();
s = s.toJSON();
s.current_method = s.lastInstruction[0] ? s.lastInstruction[0].met_name : "no_method";
s.current_instruction = s.lastInstruction[0] ? s.lastInstruction[0].ins_name : "no_instruction";
if (typeof(s.license[0]) != 'undefined') {
s.licenseIsValid = new Date(s.license[0].expiration_ts) - new Date() > 0 ? true : false;
s.license = s.license[0];
} else {
s.licenseIsValid = false;
s.license = null;
}
s.supervision = sup.office ? 2 : 1; // if Supervisor has office, then is a therapist (2), a tutor (1) otherwise
if (!s.license)
return next_cb();
l.push(s);
next_cb();
});
},
function (err) { // loop has end
// Get all students from the office if user is administrator
if (sup.office && sup.office.admin == sup.id) {
var officeStudents;
Student.find({ office: sup.office.id })
.populate('lastInstruction')
.populate('license')
.then(function (officeStudents) {
officeStudents = officeStudents.map((student) => {
student.supervision = 0;
student.current_method = student.lastInstruction[0] ? student.lastInstruction[0].met_name : "no_method";
student.current_instruction = student.lastInstruction[0] ? student.lastInstruction[0].ins_name : "no_instruction";
if (typeof(student.license[0]) != 'undefined') {
student.licenseIsValid = new Date(student.license[0].expiration_ts) - new Date() > 0 ? true : false;
student.license = student.license[0];
} else {
student.licenseIsValid = false;
student.license = null;
}
return student;
});
l = l.concat(officeStudents);
callback(err, lodash.uniq(l, false, 'id'));
})
.catch(function (err) {
callback(err, l);
});
} else {
callback(err, l);
}
}); // end async.eachSeries
function (err) {
callback(err, l);
});
})
.catch((err) => {
callback(err, l);
}); // end Supervisor.findOne
},
/***
* Return the list of students that are common to both supervisors
*/
commonStudents: function(id1, id2, callback) {
var l = [];
StuSup.find({ supervisor: id1 })
.then(function (stuSups) {
return [stuSups, StuSup.find({ supervisor: id2 })];
})
.spread((stuSups1, stuSups2) => {
if (!stuSups1 || !stuSups2)
throw new Error("No students");
// Common students
var stuSups = stuSups1.filter(a => stuSups2.findIndex(b => b.student == a.student) >= 0);
// Now, let's take full information about them
async.eachSeries(stuSups, function(stuSup, next_cb) {
// set current method and instruction if any
Student.findOne(stuSup.student)
.populate('lastInstruction')
.populate('license')
.then(function (s) {
if (!s)
return next_cb();
s = s.toJSON();
s.current_method = s.lastInstruction[0] ? s.lastInstruction[0].met_name : "no_method";
s.current_instruction = s.lastInstruction[0] ? s.lastInstruction[0].ins_name : "no_instruction";
if (!s.license)
return next_cb();
l.push(s);
next_cb();
});
},
function (err) {
return callback(err, l);
});
})
.catch((err) => {
return callback(err, l);
});
}
};
module.exports = function isAdmin (req, res, next) {
//
// Only if the user that has connected is global administrator (Yotta employee)
// Only if the user that has connected is global administrator (Yotta employee)
//
if (!req.token || !req.token.isAdmin)
if (!req.token || req.token.role !== 'admin')
res.json(401, {error: 'Access denied'});
// Finally, if the user has a clean record, we'll call the `next()` function
// to let them through to the next policy or our controller
next();
};
\ No newline at end of file
};
module.exports = function isAdmin (req, res, next) {
module.exports = function isAdminOrOffice (req, res, next) {
//
// Only if the user that has connected is global administrator (Yotta employee)
// Only if the user that has connected is global administrator (Yotta employee) or is an office
//
if (!req.token || !req.token.isAdmin && !req.token.isSupAdmin)
if (!req.token || req.token.role !== 'admin' && req.token.role !== 'office')
res.json(401, {error: 'Access denied'});
// Finally, if the user has a clean record, we'll call the `next()` function
......
......@@ -3,10 +3,10 @@ module.exports = function isSupAdmin (req, res, next) {
//
// A SupAdmin is a supervisor that is administrator of an office
// That means that we can find its id at the admin column in an entry at the office table
if (!req.token || !req.token.isSupAdmin)
if (!req.token || req.token.role !== 'office')
res.json(401, {error: 'Access denied'});
// Finally, if the user has a clean record, we'll call the `next()` function
// to let them through to the next policy or our controller
next();
};
\ No newline at end of file
};
module.exports = function isSupervisorOfStudentOrIsStudent (req, res, next) {
module.exports = function isStudentOrSupervisorOfStudent (req, res, next) {
// sails.log("TOKEN: " + JSON.stringify(req.token));
if (!req.params.id_stu)
return res.json(401, {error: 'Access denied 1'}); // If it is a student, then is ok
if (req.token && req.token.isStudent && req.token.id == req.params.id_stu)
return next();
// Get list of supervisors for the student
Student.supervisors(req.params.id_stu, function(err, sups) {
Student.allSupervisors(req.params.id_stu, function(err, sups) {
if (err)
return res.json(401, {error: err});
if (!sups || sups.length == 0)
return res.json(401, {error: "This student has no supervisors associated"});
// if supervisor is not in the list of supervisors
if (sups.map(function(e) {return e.id}).indexOf(req.token.id) < 0)
// if supervisor is not in the list of supervisors
if (_.compact(sups).map(function(e) {return e.id}).indexOf(req.token.id) < 0)
return res.json(401, {error: 'Access denied 3'});
// Finally, if the user has a clean record, we'll call the `next()` function
// to let them through to the next policy or our controller
next();
});
};
/* global sails, Student */
module.exports = function isSupervisorOfStudent(req, res, next) {
const supervisorId = req.token.id;
const studentId = req.params.id_stu;
if (!studentId || !supervisorId) {
sails.log.error('This request needs an id_stu parameter and a authenticated supervisor');
res.json(401, { error: 'Access denied' });
} else {
Student.supervisors(studentId, function (err, sups) {
const studentSupervisorsIds = sups.map((studentSupervisor) => studentSupervisor.id);
if (err || studentSupervisorsIds.length === 0) {
sails.log.error(`Student ${studentId} has no supervisor assigned`);
res.json(401, { error: 'Access denied' });
} else if (studentSupervisorsIds.indexOf(supervisorId) < 0) {
sails.log.error(`Supervisor ${supervisorId} is not assigned to Student ${studentId}`);
sails.log.debug(`Student supervisors: ${studentSupervisorsIds}`);
res.json(401, { error: 'Access denied' });
} else {
sails.log.debug(`Supervisor ${supervisorId} is assigned to Student ${studentId}`);
next();
}
});
}
if (!req.params.id_stu || !req.token.id)
return res.json(401, {error: 'Access denied'});
// Get list of supervisors for the student
Student.allSupervisors(req.params.id_stu, function(err, sups) {
if (err)
return res.json(401, {error: err});
if (!sups || sups.length == 0)
return res.json(401, {error: "This student has no supervisors associated"});
// if supervisor is not in the list of supervisors
if (_.compact(sups).map(function(e) {return e.id}).indexOf(req.token.id) < 0)
return res.json(401, {error: 'Access denied 3'});
// Finally, if the user has a clean record, we'll call the `next()` function
// to let them through to the next policy or our controller
next();
});
};
/* global sails, Student */
module.exports = function isSupervisorOfStudentOrIsSupAdmin(req, res, next) {
const supervisorId = req.token.id;
const studentId = req.params.id_stu;
if (!studentId || !supervisorId) {
sails.log.error('This request needs an id_stu parameter and a authenticated supervisor');
return res.json(401, { error: 'Access denied' });
} else {
Student.findOne(studentId)
.then(function (s) {
if (req.token.office && s.office == req.token.office.id && req.token.isSupAdmin)
next();
else {
Student.supervisors(studentId, function (err, sups) {
if (err)
return res.json(401, {error: 'Access denied'});
var supIds = sups.map((studentSupervisor) => studentSupervisor.id);
if (supIds.indexOf(supervisorId) >= 0)
return next();
sails.log.error(`Supervisor ${supervisorId} is not assigned to Student ${studentId}`);
return res.json(401, { error: 'Access denied' });
});
}
})
.catch((err) => {
sails.log.error(JSON.stringify(err));
return res.json(401, { error: "No student found" })
});
}
};
module.exports = function isSupervisorOfStudentOrIsSupAdminOrIsStudent (req, res, next) {
// sails.log("TOKEN: " + JSON.stringify(req.token));
if (!req.params.id_stu)
return res.json(401, {error: 'Access denied 1'});
Student.findOne(req.params.id_stu)
.then(function (s) {
if (req.token && req.token.isStudent && req.token.id == req.params.id_stu)
return next(); // Is Student
if (req.token.office && s.office == req.token.office.id && req.token.isSupAdmin)
return next(); // Is Office's administrator
Student.supervisors(req.params.id_stu, function(err, sups) {
if (err || !sups || sups.length == 0)
return res.json(401, {error: "This student has no supervisors associated"});
if (sups.map(function(e) {return e.id}).indexOf(req.token.id) >= 0)
return next(); // Is Supervisor of Student
return res.json(401, {error: "No valid credentials"});
});
})
.catch((err) => {
return res.json(401, {error: "Student not found"});
});
};
......@@ -27,7 +27,7 @@ module.exports = function badRequest(data, options) {
// Log error to console
if (data !== undefined) {
sails.log.verbose('Sending 400 ("Bad Request") response: \n',data);
sails.log.verbose('Sending 400 ("Bad Request") response: \n', data);
}
else sails.log.verbose('Sending 400 ("Bad Request") response');
......
......@@ -22,7 +22,7 @@
"humanize-duration": "~3.0.0",
"momentjs": "~2.10.3",
"ngtoast": "~1.5.4",
"angular-animate": "~1.4.1",
"angular-animate": "~1.2.2",
"angular-sanitize": "~1.4.1",
"angular-chart.js": "latest",
"ng-lodash": "~0.3.0",
......@@ -34,7 +34,6 @@
},
"resolutions": {
"angular": ">=1 <1.3.0",
"humanize-duration": "~3.0.0",
"momentjs": "~2.10.3"
"humanize-duration": "~3.0.0"
}
}
{
"account": "Account",
"account_activate": "The account has been activated",
"account_available": "Account available",
"account_desc_office": "Manage students, intervention teams along with all therapist related functionalities.",
"account_desc_therapist": "Manage pictograms, devices, record supervised sessions and get progress reports.",
"account_desc_tutor": "Configure your child's pictograms and his/her communication device.",
"account_no_activate": "The account could not be activated",
"action-add": "Add picto",
"action-delete": "Delete picto",
......@@ -13,8 +17,12 @@
"action-unshow": "Writing mode",
"activation": "Activation",
"add": "Add",
"add_existing": "Add existing account",
"add_existing_desc": "Link your profile to an already registered student's account to start working with him/her. You'll be asked for the current active license of the student.",
"add_expression": "Add expression",
"add_instruction": "Add instruction",
"add_new_official": "New official account",
"add_new_official_desc": "Create a new student account with a new official license.",
"add_office": "Add office",
"add_picto": "Add pictogram",
"add_pictos": "Add pictograms",
......@@ -41,7 +49,9 @@
"August": "August",
"average_time_between_pictos": "Average time between pictograms",
"average_time_per_try": "Average time per try",
"back": "Back",
"background": "Background",
"back_to_login": "Back to login",
"beep": "Beep",
"birthdate": "Birthdate",
"black_and_white": "B&W",
......@@ -114,6 +124,7 @@
"edit": "Edit",
"email": "Email address",
"email_confirm": "E-mail address confirmation",
"email_invalid": "Invalid email",
"email_match": "The emails must match",
"email_type": "E-mail address",
"enable_sound_for": "Enable sound for",
......@@ -178,6 +189,7 @@
"keep_strip_and_deliveries": "Keep strip and allow several deliveries",
"keep_strip_and_one_delivery": "Keep strip and allow only one delivery",
"language": "Language",
"language_change_warning": "Your preferred language has been changed. Session restarting is recommended.",
"large": "Large",
"large_picto": "Large pictograms",
"last_session": "Last session",
......@@ -191,11 +203,15 @@
"licenses": "Licenses",
"license_already_activated": "License already activated",
"license_created": "License created",
"license_expires": "PRO license expires on ",
"license_expired": "PRO license expired, you can",
"license_expired_official": "PRO license expired. To maintain access to therapeutical functionalities you can",
"license_expired_trial": "Trial license expired. To keep the account you should",
"license_expired_buy": "buy one license",
"license_expired_renew": "renew it",
"license_expires_official": "PRO license expires on ",
"license_expires_trial": "Trial license expires on ",
"license_invalid": "Invalid license number",
"license_missing": "Account without PRO license",
"license_missing_official": "This PRO license expired. You have no access to therapeutical functionalities, but you can still manage pictograms and devices.",
"license_missing_trial": "Trial license expired. Buy an official one to keep using this account (go to Settings).",
"license_number": "License number",
"license_pro": "Pictogram PRO license",
"license_warning": "Only available for professional licenses (Pictogram Pro).",
......@@ -203,6 +219,8 @@
"licenses_left": "{{number}} licenses left",
"light_up": "Light up",
"link": "Link",
"link_supervisor": "Link supervisor",
"link_supervisor_desc": "When linking a therapist/parent/tutor, he/she will be notified of this action.",
"loading_pictos": "Loading pictos",
"login": "Log In",
"login_fail": "Invalid user or password",
......@@ -235,17 +253,23 @@
"new_scene_with_categories": "Create scene with categories",
"new_scene_without_categories": "Create scene without categories",
"new_session": "New session",
"new_test_account": "New test account",
"new_test_account_desc": "Create a test account to try Pictogram for free. You will be able to keep the account beyond the three months trial by activating an official license on the account.",
"next": "Next",
"next_actions": "Next actions",
"next_sessions": "Next sessions",
"no": "No",
"no_categories": "Without categories",
"nobegin": "No started",
"no_instruction": "No instruction defined",
"no_method": "No method defined",
"no_office": "No office",
"no_subscribed": "No connection to student account",
"no_instruction": "No instruction defined",
"no_students_for_user": "You are not associated to any students. Please ask your office to link your account to a Pictogram student.",
"no_space_in_category": "No space left in category",
"no_supervisors": "No supervisors linked. ",
"no_supervisors_desc": "Enter supervisor's email in the input field above to add one.",
"no_supervisor_linked": "Unable to link supervisor",
"normal": "Normal",
"note": "Note",
"notes": "Notes",
......@@ -258,9 +282,11 @@
"objetive": "Objetive",
"October": "October",
"office": "Office",
"office_account_desc": "Manage students and intervention teams, along with all therapist related functionalities.",
"office_added": "Office added",
"office_center": "Office or center",
"office_deleted": "Office deleted",
"office_name": "Office's name",
"office_not_added": "Office not added",
"office_not_deleted": "Office not deleted",
"office_not_updated": "Office not updated",
......@@ -273,6 +299,7 @@
"own_pictos": "Your pictograms",
"tos": "Your pictograms",
"pages": "Pages",
"parents_tutor": "Parent or tutor",
"password": "Password",
"password_changed": "Password changed sucessfully",
"password_confirm": "Repeat password",
......@@ -336,6 +363,7 @@
"search_sup_email": "Search supervisor by email",
"search_tutor_email": "Search tutor by email",
"seconds": "seconds",
"select_account": "Select account type",
"select_instruction": "-- Select an instruction --",
"select_a_method": "-- Select a method --",
"select_method": "-- Select a method or create it --",
......@@ -376,8 +404,10 @@
"state_spontaneous": "Spontaneous",
"state_supervised": "Supervised",
"stop": "Stop",
"student_account_confirm": "The new account is now available from the students list.",
"student_added": "Student added",
"student_already_exists": "A student with that username already exists, please try with another one",
"student_already_linked": "The student is already linked to your account",
"student_deleted": "Student deleted",
"student_not_added": "Student not added",
"student_not_deleted": "Student not deleted",
......@@ -389,19 +419,25 @@
"sup_not_added": "Supervisor not added to the student",
"sup_not_deleted": "The supervisor couldn't be deleted by the student",
"sup_not_found": "There is no supervisor account in Pictogram with this email",
"sup_not_in_office": "There is no supervisor account related to your office/center with this email.",
"supervisor_added": "Supervisor added",
"supervisor_added_notified": "Supervisor added. A notification email has been sent to his/her email address.",
"supervisor_already_linked": "The supervisor is already linked to your account",
"supervisor_deleted": "Supervisor deleted",
"supervisor_not_added": "Supervisor not added",
"supervisor_not_deleted": "Supervisor not deleted",
"supervisor_not_updated": "Supervisor not updated",
"supervisor_note": "If the parent aren't going to register in the platform, the administrator can use the notes field to store their information.",
"supervisor_updated": "Supervisor updated",
"supervisor_yourself": "This is you. No reason to link to yourself.",
"supervisors": "Supervisors",
"support": "User support",
"surname": "Surname",
"tag_deleted": "Tag deleted",
"tape_background": "Tape background",
"template_deleted": "Template deleted",
"therapist": "Therapist",
"therapist_account_desc": "Manage pictograms, devices, record therapy sessions and get evolution reports.",
"therapists": "Therapists",
"time_hours": "Time: {{hours}} hours",
"time_instruction_method": "Time instructions of method",
......@@ -417,6 +453,7 @@
"tpl_date_frame": "de {{ begin | date:'dd-MM-yyyy' }} a {{ end | date:'dd-MM-yyyy' }}",
"tpl_day": "{{ day | date:'yyyy-MM-dd' }}",
"tpl_hours_frame": "from {{ begin | date:'HH:mm:ss' }} to {{ end | date:'HH:mm:ss' }}",
"trial_license": "Trial license",
"tries": "Tries",
"tries_done": "Tries done",
"tries_length": "Tries length",
......@@ -425,7 +462,9 @@
"tries_per_instruction_method": "Tries per instruction of method",
"tries_per_months": "Tries per months in",
"tries_results_instruction": "Tries results in instruction",
"tutor": "Parent/tutor",
"tutor_added": "Tutor added to the student",
"tutor_account_desc": "Manage child's pictograms and configure his/her communication device.",
"tutor_deleted": "Tutor removed from the student",
"tutor_not_added": "Tutor not added to the student.",
"tutor_not_deleted": "Tutor couldn't be removed from the student",
......@@ -439,9 +478,11 @@
"update_supervisor": "Update supervisor",
"upload_image": "Upload image",
"use_categories": "Use categories",
"username": "Name of account (no spaces)",
"username": "Account identifier",
"username_default": "Account identifier (don't use spaces)",
"username_exists": "There is already an account with name '{{username}}'",
"user_created": "User {{name}} {{surname}} created. An email with instructions to activate the account has been sent.",
"user_created": "Account created!",
"user_created_text": "An email with instructions to activate the account has been sent to {{email}}.",
"user_exists": "User with email {{email}} already exists",
"validate_fail": "The user account couldn't be validated",
"validate_success": "The user account has been validated. Now, you can login from the link below",
......
{
"account": "Cuenta",
"account_activate": "La cuenta ha sido activada",
"account_available": "Cuenta disponible",
"account_desc_office": "Gestione alumnos y equipos de intervención, además de todas las funcionalidades propias de un terapeuta.",
"account_desc_tutor": "Gestione los pictogramas de su hijo o hija y configure su dispositivo de comunicación.",
"account_desc_therapist": "Gestione pictogramas, dispositivos, grabe sesiones de terapia y obtenga estadísticas de progreso.",
"account_no_activate": "La cuenta no se ha podido activar",
"action-add": "Añade picto",
"action-delete": "Elimina picto",
......@@ -13,8 +17,12 @@
"action-unshow": "Modo escritura",
"activation": "Activación",
"add": "Añadir",
"add_existing": "Asociar cuenta existente",
"add_existing_desc": "Asocie a su perfil la cuenta de un/a alumno/a ya registrado/a para poder gestionarla. Necesitará el número de licencia en uso del estudiante.",
"add_expression": "Añadir expresión",
"add_instruction": "Añadir instrucción",
"add_new_official": "Nueva cuenta oficial",
"add_new_official_desc": "Alta de una nueva cuenta de alumno/a con licencia oficial.",
"add_office": "Añadir gabinete",
"add_picto": "Añadir pictograma",
"add_pictos": "Añadir pictogramas",
......@@ -41,7 +49,9 @@
"August": "Agosto",
"average_time_between_pictos": "Tiempo medio entre pictogramas",
"average_time_per_try": "Tiempo medio por intento",
"back": "Volver",
"background": "Fondo",
"back_to_login": "Volver a inicio de sesión",
"beep": "Pitido",
"birthdate": "Fecha de nacimiento",
"black_and_white": "ByN",
......@@ -69,8 +79,7 @@
"close_session": "Cerrar sesion",
"collections": "Colecciones",
"confirmation": "¿Estás seguro?",
"confirm_unlink_therapist": "¿Desligar {{ name }} de {{ student }} como terapeuta?",
"confirm_unlink_tutor": "¿Desligar {{ name }} de {{ student }} como tutor?",
"confirm_unlink_student": "¿Desligar {{ name }} de {{ student }}?",
"contact_person": "Persona de contacto",
"contact_person": "Persona de contacto",
"continue_session": "Reanudar sesión",
......@@ -114,6 +123,7 @@
"edit": "Editar",
"email": "Correo electrónico",
"email_confirm": "Repite tu email",
"email_invalid": "El email no es válido",
"email_match": "Los emails deben coincidir",
"email_type": "Introduce tu email",
"enable_sound_for": "Habilitar sonido para",
......@@ -178,6 +188,7 @@
"keep_strip_and_deliveries": "Mantener cinta y permitir varias entregas",
"keep_strip_and_one_delivery": "Mantener cinta y permitir sólo una entrega",
"language": "Idioma",
"language_change_warning": "Ha cambiado el idioma. Se recomienda reiniciar sesión.",
"large": "Grande",
"large_picto": "Pictogramas grandes",
"last_session": "Última sesión",
......@@ -191,18 +202,24 @@
"licenses": "Licencias",
"licenses_left": "{{number}} licencias disponibles",
"license_already_activated": "Licencia ya activada previamente",
"license_expires": "La licencia PRO expira el ",
"license_expired": "La licencia PRO expiró, puede",
"license_expired_renew": "renovarla",
"license_created": "Licencia creada",
"license_expired_official": "La licencia PRO expiró. Para mantener acceso a funcionalidades terapéuticas puede",
"license_expired_trial": "La licencia de prueba expiró. Para mantener la cuenta debería",
"license_expired_buy": "adquirir una licencia",
"license_expired_renew": "renovarla",
"license_expires_official": "La licencia PRO finaliza el ",
"license_expires_trial": "La licencia de prueba finaliza el ",
"license_invalid": "Licencia inválida",
"license_number": "Número de licencia",
"license_pro": "Licencia Pictogram PRO",
"license_warning": "Sólo disponible para licencias profesionales (Pictogram Pro).",
"license_missing": "Cuenta sin licencia PRO",
"license_missing_official": "La licencia PRO expiró. El acceso a las funcionalidades terapéuticas queda restringido, aunque puede seguir gestionando pictogramas y dispositivos.",
"license_missing_trial": "La licencia de prueba expiró. Adquiera una licencia oficial para mantener esta cuenta (puede hacerlo en Configuración).",
"licenses_created": "Licencias creadas",
"light_up": "Iluminar",
"link": "Vincular",
"link_supervisor": "Vincular supervisor",
"link_supervisor_desc": "Al vincular un terapeuta/padre/madre/tutor se enviará un correo de notificación al mismo.",
"loading_pictos": "Cargando pictos",
"login": "Iniciar sesión",
"login_fail": "Usuario o contraseña incorrectos",
......@@ -235,6 +252,9 @@
"new_scene_with_categories": "Crear escena con categorías",
"new_scene_without_categories": "Crear escena sin categorías",
"new_session": "Nueva sesión",
"new_test_account": "Crear cuenta de prueba",
"new_test_account_desc": "Cree una cuenta temporal para probar gratuitamente Pictogram. Podrá activar una licencia en esta cuenta para mantenerla más allá de los tres meses de prueba.",
"next": "Siguiente",
"next_actions": "Acciones posteriores",
"next_sessions": "Sesiones posteriores",
"no": "No",
......@@ -242,9 +262,13 @@
"no_method": "Método sin definir",
"no_office": "Sin centro",
"no_instruction": "Instrucción sin definir",
"no_students_for_user": "Su cuenta no está asociada a ningún estudiante. Por favor, contacte con su gabinete para enlazar su cuenta a un estudiante.",
"no_students": "Su cuenta no está asociada a ningún estudiante",
"no_students_desc": "Pulse en 'Añadir estudiante' para vincularse a cuentas de alumnos existentes o dar de alta nuevas",
"no_space_in_category": "No queda espacio en la categoría",
"no_subscribed": "Sin conexión a la cuenta del estudiante",
"no_supervisors": "No tiene tutores, padres o terapeutas asociados.",
"no_supervisors_desc": "Introduzca el correo electrónico del supervisor en el campo de arriba para añadirlo.",
"no_supervisor_linked": "No se pudo asociar al supervisor",
"nobegin": "Sin iniciar",
"normal": "Normal",
"note": "Nota",
......@@ -257,10 +281,12 @@
"num_sessions_per_month_in": "Número de sesiones por meses en",
"objetive": "Objetivo",
"October": "Octubre",
"office": "Gabinete",
"office": "Gabinete/centro",
"office_account_desc": "Gestione alumnos y equipos de intervención, además de todas las funcionalidades propias de un terapeuta.",
"office_center": "Gabinete/centro",
"office_added": "Gabinete añadido",
"office_deleted": "Gabinete eliminado",
"office_name": "Nombre del centro/gabinete",
"office_not_added": "No se ha podido añadir el gabinete",
"office_not_deleted": "No se ha podido eliminar el gabinete",
"office_not_updated": "El gabinete no se ha podido actualizar",
......@@ -272,6 +298,7 @@
"own_labels": "Etiquetas propias",
"own_pictos": "Pictogramas propios",
"pages": "Páginas",
"parents_tutor": "Padre, madre o tutor",
"password": "Contraseña",
"password_changed": "La clave ha sido modificada exitosamente.",
"password_confirm": "Repita la contraseña",
......@@ -337,6 +364,7 @@
"search_tutor_email": "Buscar tutor por email",
"seconds": "segundos",
"select_instruction": "-- Selecciona una instrucción --",
"select_account": "Seleccione tipo de cuenta",
"select_a_method": "-- Selecciona un método --",
"select_method": "-- Selecciona un método o créalo --",
"select_office": "Seleccione una oficina/centro de la lista",
......@@ -376,8 +404,10 @@
"state_spontaneous": "Espontáneo",
"state_supervised": "Guiado",
"stop": "Parar",
"student_account_confirm": "La nueva cuenta ahora está disponible en su lista de alumnos.",
"student_added": "Estudiante añadido",
"student_already_exists": "Ya existe un estudiante con ese nombre de usuario. Por favor, inténtelo de nuevo con algo diferente.",
"student_already_linked": "El estudiante ya está vinculado a su cuenta",
"student_deleted": "Estudiante eliminado",
"student_not_added": "Estudiante no añadido",
"student_not_deleted": "No se ha podido eliminar el estudiante",
......@@ -389,20 +419,26 @@
"sup_not_added": "El supervisor no se ha podido añadir al estudiante.",
"sup_not_deleted": "El supervisor no se ha podido desvincular del alumno.",
"sup_not_found": "No hay ningún usuario en Pictogram con ese correo electrónico.",
"sup_not_in_office": "No hay ningún usuario asociado a su centro/gabinete con ese correo electrónico.",
"supervisor_added": "Supervisor añadido",
"supervisor_added_notified": "Supervisor añadido. Se le ha enviado al mismo una notificación por correo electrónico.",
"supervisor_already_linked": "El supervisor ya está vinculado",
"supervisor_deleted": "Supervisor eliminado",
"supervisor_not_added": "Supervisor no añadido",
"supervisor_not_deleted": "No se ha podido eliminar el supervisor",
"supervisor_not_updated": "El supervisor no se ha podido actualizar",
"supervisor_note": "Si los padres no se van a dar de alta en la plataforma nunca, el administrador puede anotar la información de contacto en el campo notas.",
"supervisor_updated": "Supervisor actualizado",
"supervisor_yourself": "Este es usted. No hay razón para añadir a uno mismo.",
"support": "Atención al cliente",
"therapists": "Terapeutas",
"supervisors": "Supervisores",
"surname": "Apellidos",
"tag_deleted": "Etiqueta borrada",
"tape_background": "Fondo de la cinta",
"template_deleted": "Plantilla eliminada",
"therapists": "Terapeutas",
"therapist": "Terapeuta",
"therapist_account_desc": "Gestione pictogramas, dispositivos, grabe sesiones de terapia y obtenga estadísticas de evolución.",
"time_hours": "Tiempo: {{hours}} horas",
"time_instruction_method": "Tiempo instrucciones del método",
"time_sessions_total": "Tiempo total de sesiones",
......@@ -417,6 +453,7 @@
"tpl_date_frame": "de {{ begin | date:'dd-MM-yyyy' }} a {{ end | date:'dd-MM-yyyy' }}",
"tpl_day": "{{ day | date:'dd-MM-yyyy' }}",
"tpl_hours_frame": "de {{ begin | date:'HH:mm:ss' }} a {{ end | date:'HH:mm:ss' }}",
"trial_license": "Licencia de prueba",
"tries": "Ensayos",
"tries_done": "Ensayos realizados",
"tries_length": "Duración ensayos",
......@@ -425,6 +462,8 @@
"tries_per_instruction_method": "Ensayos por instrucción del método",
"tries_per_months": "Número de ensayos por meses en",
"tries_results_instruction": "Resultados ensayos en instrucción",
"tutor": "Padre/madre/tutor",
"tutor_account_desc": "Gestione los pictogramas de su hijo o hija y configure su dispositivo de comunicación.",
"tutor_added": "Tutor añadido al estudiante",
"tutor_deleted": "Tutor desvinculado del estudiante",
"tutor_not_added": "El tutor no se ha podido añadir al estudiante",
......@@ -439,9 +478,11 @@
"update_supervisor": "Editar supervisor",
"upload_image": "Subir imagen",
"use_categories": "Usar categorías",
"username": "Nombre cuenta (sin espacios)",
"username": "Identificador de cuenta",
"username_default": "Identificador cuenta (no use espacios)",
"username_exists": "Ya existe un usuario con nombre de cuenta '{{username}}'",
"user_created": "Usuario {{name}} {{surname}} creado. Se ha enviado un email de confirmación para activar su cuenta.",
"user_created": "¡Cuenta creada!",
"user_created_text": "Se ha enviado un email de confirmación para activar su cuenta a la dirección {{email}}.",
"user_exists": "Ya existe el usuario con email '{{email}}'",
"validate_fail": "La cuenta no se ha podido validar",
"validate_success": "Cuenta validada. Puede iniciar sesión desde el enlace inferior",
......
......@@ -32,8 +32,9 @@ dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $
id: '',
name: '',
surname: '',
email: '',
role: '',
pic: '',
office: '',
lang: ''
};
......@@ -74,7 +75,7 @@ dashboardControllers.controller('MainCtrl', function MainCtrl($scope, $window, $
// Returns the full name of the user
$scope.user.getFullName = function(){
return $scope.user.name + " " + $scope.user.surname;
return $scope.user.name + ($scope.user.isOffice ? "" : " " + $scope.user.surname);
};
// Logout
......
......@@ -8,6 +8,7 @@
dashboardControllers.controller('LoginCtrl',
function LoginCtrl(
$scope,
$rootScope,
$http,
$window,
$translate,
......@@ -15,82 +16,160 @@ function LoginCtrl(
$location,
config,
$stateParams,
ngToast) {
$timeout,
ngToast,
CONSTANTS,
vcRecaptchaService) {
/* Slider object */
$scope.slide = {
state: 'login',
prev: 'login',
back: false,
rightTo: function (state) {
$scope.slide.back = false;
$scope.slide.prev = $scope.slide.state;
$timeout(function () {
$scope.slide.state = state;
}, 0);
},
leftTo: function (state) {
$scope.slide.back = true;
$scope.slide.prev = $scope.slide.state;
$timeout(function () {
$scope.slide.state = state;
}, 0);
}
};
/*
LOGIN --------------------------
*/
/* Login credentials */
$scope.credentials = {
email: '',
password: '',
lang: 'es-es'
};
$scope.office = {
logoUrl : 'img/logo_pictogram.png',
name : 'Pictogram'
};
// Corporate login, office code has been passed
if ($stateParams.office) {
$http
.get(config.backend + '/office/' + $stateParams.office)
.success(function (data) {
$scope.office = data;
});
}
/* Login function */
$scope.login = function () {
$scope.submitted = true;
$http
.post(config.backend + '/sup/login', $scope.credentials)
.success(function (data) {
// default logo to Pictogram logo
if (!data.user.office) {
data.user.office = $scope.office;
data.user.isTutor = true;
} else
data.user.isTutor = false;
if (data.user.office.logoUrl.length < 5)
data.user.office.logoUrl = 'img/logo_pictogram.png';
$window.sessionStorage.token = data.token;
//User data correct
if (data.user) {
// Adapt language en-us to en-gb (the latter is the one supported for 'en')
if (data.user.lang === 'en-us') {
if (data.user.lang === 'en-us')
data.user.lang = 'en-gb';
}
//Update $scope
data.user.isTutor = data.user.role == 'tutor';
data.user.isTherapist = data.user.role == 'therapist';
data.user.isOffice = data.user.role == 'office';
data.user.isAdmin = data.user.role == 'admin';
$scope.lang = data.user.lang;
//Update $translate
$translate.use($scope.lang);
} else {
//No user data, use default lang
$translate.use($scope.lang);
$location.path('/sup/login');
}
// Change
$window.sessionStorage.user = JSON.stringify(data.user);
$translate('login_success').then(function (translation) {
ngToast.success({ content: translation });
});
// Name in login success message
$scope.name = data.user.name;
// Redirección
$location.path('/students');
})
.error(function (err) {
$scope.submitted = false;
delete $window.sessionStorage.token;
if (err.search("without students") > 0) {
ngToast.warning($translate.instant('no_students_for_user'));
} else if (err.search("not been activated") > 0) {
ngToast.danger($translate.instant('inactive_account'));
} else {
ngToast.danger($translate.instant("login_fail"));
}
if (err.search("not been activated") > 0)
ngToast.danger($translate.instant('inactive_account'));
else
ngToast.danger($translate.instant("login_fail"));
});
};
/*
SIGNUP ------------------------------
*/
/* form data */
var formdata_empty = {
name: '',
email: '',
password: '',
password_confirm: '',
lang: '',
role: '',
};
$scope.minlength = CONSTANTS.password_minlength;
/* Forms objects */
$scope.forms = {};
$scope.reset = function () {
$scope.formdata = formdata_empty;
};
$scope.reset();
// Signup form submit
$scope.signup = function (formName) {
var form;
// select form according to account
if (formName == 'tutorForm')
form = $scope.forms.tutorForm;
else if (formName == 'therapistForm')
form = $scope.forms.therapistForm;
else
form = $scope.forms.officeForm;
// set language according to interface settings
$scope.formdata.lang = $translate.use();
//
// check validity of fields
//
if (typeof $scope.formdata.email == 'undefined' || form.email.$invalid) {
ngToast.danger($translate.instant('email_invalid'));
return;
}
if ($scope.formdata.password.length < CONSTANTS.password_minlength) {
ngToast.danger($translate.instant('password_short', {minlength: CONSTANTS.password_minlength}));
return;
}
if ($scope.formdata.password !== $scope.formdata.password_confirm) {
ngToast.danger($translate.instant('password_match'));
return;
}
if (!$scope.formdata.disclaimer_accepted) {
ngToast.danger($translate.instant('disclaimer_requested'));
return;
}
if (form.$invalid)
return;
$http
.post(config.backend + '/sup', $scope.formdata)
.success(function () {
$scope.slide.rightTo('confirmation');
})
.error(function () {
ngToast.danger({ content: $translate.instant('user_exists', {email: $scope.formdata.email}) });
});
};
});
/* global dashboardControllers */
'use strict';
//-------------------
// SignIn Controller
//-------------------
dashboardControllers.controller('SignInCtrl',
function SignInCtrl($scope,
$http,
$window,
$translate,
$rootScope,
config,
CONSTANTS,
ngToast,
vcRecaptchaService)
{
$scope.reset = function () {
$scope.formdata = {
name: '',
surname: '',
address: '',
postalCode: '',
country: '00',
phone: '',
gender: 'F',
email: '',
email_confirm: '',
password: '',
password_confirm: '',
lang: '00',
role: 'therapist_office',
office: {
name: '',
address: '',
postalCode: '',
country: '00',
contactPerson: '',
phone1: '',
email: '',
logoUrl: ''
},
id_off: -1
};
};
$scope.reset();
// Get the list of offices
$http
.get(config.backend + '/office/get_all')
.success(function (offices) {
$scope.offices = offices;
})
.error(function () {
ngToast.danger({ content: $translate.instant('server_error') });
});
// Copy fields from supervisor to office
$scope.copyFields = function () {
$scope.formdata.office.address = $scope.formdata.address;
$scope.formdata.office.postalCode = $scope.formdata.postalCode;
$scope.formdata.office.country = $scope.formdata.country;
$scope.formdata.office.lang = $scope.formdata.lang;
$scope.formdata.office.email = $scope.formdata.email;
$scope.formdata.office.phone1 = $scope.formdata.phone;
$scope.formdata.office.contactPerson = $scope.formdata.name + " " + $scope.formdata.surname;
};
// Form submit
$scope.signin = function () {
// Validate email match
if ($scope.formdata.email !== $scope.formdata.email_confirm) {
ngToast.danger({ content: $translate.instant('email_match') });
return;
}
// Validate password match
if ($scope.formdata.password !== $scope.formdata.password_confirm) {
ngToast.danger({ content: $translate.instant('password_match') });
return;
}
if ($scope.formdata.password.length < CONSTANTS.password_minlength) {
ngToast.danger({ content: $translate.instant('password_short', {minlength: CONSTANTS.password_minlength}) });
return;
}
if ($scope.formdata.country == '00') {
ngToast.danger({ content: $translate.instant('country_requested') });
return;
}
if (($scope.formdata.role == 'therapist_office' || $scope.formdata.role == 'tutor_office') && $scope.formdata.id_off == -1) {
ngToast.danger({ content: $translate.instant('select_office') });
return;
}
if ($scope.formdata.role == 'therapist_nooffice' && $scope.formdata.office.country == '00') {
ngToast.danger({ content: $translate.instant('country_office_requested') });
return;
}
if (!$scope.formdata.disclaimer_accepted) {
ngToast.danger({ content: $translate.instant('disclaimer_requested') });
return;
}
if (!$scope.formdata.role) {
ngToast.danger({ content: $translate.instant('case_requested') });
return;
}
if (!$scope.signInForm.$valid)
return;
$scope.showdialog = true;
if ($scope.formdata.id_off == -1)
delete $scope.formdata.id_off;
if ($scope.formdata.role === 'tutor_nooffice') {
$scope.formdata.office.name = 'no_office';
$scope.formdata.office.address = $scope.formdata.address;
$scope.formdata.office.postalCode = $scope.formdata.postalCode;
$scope.formdata.office.country = $scope.formdata.country;
$scope.formdata.office.contactPerson = $scope.formdata.name + " " + $scope.formdata.surname;
$scope.formdata.office.phone1 = $scope.formdata.phone;
$scope.formdata.office.email = $scope.formdata.email;
$scope.formdata.office.lang = $scope.formdata.lang;
}
$http
.post(config.backend + '/sup', $scope.formdata)
.success(function () {
ngToast.success({ content: $translate.instant('user_created', { name: $scope.formdata.name, surname: $scope.formdata.surname }) });
$scope.reset();
})
.error(function () {
ngToast.danger({ content: $translate.instant('user_exists', {email: $scope.formdata.email}) });
});
};
});
......@@ -2,7 +2,7 @@
<div class="header-image">
<div class="row">
<div class="col-md-12 text-center">
<img ng-src="{{office.logoUrl}}" alt="{{office.name}}" title="{{office.name}}">
<img ng-src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram">
</div>
</div>
</div>
......@@ -10,69 +10,322 @@
<br>
<div id="main-content" class="container">
<div class="row">
<div id="main-content">
<!-- Form column and offset -->
<div class="col-md-4 col-md-offset-2">
<div id="login">
<!-- Formulario -->
<!-- LoginCtrl controls here, see app.js -->
<form name="loginForm" ng-submit="login()" novalidate>
<!-- Email -->
<div class="form-group">
<label translate>email</label>:
<input type="email" class="form-control" id="login_email" placeholder="{{ 'your_email' | translate}}" required ng-model="credentials.email" />
</div>
<!-- Password -->
<div class="form-group">
<label translate>password</label>:
<input type="password" class="form-control" id="login_password" placeholder="{{ 'your_password' | translate}}" required ng-model="credentials.password" />
<div class="row">
<div class="col-md-2">
</div>
<div class="col-md-8">
<div class="switch-panel-body height600" ng-switch="slide.state">
<!--
SLIDE 1: login pane
-->
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="login">
<div class="row">
<div class="col-md-2">
</div>
<div class="col-md-4">
<!-- Formulario -->
<!-- LoginCtrl controls here, see app.js -->
<form name="loginForm" ng-submit="login()" novalidate>
<!-- Email -->
<div class="form-group">
<label translate>email</label>:
<input type="email" class="form-control" id="login_email" placeholder="{{ 'your_email' | translate}}" required ng-model="credentials.email" />
</div>
<!-- Password -->
<div class="form-group">
<label translate>password</label>:
<input type="password" class="form-control" id="login_password" placeholder="{{ 'your_password' | translate}}" required ng-model="credentials.password" />
</div>
<div class="row">
<div class="col-xs-6">
<!-- Login -->
<div class="pull-left">
<button type="submit" class="btn btn-primary" translate>login</button>
</div>
<!-- Spinner -->
<div class="pull-left">
<i ng-class="{'fa fa-spinner fa-spin fa-2x fa-fw margin-bottom': true, 'spin_disabled': !submitted}"></i>
</div>
</div>
<div class="col-xs-6 margin-top7">
<!-- Remember -->
<div class="checkbox">
<label>
<input type="checkbox" id="login_savepassword" ng-model="credentials.savepassword" />{{ 'remember' | translate }}
</label>
</div>
</div>
</div>
<br>
<!-- Remember password -->
<div class="row text-center">
<a href="/app/#/changepass" translate>password_forgotten</a>
</div>
<!-- Create account -->
<div class="row text-center">
<a ng-click="slide.rightTo('accounts')" translate>create_an_account</a>
</div>
</form>
</div>
<!--/. form column -->
<!-- Image column -->
<div class="col-md-4 text-center">
<img src="img/login.png" alt="Pictogram" title="Pictogram" />
</div>
<!--/. image column -->
<div class="col-md-2">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<!-- Login -->
<div class="pull-left">
<button type="submit" class="btn btn-primary" translate>login</button>
<!--
SLIDE 2: Account selection
-->
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="accounts">
<h2 translate>select_account</h2>
<div class="row">
<div class="col-md-4">
<legend translate>parents_tutor</legend>
<div class="text-center">
<a ng-click="slide.rightTo('tutor'); formdata.role = 'tutor'">
<img src="img/parents.png" alt="{{'parents_tutor' | translate}}" title="{{'parents_tutor' | translate}}"
ng-class="{'img-200': hover_tutor}"
ng-mouseenter="hover_tutor = true"
ng-mouseleave="hover_tutor = false"/>
</a>
</div>
</div>
<div class="col-md-4">
<legend translate>therapist</legend>
<div class="text-center">
<a ng-click="slide.rightTo('therapist'); formdata.role = 'therapist'">
<img src="img/therapist.png" alt="{{'therapist' | translate}}" title="{{'therapist' | translate}}"
ng-class="{'img-200': hover_therapist}"
ng-mouseenter="hover_therapist = true"
ng-mouseleave="hover_therapist = false"/>
</a>
</div>
</div>
<!-- Spinner -->
<div class="pull-left">
<i ng-class="{'fa fa-spinner fa-spin fa-2x fa-fw margin-bottom': true, 'spin_disabled': !submitted}"></i>
<div class="col-md-4">
<legend translate>office_center</legend>
<div class="text-center">
<a ng-click="slide.rightTo('office'); formdata.role = 'office'">
<img src="img/office.jpg" alt="{{'office_center' | translate}}" title="{{'office_center' | translate}}"
ng-class="{'img-200': hover_office}"
ng-mouseenter="hover_office = true"
ng-mouseleave="hover_office = false"/>
</a>
</div>
</div>
</div>
<div class="col-xs-6 margin-top7">
<!-- Remember -->
<div class="checkbox">
<label>
<input type="checkbox" id="login_savepassword" ng-model="credentials.savepassword" />{{ 'remember' | translate }}
</label>
<div class="row">
<div class="col-md-4">
<p translate>account_desc_tutor</p>
</div>
<div class="col-md-4">
<p translate>account_desc_therapist</p>
</div>
<div class="col-md-4">
<p translate>account_desc_office</p>
</div>
</div>
</div>
<br>
<!--
SLIDE 3: Tutor account form
-->
<form name="forms.tutorForm" role="form" ng-submit="signup('tutorForm')" novalidate ng-if="formdata.role == 'tutor'">
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="tutor">
<legend translate>parents_tutor</legend>
<div class="row">
<div class="col-md-4 text-center">
<img src="img/parents.png" alt="{{'parents_tutor' | translate}}" title="{{'parents_tutor' | translate}}" />
</div>
<div class="form-group col-md-4">
<input type="hidden" ng-model="formdata.role" value="tutor"></input>
<div class="form-group">
<label translate>email</label>
<div class="form-group">
<input type="email" class="form-control" name="email" placeholder="{{ 'email' | translate }}" ng-model="formdata.email"/>
<span class="color_red text_sm pull-right" ng-show="forms.tutorForm.email.$dirty && forms.tutorForm.email.$invalid" translate>email_invalid</span>
</div>
</div>
<fieldset>
<label translate>password</label>
<div class="form-group">
<input type="password" class="form-control" id="signin_password1" placeholder="{{ 'password_type' | translate }}" name="password" required ng-model="formdata.password"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.tutorForm.password.$dirty && forms.tutorForm.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="signin_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" required ng-model="formdata.password_confirm"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.tutorForm.password.$dirty && forms.tutorForm.password_confirm.$dirty" translate>password_match</span>
</div>
</fieldset>
<div class="form-group">
<input type="checkbox" ng-model="formdata.disclaimer_accepted">
<span translate>disclaimer_accept</span>
</div>
<div class="form-group">
<label>Captcha</label>
<div vc-recaptcha></div>
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-4">
<button class="btn btn-default" ng-click="slide.leftTo('accounts')">&lt;&lt; {{ 'back' | translate }} </button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-primary" ng-disabled="forms.tutorForm.$invalid || !formdata.disclaimer_accepted">{{ 'create_account' | translate }} &gt;&gt; </button>
</div>
</div>
</div>
</form>
<!--
SLIDE 4: Therapist account form
-->
<form name="forms.therapistForm" role="form" ng-submit="signup('therapistForm')" novalidate ng-if="formdata.role == 'therapist'">
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="therapist">
<legend translate>therapist</legend>
<div class="row">
<div class="col-md-4 text-center">
<img src="img/therapist.png" alt="{{'therapist' | translate}}" title="{{'therapist' | translate}}" />
</div>
<div class="form-group col-md-4" id="tutor_form">
<div class="form-group">
<label translate>email</label>
<input type="email" class="form-control" name="email" placeholder="{{ 'email' | translate }}" ng-model="formdata.email"/>
<span class="color_red text_sm pull-right" ng-show="forms.therapistForm.email.$dirty && forms.therapistForm.email.$invalid" translate>email_invalid</span>
</div>
<fieldset>
<label translate>password</label>
<div class="form-group">
<input type="password" class="form-control" id="signin_password1" placeholder="{{ 'password_type' | translate }}" name="password" required ng-model="formdata.password"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.therapistForm.password.$dirty && forms.therapistForm.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="signin_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" required ng-model="formdata.password_confirm"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.therapistForm.password.$dirty && forms.therapistForm.password_confirm.$dirty" translate>password_match</span>
</div>
</fieldset>
<div class="form-group">
<input type="checkbox" ng-model="formdata.disclaimer_accepted">
<span translate>disclaimer_accept</span>
</div>
<div class="form-group">
<label>Captcha</label>
<div vc-recaptcha></div>
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-4">
<button class="btn btn-default" ng-click="slide.leftTo('accounts')">&lt;&lt; {{ 'back' | translate }} </button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-primary" ng-disabled="forms.therapistForm.$invalid || !formdata.disclaimer_accepted">{{ 'create_account' | translate }} &gt;&gt; </button>
</div>
</div>
</div>
</form>
<!--
SLIDE 5: Office account form
-->
<form name="forms.officeForm" role="form" ng-submit="signup('officeForm')" novalidate ng-if="formdata.role == 'office'">
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="office">
<legend translate>office_center</legend>
<div class="row">
<div class="col-md-4 text-center">
<img src="img/office.jpg" alt="{{'office_center' | translate}}" title="{{'office_center' | translate}}" />
</div>
<div class="form-group col-md-4" id="office_form">
<div class="form-group">
<label translate>name</label>
<input type="text" class="form-control" placeholder="{{ 'name' | translate }}" name="name" required ng-model="formdata.name"/>
</div>
<div class="form-group">
<label translate>email</label>
<input type="email" class="form-control" placeholder="{{ 'email' | translate }}" name="email" required ng-model="formdata.email"/>
<span class="color_red text_sm pull-right" ng-show="forms.officeForm.email.$dirty && forms.officeForm.email.$invalid" translate>email_invalid</span>
</div>
<fieldset>
<label translate>password</label>
<div class="form-group">
<input type="password" class="form-control" id="signin_password1" placeholder="{{ 'password_type' | translate }}" name="password" required ng-model="formdata.password"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.officeForm.password.$dirty && forms.officeForm.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="signin_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" required ng-model="formdata.password_confirm"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.officeForm.password.$dirty && forms.officeForm.password_confirm.$dirty" translate>password_match</span>
</div>
</fieldset>
<div class="form-group">
<input type="checkbox" ng-model="formdata.disclaimer_accepted">
<span translate>disclaimer_accept</span>
</div>
<div class="form-group">
<label>Captcha</label>
<div vc-recaptcha></div>
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-4">
<button class="btn btn-default" ng-click="slide.leftTo('accounts')">&lt;&lt; {{ 'back' | translate }} </button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-primary" ng-disabled="forms.officeForm.$invalid">{{ 'create_account' | translate }} &gt;&gt; </button>
</div>
</div>
</div>
</form>
<!--
SLIDE 6: Confirmation message
-->
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="confirmation">
<h2>{{ 'user_created' | translate }} </h2>
<p> {{ 'user_created_text' | translate:'{ email: formdata.email }' }} </p>
<br>
<img src="img/child.png"/>
<!-- Remember password -->
<div class="row text-center">
<a href="/app/#/changepass" translate>password_forgotten</a>
</div>
<!-- Create account -->
<div class="row text-center">
<a href="/app/#/signin" translate>create_an_account</a>
</div>
</form>
</div>
</div>
<div class="col-md-2">
</div>
<!--/. login -->
</div>
<!--/. form column -->
<!-- Image column -->
<div class="col-xs-12 col-md-4 text-center">
<img src="img/login.png" alt="Pictogram" title="Pictogram" />
<div class="text-center">
<a ng-click="slide.leftTo('login')" ng-if="slide.state != 'login'"><< {{ 'back_to_login' | translate}}</a>
</div>
<!--/. image column -->
</div>
</div>
<footer-translate></footer-translate>
<!-- SigningCtrl controls here, see app.js -->
<div class="container">
<div class="row">
<!-- Rejilla 3 elementos de igual ancho -->
<div class="col-lg-2">&nbsp;</div>
<div class="col-lg-8">
<p>&nbsp;</p>
<p class="text-center">
<a href="/app"><img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" style="border-style: none"/></a>
</p>
<div class="page-header">
<h2 translate>register</h2>
</div>
<div id="signin">
<!-- Logo Pictogram -->
<!-- Formulario -->
<form name="signInForm" role="form" ng-submit="signin()">
<fieldset>
<legend translate>personal_data</legend>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<input type="text" class="form-control" id="signin_name" placeholder="{{ 'name' | translate }}" required ng-model="formdata.name"/>
</div>
</div>
<div class="col-md-8">
<div class="form-group">
<input type="text" class="form-control" id="signin_surname" placeholder="{{ 'surname' | translate }}" required ng-model="formdata.surname"/>
</div>
</div>
</div>
<div class="form-group">
<input type="text" class="form-control" id="signin_address" placeholder="{{ 'address' | translate }}" ng-model="formdata.address"/ required>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<input type="text" class="form-control" id="signin_postal_code" placeholder="{{ 'postal_code' | translate }}" required ng-model="formdata.postalCode" ng-change="formdata.postalCode = formdata.postalCode.toUpperCase()"/>
</div>
</div>
<div class="col-md-8">
<div class="form-group">
<select class="form-control" ng-model="formdata.country" required ng-change="load_tries()">
<option value="00" selected disabled hidden>{{ 'country' | translate }}</option>
<option value="ES">España</option>
<option value="US">United States</option>
<option value="UK">United Kingdom</option>
<option value="IE">Ireland</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input type="text" class="form-control" id="signin_phone" placeholder="{{ 'phone' | translate }}" ng-model="formdata.phone"/>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<select class="form-control" name="signin_gender" id="signin_gender" ng-model="formdata.gender">
<option value="F" translate>woman</option>
<option value="M" translate>man</option>
</select>
</div>
</div>
</div>
</fieldset>
<fieldset>
<div class="row">
<div class="col-md-12">
<span class="color_red text_sm pull-right" ng-show="formdata.email != formdata.email_confirm" translate>email_match</span>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<input type="email" class="form-control" id="email" name="email" placeholder="{{ 'email_type' | translate }}" required ng-model="formdata.email" />
</div>
<div class="col-md-6">
<input type="email" class="form-control" id="email_confirm" name="email_confirm" placeholder="{{ 'email_confirm' | translate }}" required ng-model="formdata.email_confirm" />
</div>
</div>
</div>
</fieldset>
<fieldset>
<div class="row">
<div class="col-md-12">
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm" translate>password_match</span>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<input type="password" class="form-control" id="signin_password1" placeholder="{{ 'password_type' | translate }}" required ng-model="formdata.password" />
</div>
<div class="col-md-6">
<input type="password" class="form-control" id="signin_password2" placeholder="{{ 'password_confirm' | translate }}" required ng-model="formdata.password_confirm" />
</div>
</div>
</div>
</fieldset>
<fieldset>
<div class="form-group">
<select class="form-control" name="signin_language" id="signin_language" ng-model="formdata.lang" required>
<option value="00" selected disabled hidden>{{ 'language' | translate }}</option>
<option value="es-es" selected>Español</option>
<option value="en-gb">English</option>
</select>
</div>
</fieldset>
<fieldset>
<legend translate>case_title</legend>
<div class="form-group">
<div class="row">
<div class="col-md-1 text-right">
<input
type="radio"
ng-model="formdata.role"
value="therapist_office"
onClick="$('#office_selection').slideDown(); $('#office_form').slideUp();">
</div>
<div class="col-md-11">
{{ 'case_therapist_office' | translate }}
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-1 text-right">
<input
type="radio"
ng-model="formdata.role"
value="therapist_nooffice"
onClick="$('#office_selection').slideUp(); $('#office_form').slideDown();"
ng-click="copyFields();">
</div>
<div class="col-md-11">
{{ 'case_therapist_nooffice' | translate }}
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-1 text-right">
<input
type="radio"
ng-model="formdata.role"
value="tutor_office"
onClick="$('#office_selection').slideDown(); $('#office_form').slideUp();">
</div>
<div class="col-md-11">
{{ 'case_tutor_office' | translate }}
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-1">
<input
type="radio"
ng-model="formdata.role"
value="tutor_nooffice"
onClick="$('#office_selection').slideUp(); $('#office_form').slideUp(); copyFields();"
ng-click="copyFields();">
</div>
<div class="col-md-11">
{{ 'case_tutor_nooffice' | translate }}
</div>
</div>
</div>
</fieldset>
<div class="form-group" id="office_form" hidden>
<legend translate>office_center</legend>
<div class="form-group">
<input type="text" class="form-control" placeholder="{{ 'name' | translate }}" ng-model="formdata.office.name" ng-required="formdata.role == 'therapist_nooffice'"/>
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="{{ 'logo_url' | translate }}" ng-model="formdata.office.logoUrl"/>
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="{{ 'address' | translate }}" ng-model="formdata.office.address" ng-required="formdata.role == 'therapist_nooffice'"/>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input type="text" class="form-control" placeholder="{{ 'postal_code' | translate }}" ng-model="formdata.office.postalCode" ng-change="formdata.office.postalCode = formdata.office.postalCode.toUpperCase()" ng-required="formdata.role == 'therapist_nooffice'"/>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<input type="text" class="form-control" placeholder="{{ 'contact_person' | translate }}" ng-model="formdata.office.contactPerson" ng-required="formdata.role == 'therapist_nooffice'"/>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input type="email" class="form-control" placeholder="{{ 'email' | translate }}" ng-model="formdata.office.email" ng-required="formdata.role == 'therapist_nooffice'"/>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<input type="text" class="form-control" placeholder="{{ 'phone' | translate }}" ng-model="formdata.office.phone1" ng-required="formdata.role == 'therapist_nooffice'"/>
</div>
</div>
</div>
</div>
<div class="form-group" id="office_selection">
<legend translate>office_center</legend>
<select class="form-control" ng-model="formdata.id_off" ng-required="formdata.role == 'therapist_office' || formdata.role == 'tutor_office'">
<option selected disabled hidden value="-1">{{ 'select_office' | translate }}</option>
<option ng-repeat="office in offices | orderBy: 'name' track by office.id" ng-value="office.id"> {{ office.name }} </option>
</select>
</div>
<div class="form-group">
<legend></legend>
<input type="checkbox" ng-model="formdata.disclaimer_accepted">
<span translate>disclaimer_accept</span>
</div>
<div class="form-group">
<legend>Captcha</legend>
<div vc-recaptcha></div>
</div>
<p class="text-center">
<a href="/app/#/login" class="btn btn-default" translate>cancel</a>
<button type="submit" class="btn btn-primary" ng-disabled="signInForm.$invalid" translate>create_account</button>
</p>
</form>
</div>
<!-- Fin signin -->
</div>
<div class="col-lg-2">&nbsp;</div>
</div>
<!-- Fin de row -->
</div>
<!-- Fin de container -->
<footer-translate></footer-translate>
......@@ -26,7 +26,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
});*/
$scope.supsForm = {};
$scope.section = 'account';
$scope.section = {val: 'account'};
$scope.changeImg = function () {
......@@ -148,11 +148,11 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
.error(function (err) {
console.log(err);
if (err.message && err.message.search('nvalid license') > 0)
ngToast.danger({ content: $translate.instant('license_invalid') });
ngToast.danger($translate.instant('license_invalid'));
else if (err.message && err.message.search('in use') > 0)
ngToast.danger({ content: $translate.instant('license_already_activated') });
ngToast.danger($translate.instant('license_already_activated'));
else
ngToast.danger({ content: $translate.instant('student_not_updated') });
ngToast.danger($translate.instant('student_not_updated'));
});
};
......@@ -161,26 +161,21 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
* The email used for search is fetched from $scope.email_sup.
*/
$scope.search_sup = function () {
console.log("--> " + $scope.supsForm.email_sup);
// Find tutor by email
$http.get(config.backend + '/sup/email/' + $scope.supsForm.email_sup)
$http.get(config.backend + '/sup/off/email/' + $scope.supsForm.email_sup)
.success(function (data) {
if (data) {
$scope.supToAdd = data;
$scope.showmessagesupfound = true;
$scope.showmessagesupnotfound = false;
} else {
$translate('sup_not_found').then(function (translation) {
ngToast.danger({ content: translation });
});
ngToast.danger($translate.instant('sup_not_in_office'));
// Hide the success message (if it exists by other query)
$scope.showmessagesupfound = false;
}
})
.error(function () {
$translate('sup_not_found').then(function (translation) {
ngToast.danger({ content: translation });
});
ngToast.danger($translate.instant('sup_not_in_office'));
});
};
......@@ -193,13 +188,13 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
// Ensure supervisor is not already in the list
if ($scope.studentSupervisors.map((s) => s.id).includes($scope.supToAdd.id)) {
ngToast.danger({ content: $translate.instant('sup_already_added') });
ngToast.danger($translate.instant('sup_already_added'));
$scope.supsForm.email_sup = '';
$scope.showmessagesupfound = false;
return;
}
$http.post(config.backend + '/stu/' + $scope.studentData.id + '/sup/' + $scope.supToAdd.id, {asTherapist: true})
$http.post(config.backend + '/stu/' + $scope.studentData.id + '/sup/' + $scope.supToAdd.id)
.success(function (data) {
// Assign the info of supervisor to add
stusup.supervisor = $scope.supToAdd;
......@@ -214,7 +209,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
$scope.showmessagesupfound = false;
})
.error(function () {
ngToast.danger({ content: $translate.instant('sup_not_added') });
ngToast.danger($translate.instant('sup_not_added'));
});
};
......@@ -226,7 +221,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
var deleteSup = $window.confirm(
$translate.instant(
'confirm_unlink_therapist',
'confirm_unlink_student',
{name: $scope.studentSupervisors[i].name, student: $scope.studentData.name}
));
......@@ -243,95 +238,6 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
}
};
// Search tutor by email
$scope.search_tutor = function () {
// Find tutor by email
$http.get(config.backend + '/sup/email/' + $scope.supsForm.email_tutor)
.success(function (data) {
// If it found the length is > 0
if (data) {
$scope.tutorToAdd = data;
// Show message for validate
$scope.showmessagetutorfound = true;
$scope.showmessagetutornotfound = false;
} else {
$translate('tutor_not_found').then(function (translation) {
ngToast.danger({ content: translation });
});
// Hide the success message (if it exists by other query)
$scope.showmessagetutorfound = false;
}
})
.error(function () {
$translate('tutor_not_found').then(function (translation) {
ngToast.danger({ content: translation });
});
});
};
// Add tutor
$scope.add_tutor = function () {
var stusup = {
student: $scope.studentData.id,
supervisor: $scope.tutorToAdd.id
};
// Ensure supervisor is not already in the list
if ($scope.studentTutors.map((s) => s.id).includes($scope.tutorToAdd.id)) {
ngToast.danger({ content: $translate.instant('sup_already_added') });
$scope.supsForm.email_tutor = '';
$scope.showmessagetutorfound = false;
return;
}
$http.post(config.backend + '/stu/' + $scope.studentData.id + '/sup/' + $scope.tutorToAdd.id)
.success(function (data) {
// Assign the info of supervisor to add
stusup.supervisor = $scope.tutorToAdd;
stusup.id = data.id;
// Add to the list of tutors in view
$scope.studentTutors.push($scope.tutorToAdd);
// Delete the email form field
$scope.supsForm.email_tutor = '';
// Hide the message of tutor founded
$scope.showmessagetutorfound = false;
$translate('tutor_added').then(function (translation) {
ngToast.success({ content: translation });
});
})
.error(function () {
$translate('tutor_not_added').then(function (translation) {
ngToast.danger({ content: translation });
});
});
};
// Delete tutor
$scope.delete_tutor = function (id_sup) {
//Se recorre el array de objetos json para buscarlo
var i;
for (i = 0; i < $scope.studentTutors.length && id_sup !== $scope.studentTutors[i].id; i++);
var deleteTutor = $window.confirm(
$translate.instant(
'confirm_unlink_tutor',
{name: $scope.studentTutors[i].name, student: $scope.studentData.name}
));
if (deleteTutor) {
$http.delete(config.backend + '/stu/' + $scope.studentData.id + '/sup/' + id_sup)
.success(function () {
// Eliminar de la vista
$scope.studentTutors.splice(i, 1);
ngToast.success({ content: $translate.instant('tutor_deleted') });
})
.error(function () {
ngToast.danger({ content: $translate.instant('tutor_not_deleted') });
});
}
};
// *******************************************************
// Setup
// $scope.studentData.attributes
......@@ -342,14 +248,10 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
attributes: $scope.studentData.attributes
})
.success(function () {
$translate('attributes_updated').then(function (translation) {
ngToast.success({ content: translation });
});
ngToast.success($translate.instant('attributes_updated'));
})
.error(function () {
$translate('attributes_not_updated').then(function (translation) {
ngToast.danger({ content: translation });
});
ngToast.danger($translate.instant('attributes_not_updated'));
});
}, 300);
});
......@@ -32,10 +32,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
number: ''
},
license_expired: false,
office: {
id: '',
name: ''
},
stuSup: [],
pcb_count: 0,
pdb_count: 1
......@@ -84,15 +80,14 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
$scope.studentData.license_expired = new Date($scope.studentData.license.expiration_ts) - new Date() < 0;
moment.locale($translate.use().substr(0, 2));
$scope.studentData.expiration_date = moment($scope.studentData.license.expiration_ts).format('L');
console.log("updateLicenseExpiration");
};
// ----------------------------------------------------------------------
// MAIN
//
// Load student account information
//
//
$http.get(config.backend + '/stu/' + $scope.studentData.id)
.success(function (data) {
$scope.studentData.id = data.id;
......@@ -105,8 +100,6 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
$scope.studentData.gender = data.gender;
$scope.studentData.lang = data.lang;
$scope.studentData.notes = data.notes;
$scope.studentData.office.id = data.office.id;
$scope.studentData.office.name = data.office.name;
$scope.studentData.stuSup = data.stuSup;
$scope.studentData.attributes = data.attributes;
$scope.studentData.current_method = data.current_method;
......@@ -148,27 +141,22 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
ngToast.danger({ content: $translate.instant('no_subscribed') });
});
//
// For tab navigation, initially blank goes to collections
// Defined as JSON object to be available in in children as the same scope
//
$scope.nav = {
tab: 'collections'
};
//
// Load student supervisors
//
$scope.studentSupervisors = [];
$http.get(config.backend + '/stu/' + $scope.studentData.id + '/therapists')
$http.get(config.backend + '/stu/' + $scope.studentData.id + '/supervisors')
.success(function (data) {
$scope.studentSupervisors = data;
})
.error(function () {
// TODO show error with ngToast
});
.error(function (err) {});
$scope.studentTutors = [];
$http.get(config.backend + '/stu/' + $scope.studentData.id + '/tutors')
.success(function (data) {
$scope.studentTutors = data;
})
.error(function () {
// TODO show error with ngToast
});
});
......@@ -25,7 +25,8 @@
ng-init="rowIndex = $index"
class="picto-grid__row">
<div
class="picto pull-left ng-class:{'picto-out': studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)};"
ng-hide="studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)"
class="picto pull-left"
data-row="{{ rowIndex }}"
data-column="{{ colIndex }}"
id="student-picto-{{
......@@ -117,7 +118,8 @@
ng-init="rowIndex = $index"
class="picto-grid__row">
<div
class="picto pull-left ng-class:{'picto-out': studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)};"
ng-hide="studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)"
class="picto pull-left"
ng-repeat="studentPicto in studentPictoRow track by $index"
ng-init="colIndex = $index"
popover="{{ studentPicto != emptyStudentPicto ? studentPicto.attributes.expression : ''}}"
......@@ -231,7 +233,8 @@
ng-init="rowIndex = $index"
class="picto-grid__row">
<div
class="picto pull-left ng-class:{'picto-out': studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)};"
ng-hide="studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)"
class="picto pull-left"
data-row="{{ rowIndex }}"
data-column="{{ colIndex }}"
id="student-picto-{{
......
......@@ -50,17 +50,17 @@
<div class="row">
<div class="col-md-12">
<ul class="nav nav-tabs tabs_student">
<!-- 0: admin, 1: tutor, 2: therapist -->
<li role="presentation" ng-class="{'active' : nav.tab == 'collections'}" ng-if="studentData.supervision != 0">
<!-- 0: admin, 1: tutor, 2: therapist -->
<li role="presentation" ng-class="{'active' : nav.tab == 'collections'}" ng-if="studentData.license.isValid || !studentData.license.isTrial">
<a href="/app/#/student/{{studentData.id}}/collections" ng-click="nav.tab = ''"><span class="glyphicon glyphicon-th" aria-hidden="true"></span> {{ 'collections' | translate }}</a>
</li>
<li role="presentation" ng-class="{'active' : nav.tab == 'instructions'}" ng-if="studentData.supervision == 2">
<li role="presentation" ng-class="{'active' : nav.tab == 'instructions'}" ng-if="studentData.license.isValid && !user.isTutor">
<a href="/app/#/student/{{studentData.id}}/instructions" ng-click="nav.tab = 'instructions'"><span class="glyphicon glyphicon-tasks" aria-hidden="true"></span> {{ 'instructions' | translate }}</a>
</li>
<li role="presentation" ng-class="{'active' : nav.tab == 'session'}" ng-if="studentData.supervision == 2">
<li role="presentation" ng-class="{'active' : nav.tab == 'session'}" ng-if="studentData.license.isValid && !user.isTutor">
<a href="/app/#/student/{{studentData.id}}/session" ng-click="nav.tab = 'session'"><span class="glyphicon glyphicon-transfer" aria-hidden="true"></span> {{ 'sessions' | translate }}</a>
</li>
<li role="presentation" ng-class="{'active' : nav.tab == 'reports'}" ng-if="studentData.supervision != 1">
<li role="presentation" ng-class="{'active' : nav.tab == 'reports'}" ng-if="studentData.license.isValid && !user.isTutor">
<a href="/app/#/student/{{studentData.id}}/reports" ng-click="nav.tab = 'reports'"><i class="fa fa-bar-chart" aria-hidden="true"></i> {{ 'reports' | translate }}</a>
</li>
<li role="presentation" ng-class="{'active' : nav.tab == 'setup'}">
......
......@@ -2,18 +2,21 @@
<div class="panel-body">
<div class="btn-group">
<button class="btn btn-default" btn-radio="'account'" ng-model="section">
<button class="btn btn-default" btn-radio="'account'" ng-model="section.val">
<i class="fa fa-user" aria-hidden="true"></i> {{ 'account' | translate }}
</button>
<button class="btn btn-default" btn-radio="'device'" ng-model="section">
<button class="btn btn-default" btn-radio="'device'" ng-model="section.val" ng-if="studentData.license.isValid || studentData.license.isOfficial">
<i class="fa fa-tablet" aria-hidden="true"></i> {{ 'device' | translate }}
</button>
<button class="btn btn-default" btn-radio="'supervisors'" ng-model="section">
<button class="btn btn-default" btn-radio="'supervisors'" ng-model="section.val" ng-if="user.isOffice">
<i class="fa fa-users" aria-hidden="true"></i> {{ 'supervisors' | translate }}
</button>
</div>
<div class="row" ng-show="section == 'account'">
<!-- ***********************************************************************
Sección: Configuración de la cuenta del estudiante
-->
<div class="row" ng-show="section.val == 'account'">
<!-- Parte izquierda: Datos personales -->
<div class="col-md-6">
<legend translate>account</legend>
......@@ -51,25 +54,42 @@
<label translate>license_number</label>
<input type="text" id="setup_license" class="form-control" mask="wwww-wwww-wwww-wwww" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formUser.license_number" required>
<!-- With license -->
<div ng-show="studentData.license && !studentData.license_expired" class="alert alert-info" role="alert">
<!-- With official license -->
<div ng-show="studentData.license && studentData.license.isValid && studentData.license.isOfficial" class="alert alert-info" role="alert">
<div class="row">
<div class="col-xs-2"><i class="fa fa-info-circle fa-lg" aria-hidden="true"></i></div>
<div class="col-xs-2"><i class="fa fa-certificate fa-lg" aria-hidden="true"></i></div>
<div class="col-xs-10">
{{ 'license_expires' | translate }} <b>{{ studentData.expiration_date }}</b>
{{ 'license_expires_official' | translate }} <b>{{ studentData.expiration_date }}</b>
</div>
</div>
</div>
<!-- License expired -->
<div ng-show="studentData.license && studentData.license_expired" class="alert alert-warning" role="alert">
<!-- With trial license -->
<div ng-show="studentData.license && studentData.license.isValid && studentData.license.isTrial" class="alert alert-info" role="alert">
<div class="row">
<div class="col-xs-2"><i class="fa fa-exclamation-circle fa-lg" aria-hidden="true"></i></div>
<div class="col-xs-2"><i class="fa fa-flask fa-lg" aria-hidden="true"></i></div>
<div class="col-xs-10">
<h4 class="alert-heading"> {{ 'license_expired' | translate }} </h4>
<p>
<a href="http://pictogramweb.com/caracteristicas-de-pictogram/">{{ 'license_expired_renew' | translate }}</a>
</p>
{{ 'license_expires_trial' | translate }} <b>{{ studentData.expiration_date }}</b>
</div>
</div>
</div>
<!-- Official license expired -->
<div ng-show="studentData.license && !studentData.license.isValid && studentData.license.isOfficial" class="alert alert-warning" role="alert">
<div class="row">
<div class="col-xs-2"><i class="fa fa-certificate fa-lg text-danger" aria-hidden="true"></i></div>
<div class="col-xs-10">
{{ 'license_expired_official' | translate }} <a href="http://pictogramweb.com/caracteristicas-de-pictogram/">{{ 'license_expired_renew' | translate }}</a>.
</div>
</div>
</div>
<!-- Trial license expired -->
<div ng-show="studentData.license && !studentData.license.isValid && studentData.license.isTrial" class="alert alert-warning" role="alert">
<div class="row">
<div class="col-xs-2"><i class="fa fa-flask fa-lg text-danger" aria-hidden="true"></i></div>
<div class="col-xs-10">
{{ 'license_expired_trial' | translate }} <a href="http://pictogramweb.com/caracteristicas-de-pictogram/">{{ 'license_expired_buy' | translate }}</a>.
</div>
</div>
</div>
......@@ -170,9 +190,12 @@
</div> <!-- Fin de student_personal_edit -->
<!-- ***********************************************************************
Sección: Configuración del dispositivo
-->
<!-- Configuración dispositivo -->
<div id="device_setup" ng-show="section == 'device'">
<div id="device_setup" ng-show="section.val == 'device'">
<div class="row">
<div class="col-md-6">
<legend translate>device_setup</legend>
......@@ -308,18 +331,32 @@
</div>
</div>
<!-- ***********************************************************************
Sección: Gestión de supervisores
-->
<!-- Tutores y dispositivos -->
<div id="supervisors_section" ng-show="section == 'supervisors'">
<div id="supervisors_section" ng-show="section.val == 'supervisors'" ng-if="user.isOffice">
<legend translate>link_supervisor</legend>
<div class="row">
<div class="col-md-5" ng-if="studentData.supervision != 1">
<div class="col-md-5">
<div class="alert alert-info">
<p translate>link_supervisor_desc</p>
<p translate>supervisor_note</p>
</div>
</div>
<div class="col-md-5">
<!-- Supervisores (terapeutas) del alumno -->
<div id="student_sups">
<legend translate>therapists</legend>
<!-- Buscador de supervisores -->
<p>
<form role="search" ng-submit="search_sup()">
<div class="input-group" ng-if="user.isSupAdmin">
<div class="input-group">
<input type="email" class="form-control" placeholder="{{ 'search_sup_email' | translate }}" name="email_sup" id="email_sup" ng-model="supsForm.email_sup" required>
<div class="input-group-btn">
<button class="btn btn-default" type="submit">
......@@ -336,71 +373,34 @@
<img ng-src="{{supToAdd.pic}}" class="profile" alt="" title="" /> {{ supToAdd.name }} {{ supToAdd.surname }}
<a class="btn btn-default btn-sm pull-right" role="button" ng-click="add_sup()" translate>add</a>
</div>
<!-- Fin de buscador de supervisores -->
<!-- Supervisores asignados -->
<ul class="list-group" id="user_sups">
<li class="list-group-item" ng-repeat="sup in studentSupervisors">
<!-- Imagen de perfil del supervisor -->
<img ng-src="{{sup.pic}}" class="profile" alt="" title="" />
{{sup.name}} {{sup.surname}}
<a ng-if="user.isSupAdmin" ng-click="delete_sup(sup.id)" class="delete_sup" title="{{ 'unlink' | translate}}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</li>
</ul>
<!-- Fin de Supervisores asignados -->
</div>
<!-- Fin de id student-sups -->
</div>
<div class="col-md-5">
<!-- Tutores (Padres) -->
<div id="student_tutors" ng-if="studentData.supervision != 1">
<legend translate>tutors</legend>
<!-- Buscador de tutores -->
<p>
<form role="search" ng-submit="search_tutor()">
<div class="input-group" ng-if="user.isSupAdmin">
<input type="email" class="form-control" placeholder="{{ 'search_tutor_email' | translate }}" name="email_tutor" id="email_tutor" ng-model="supsForm.email_tutor" required>
<div class="input-group-btn">
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search"></span>
</button>
<div class="row">
<div class="col-xs-2">
<!-- Imagen de perfil del supervisor -->
<img ng-src="{{sup.pic}}" class="profile" alt="" title="" />
</div>
<div class="col-xs-8">
{{ sup.name }} {{ sup.surname }} <br> <span class="text-muted">{{ sup.role | translate }}</span>
</div>
<div class="col-xs-2">
<a ng-click="delete_sup(sup.id)" class="delete_sup" title="{{ 'unlink' | translate}}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</div>
</div>
</form>
</p>
<!-- Alert and success messages for tutor found -->
<div ng-show="{{ 'showmessagetutorfound' }}" class="alert alert-info">
<!-- Imagen de perfil del tutor -->
<img ng-src="{{tutorToAdd.pic}}" class="profile" alt="" title="" />
{{ tutorToAdd.name }} {{ tutorToAdd.surname }}
<a class="btn btn-default btn-sm pull-right" role="button" ng-click="add_tutor()" translate>add</a>
</div>
<!-- Fin de buscador de tutores -->
<!-- Tutores asignados -->
<ul class="list-group" id="user_tutors">
<li class="list-group-item" ng-repeat="tutor in studentTutors">
<!-- Imagen de perfil del tutor -->
<img ng-src="{{tutor.pic}}" class="profile" alt="" title="" />
{{tutor.name}} {{tutor.surname}}
<a ng-if="user.isSupAdmin" ng-click="delete_tutor(tutor.id)" class="delete_tutor" title="{{ 'unlink' | translate}}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</li>
</ul>
<!-- Fin de Tutores asignados -->
<!-- Info message -->
<div class="alert alert-info">{{ 'supervisor_note' | translate }}</div>
<!-- Fin de Supervisores asignados -->
</div>
<!-- Fin de id student-tutors -->
<!-- Fin de id student-sups -->
</div>
</div>
</div> <!-- /supervisores -->
</div>
<!-- Fin de panel body -->
</div>
......
......@@ -124,6 +124,8 @@ dashboardControllers.controller('SetupCtrl', function SetupCtrl(
user.phone = data.phone;
user.email = data.email;
user.lang = data.lang;
user.pic = data.pic;
user.role = data.role;
// Delete because at the beginning the variable user is bind
// with the form
......@@ -132,6 +134,9 @@ dashboardControllers.controller('SetupCtrl', function SetupCtrl(
$window.sessionStorage.user = JSON.stringify(user);
$location.path("/students");
//$scope.$apply();
})
.error(function () {
ngToast.danger({ content: $translate.instant('data_no_saved') });
......
......@@ -13,123 +13,167 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$window,
$translate,
ngToast,
IOService) {
$scope.formdatastudent = {
username: '',
password: '',
name: '',
surname: '',
birthdate: '',
country: 'ES',
gender: 'M',
lang: 'es-es',
notes: '',
office: $scope.user.office || { name: '' }
};
$timeout,
IOService,
CONSTANTS) {
// Flags for showing buttons according to role
$scope.user = JSON.parse($window.sessionStorage.user);
// Identify if the user is office administrator
if ($scope.user.office) {
if ($scope.user.office.admin === $scope.user.id) {
$scope.user.isAdmin = true;
}
} else {
$scope.user.office = { name: '' };
}
// --------------------------------------------------------
// Create new account
// --------------------------------------------------------
$scope.minlength = CONSTANTS.password_minlength;
// Hide new student form
$scope.hidestudentadd = true;
// Get list of supervisor's students
$http.get(config.backend + '/sup/' + $scope.user.id + '/students')
.success(function (data) {
$scope.students = data;
})
.error(function () {
ngToast.danger({ content: $translate.instant('error_fetching_students') });
});
// forms container
$scope.forms = {};
// slider object
$scope.slide = {
state: 'accounts',
prev: 'accounts',
back: false,
show: false,
rightTo: function (state) {
$scope.slide.back = false;
$scope.slide.prev = $scope.slide.state;
$timeout(function () {
$scope.slide.state = state;
}, 0);
},
leftTo: function (state) {
$scope.slide.back = true;
$scope.slide.prev = $scope.slide.state;
$timeout(function () {
$scope.slide.state = state;
}, 0);
}
};
// Reset form Student
$scope.resetForm = function () {
// Empty the form
$scope.formdatastudent = {
// Show student form
$scope.showForm = function () {
// Reset the form
$scope.formdata = {
username: '',
password: '',
password_confirm: '',
name: '',
surname: '',
birthdate: '',
name: $translate.instant('name'),
surname: $translate.instant('surname'),
birthdate: Date(),
country: 'ES',
gender: 'M',
lang: 'es-es',
notes: '',
office: $scope.user.office || { name: '' },
current_method: 'no_method',
current_instruction: 'no_instruction',
license_number: ''
license_number: null,
id_sup: $scope.user.id
};
// Hide the form
$scope.hidestudentadd = true;
$scope.slide.state ='accounts';
$scope.slide.show = true;
$('#addform').slideDown('slow', function() {});
};
$scope.hideForm = function () {
$('#addform').slideUp('slow', function() {
$scope.slide.show = false;
$scope.$apply();
});
}
/**
* Add existing account
*/
$scope.addExisting = function () {
// Send link call to server
$http.post(config.backend + '/stu/license/sup/' + $scope.user.id, {license: $scope.formdata.license_number})
.success(function (data) {
loadStudents();
$scope.slide.rightTo('confirmation');
})
.error(function (err) {
var errorMessage = 'student_not_added';
if (err.message && err.message.search('nvalid license') > 0)
errorMessage = 'license_invalid';
else if (err.message && err.message.search('in use') > 0)
errorMessage = 'license_already_activated';
else if (err.message && err.message.search("lready linked") > 0)
errorMessage = 'student_already_linked';
else if (err && err.status === 400)
errorMessage = 'invalid_fields';
ngToast.danger($translate.instant(errorMessage));
});
}
/**
* Add Student
* Add new account
*/
$scope.add_student = function () {
var student = $scope.formdatastudent;
$scope.addNew = function (type) {
// set language according to interface settings
$scope.formdata.lang = $translate.use();
// Validate password match
if (student.password_confirm.length && student.password !== student.password_confirm) {
ngToast.danger({ content: $translate.instant('password_match') });
if ($scope.formdata.password_confirm.length && $scope.formdata.password !== $scope.formdata.password_confirm) {
ngToast.danger($translate.instant('password_match'));
return;
}
// password not changed (don't send it to DB)
if (!student.password_confirm.length) {
delete student.password;
delete student.password_confirm;
}
$http.post(config.backend + '/stu', student)
// Send creating call to server
$http.post(config.backend + '/stu', $scope.formdata)
.success(function (data) {
ngToast.success({ content: $translate.instant('student_added') });
// default values
data.supervision = 0; // by default, only related to office administrator
data.current_method = $translate.instant('no_method');
data.current_instruction = $translate.instant('no_instruction');
data.licenseIsValid = new Date(data.license.expiration_ts) - new Date() > 0 ? true : false;
$scope.students.push(data);
$scope.resetForm();
$scope.hidestudentadd = true;
loadStudents();
$scope.slide.rightTo('confirmation');
})
.error(function (err) {
console.log(typeof err);
console.log(err);
var errorMessage = 'student_not_added';
if (err.message && err.message.search('nvalid license') > 0)
if (err.message && err.message.search('nvalid license') > 0 || typeof err == "string" && err.search('nvalid license') > 0)
errorMessage = 'license_invalid';
else if (err.message && err.message.search('in use') > 0)
else if (err.message && err.message.search('in use') > 0 || typeof err == "string" && err.search('in use') > 0)
errorMessage = 'license_already_activated';
else if (typeof err == "string" && err.search("Maximum number of enrolments reached") > 0)
errorMessage = 'max_licenses_reached';
else if (typeof err == "string" && err.search("already exists") > 0)
else if (err.message && err.message.search('already exists') > 0 || typeof err == "string" && err.search("already exists") > 0)
errorMessage = 'student_already_exists';
else if (err && err.status === 400)
errorMessage = 'invalid_fields';
ngToast.danger({ content: $translate.instant(errorMessage) });
});
};
}
// --------------------------------------------------------
// Students list
// --------------------------------------------------------
function loadStudents() {
// Get list of supervisor's students
$http.get(config.backend + '/sup/' + $scope.user.id + '/students')
.success(function (data) {
$scope.students = data;
})
.error(function () {
ngToast.danger({ content: $translate.instant('error_fetching_students') });
});
}
/**
* Delete Student
* Unlink Student
*/
$scope.delete_student = function (student) {
$scope.unlink_student = function (student) {
if ($window.confirm($translate.instant('confirmation'))) {
$http.delete(config.backend + '/stu/' + student.id)
$http.delete(config.backend + '/stu/' + student.id + '/sup/' + $scope.user.id)
.success(function () {
var i;
for (i = 0; i < $scope.students.length; i++) {
......@@ -149,6 +193,11 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
}
};
/**
* WEBSOCKETS
*/
// When a new student is added to the supervisor, we should update
// the student list if necesary
IOService.on('linkSupervisorToStudent', function (eventData) {
......@@ -173,15 +222,8 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
});
}
});
});
/**
* StudentAddCtrl
*/
dashboardControllers.controller('StudentAddCtrl', function StudentsCtrl($scope) {
$scope.open_calendar = function ($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened_cal_student = true;
};
// Main
loadStudents();
});
......@@ -24,15 +24,15 @@ dashboardControllers.controller('SupervisorCtrl', function SupervisorCtrl(
// Assign values this way (like an object) to ensure it's the parent scope
$scope.user.id = user.id;
$scope.user.name = user.name;
$scope.user.surname = user.surname;
$scope.user.role = user.role;
$scope.user.name = user.name || $translate.instant('name');
$scope.user.surname = user.surname || $translate.instant('surname');
$scope.user.pic = user.pic;
$scope.user.office = user.office;
if ($scope.user.office.name == 'no_office')
$scope.user.office.name = $translate.instant('no_office');
$scope.user.lang = user.lang;
$scope.user.isSupAdmin = user.isSupAdmin;
$scope.user.isOffice = user.isOffice;
$scope.user.isTutor = user.isTutor;
$scope.user.isAdmin = user.isAdmin;
$scope.user.isTherapist = user.isTherapist;
$scope.user.arasaacLicense = user.arasaacLicense;
// Link to setup
......
......@@ -5,16 +5,105 @@
//--------------------------
dashboardControllers.controller('SupervisorsCtrl', function SupervisorsCtrl($scope, $window, $http, config, $translate, ngToast) {
$http
.get(config.backend+'/office/get/' + $scope.user.office.id + '/supervisors')
.success(function(data, status, headers, config) {
$scope.supervisors_list = data;
console.log($scope.supervisors_list);
})
.error(function(data, status, headers, config) {
$translate('error_downloading_supervisors').then(function (translation) {
ngToast.danger({ content: translation });
$scope.inputs = {
search_str: '',
email: ''
};
$scope.supToAdd = {};
function loadSupervisors() {
$http
.get(config.backend+'/sup/' + $scope.user.id + '/supervisors')
.success(function(data, status, headers, config) {
$scope.supervisors_list = data;
console.log($scope.supervisors_list);
})
.error(function(data, status, headers, config) {
ngToast.danger($translate.instant('error_downloading_supervisors'));
});
}
/**
* Get a supervisor by their email and updates the $scope.supToAdd element.
* The email used for search is fetched from $scope.email_sup.
*/
$scope.searchSup = function () {
if (!$scope.user.isOffice) {
console.log("Forbidden action. You're not an office!");
return;
}
if ($scope.inputs.email.length == 0)
return;
// Find tutor by email
$http.get(config.backend + '/sup/email/' + $scope.inputs.email)
.success(function (data) {
if (data) {
$scope.supToAdd = data;
$scope.showmessagesupfound = true;
} else {
ngToast.danger($translate.instant('sup_not_found'));
// Hide the success message (if it exists by other query)
$scope.showmessagesupfound = false;
}
})
.error(function () {
ngToast.danger($translate.instant('sup_not_found'));
});
};
/**
* Links a new supervisor
*/
$scope.confirmLink = function () {
if (!$scope.user.isOffice) {
console.log("Forbidden action. You're not an office!");
return;
}
$scope.showmessagesupfound = false;
$http
.post(config.backend+'/sup/' + $scope.supToAdd.id + '/off/' + $scope.user.id)
.success(function(data, status, headers, config) {
loadSupervisors();
ngToast.success($translate.instant('supervisor_added_notified'));
})
.error(function(error) {
var message = typeof error == 'string' ? error : error.message;
if (message.search('already exists') > 0)
ngToast.danger($translate.instant('supervisor_already_linked'));
else if (message.search('yourself') > 0)
ngToast.danger($translate.instant('supervisor_yourself'));
else
ngToast.danger($translate.instant('no_supervisor_linked'));
});
};
/**
* Unlinks a supervisor
*/
$scope.unlinkSupervisor = function (id) {
if (!$scope.user.isOffice) {
console.log("Forbidden action. You're not an office!");
return;
}
$http
.delete(config.backend+'/sup/' + id + '/off/' + $scope.user.id)
.success(function(data, status, headers, config) {
loadSupervisors();
ngToast.success($translate.instant('supervisor_deleted'));
})
.error(function(data, status, headers, config) {
ngToast.danger($translate.instant('general_error'));
});
};
// MAIN
loadSupervisors();
});
......@@ -8,16 +8,39 @@
href="/app/#/students">
<img
class="topbar__logo__image"
ng-src="{{user.office.logoUrl}}"
alt="{{user.office.name}}"
title="{{user.office.name}}" />
src="/app/img/logo_pictogram.png"
alt="Pîctogram"
title="Pictogram" />
</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li ng-class="{active: $location.url() == '/students'}">
<a href="/app/#/students">
<i class="fa fa-users" aria-hidden="true"></i> {{ 'students' | translate }}
</a>
</li>
<li ng-if="user.isOffice" ng-class="{active: $location.url() == '/supervisor/list'}">
<a class="pointer" role="menuitem" tabindex="0" href="/app/#/supervisor/list">
<i class="fa fa-users" aria-hidden="true"></i> {{ 'supervisors' | translate }}
</a>
</li>
<li ng-if="!user.isTutor" ng-class="{active: $location.url() == '/instructions'}">
<a href="/app/#/instructions">
<i class="glyphicon glyphicon-tasks" aria-hidden="true"></i> {{ 'instructions' | translate }}
</a>
</li>
<li>
<a ng-click="own_pictos()">
<i class="glyphicon glyphicon-picture" aria-hidden="true"></i> {{ 'own_pictos' | translate }}
</a>
</li>
</ul>
<div class="topbar__supervisor nav navbar-nav navbar-right">
<div class="dropdown">
<div class="topbar__supervisor__name">
<div class="topbar__supervisor__name__fullname">{{user.getFullName()}}</div>
<div class="topbar__supervisor__name__office">{{user.office.name}}</div>
<div class="topbar__supervisor__name__role ng-binding">{{ user.role | translate }}</div>
</div>
<div
class="topbar__supervisor__avatar thumbnail"
......@@ -26,18 +49,18 @@
<img id="supervisor_profile" ng-src="{{user.pic}}" alt="Supervisor" title="Supervisor" />
</div>
<ul class="dropdown-menu" role="menu">
<li>
<!-- li>
<a class="pointer" role="menuitem" tabindex="0" href="/app/#/students">
<i class="fa fa-users" aria-hidden="true"></i>
{{ 'students' | translate }}
</a>
</li>
<li ng-if="user.isSupAdmin == true">
<li ng-if="user.isOffice">
<a class="pointer" role="menuitem" tabindex="0" href="/app/#/supervisor/list">
<i class="fa fa-users" aria-hidden="true"></i>
{{ 'supervisors' | translate }}
</a>
<li ng-if="user.isTutor == false">
<li ng-if="!user.isTutor">
<a class="pointer" role="menuitem" tabindex="0" href="/app/#/instructions">
<i class="glyphicon glyphicon-tasks" aria-hidden="true"></i>
{{ 'instructions' | translate }}
......@@ -48,7 +71,7 @@
<i class="glyphicon glyphicon-picture" aria-hidden="true"></i>
{{ 'own_pictos' | translate }}
</a>
</li>
</li -->
<li>
<a class="pointer" role="menuitem" tabindex="0" href="/app/#/setup">
<i class="glyphicon glyphicon-cog" aria-hidden="true"></i>
......@@ -65,4 +88,5 @@
</div>
</div>
</div>
</div>
</nav>
<!-- InstructionsCtrl controls here, see app.js -->
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title" translate>own_instructions</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-6">
<!-- Select to add new method -->
<div class="form-group">
<!-- Botón añadir método -->
<button ng-click="add_method()" class="btn btn-success btn-sm" popover="{{ 'add' | translate }}" popover-trigger="mouseenter">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> <span translate>new_method</span>
</button>
</div>
</div>
<div class="col-sm-6 text-right" ng-if="!minimalMode">
<button class="btn btn-primary" ng-click="enable_minimal()"><i class="fa fa-eye-slash" aria-hidden="true"></i> Ver menos detalles</button>
</div>
<div class="col-sm-6 text-right" ng-if="minimalMode">
<button class="btn btn-primary" ng-click="enable_minimal()"><i class="fa fa-eye" aria-hidden="true"></i> Ver todo</button>
</div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<div class="row">
<div class="col-xs-4">
<h3 translate>own_instructions</h3>
</div>
<div class="col-xs-4 margin-top20">
<div class="form-group">
<!-- Botón añadir método -->
<button ng-click="add_method()" class="btn btn-success btn-sm" popover="{{ 'add' | translate }}" popover-trigger="mouseenter">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> <span translate>new_method</span>
</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-12 text-right" ng-if="!minimalMode">
<button class="btn btn-primary" ng-click="enable_minimal()"><i class="fa fa-eye-slash" aria-hidden="true"></i> Ver menos detalles</button>
</div>
<div class="col-sm-12 text-right" ng-if="minimalMode">
<button class="btn btn-primary" ng-click="enable_minimal()"><i class="fa fa-eye" aria-hidden="true"></i> Ver todo</button>
</div>
</div>
<!-- Method instructions -->
<div class="method" ng-repeat="m in methods">
......
<!-- SetupCtrl controls here, see app.js -->
<div>
<div class="page-header">
<h2 translate>setup</h2>
<h3 translate>setup</h3>
</div>
<div id="signin">
<div>
<!-- Logo Pictogram -->
<!-- Formulario -->
<form name="setupForm" enctype="multipart/form-data" role="form" ng-submit="setup()">
<!-- Preview -->
<img class="thumbnail preview" ng-src="{{user.pic}}" />
<!-- Fin Cambiar imagen de perfil -->
<div class="form-group">
<!-- input type="file" ng-file-select="onFileSelect($files)" accept="image/*"></input -->
<button class="btn btn-default" ngf-select ng-model="picFile" accept="image/*" ngf-change="changeImg()">
<span class="glyphicon glyphicon-folder-open"></span> {{ 'change_picture' | translate }}
</button>
</div>
<fieldset>
<legend translate>personal_data</legend>
<div class="form-group">
<input type="text" class="form-control" id="signin_name" placeholder="{{ 'name' | translate }}" required ng-model="formdata.name" />
</div>
<div class="form-group">
<input type="text" class="form-control" id="signin_surname" placeholder="{{ 'surname' | translate }}" required ng-model="formdata.surname" />
</div>
<div class="form-group">
<input type="text" class="form-control" id="signin_address" placeholder="{{ 'address' | translate }}" ng-model="formdata.address" />
</div>
<div class="row">
<div class="col-md-3 col-md-offset-1">
<!-- Preview -->
<img class="thumbnail preview" ng-src="{{user.pic}}" />
<!-- Fin Cambiar imagen de perfil -->
<div class="form-group">
<input type="text" class="form-control" id="signin_phone" placeholder="{{ 'phone' | translate }}" ng-model="formdata.phone" />
<!-- input type="file" ng-file-select="onFileSelect($files)" accept="image/*"></input -->
<button class="btn btn-default" ngf-select ng-model="picFile" accept="image/*" ngf-change="changeImg()">
<span class="glyphicon glyphicon-folder-open"></span> {{ 'change_picture' | translate }}
</button>
</div>
</fieldset>
</div>
<div class="col-md-4">
<fieldset>
<legend translate>personal_data</legend>
<div class="form-group">
<input type="text" class="form-control" id="signin_name" placeholder="{{ 'name' | translate }}" required ng-model="formdata.name" />
</div>
<div class="form-group" ng-if="!user.isOffice">
<input type="text" class="form-control" id="signin_surname" placeholder="{{ 'surname' | translate }}" required ng-model="formdata.surname" />
</div>
<div class="form-group">
<input type="text" class="form-control" id="signin_address" placeholder="{{ 'address' | translate }}" ng-model="formdata.address" />
</div>
<div class="form-group">
<input type="text" class="form-control" id="signin_phone" placeholder="{{ 'phone' | translate }}" ng-model="formdata.phone" />
</div>
</fieldset>
<fieldset>
<legend translate>email</legend>
<div class="form-group">
<input type="email" class="form-control" id="signin_email1" placeholder="{{ 'email' | translate }}" required ng-model="formdata.email" />
</div>
</fieldset>
<fieldset>
<legend translate>language</legend>
<div class="form-group">
<select class="form-control" name="signin_language" id="signin_language" ng-model="formdata.lang">
<option value="es-es">Español</option>
<option value="en-gb">English</option>
</select>
</div>
</fieldset>
<fieldset>
<legend translate>change_password</legend>
<div class="form-group">
<input style="display:none" type="password" name="fakepasswordremembered"/>
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" ng-model="formdata.password" />
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" ng-model="formdata.password_confirm" />
</div>
<fieldset>
</div>
<fieldset>
<legend translate>language</legend>
<div class="form-group">
<select class="form-control" name="signin_language" id="signin_language" ng-model="formdata.lang">
<option value="es-es">Español</option>
<option value="en-gb">English</option>
</select>
</div>
</fieldset>
<div class="col-md-4">
<p class="text-center">
<button type="submit" class="btn btn-primary" translate>save</button>
</p>
</form>
<fieldset>
<legend translate>email</legend>
<div class="form-group">
<input type="email" class="form-control" id="signin_email1" placeholder="{{ 'email' | translate }}" required ng-model="formdata.email" />
</div>
</fieldset>
<fieldset>
<legend translate>change_password</legend>
<div class="form-group">
<input style="display:none" type="password" name="fakepasswordremembered"/>
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" ng-model="formdata.password" />
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" ng-model="formdata.password_confirm" />
</div>
<fieldset>
</div>
</div>
<!-- Fin signin -->
<div class="row">
<p class="text-right">
<button type="submit" class="btn btn-primary" translate>save</button>
</p>
</div>
</form>
</div>
<!-- Fin signin -->
<!-- DIV Modal cropper para recorte de imagen -->
<div class="modal fade" id="bootstrap-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
......
<!-- StudentsCtrl controls here, see app.js -->
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading"><h3 class="panel-title" translate>students</h3>
<!-- span ng-if="user.isAdmin">({{user.office.currentStudents}}/{{user.office.maxStudents}} - <span translate="licenses_left" translate-values="{number: num_licenses_left}"></span>)</span -->
<div class="panel-body">
<!-- StudentsCtrl controls here, see app.js -->
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<div class="row">
<div class="col-xs-4">
<h3 translate>students</h3>
</div>
<div class="col-xs-4 margin-top20">
<!-- Add Student Form -->
<div ng-include="'modules/supervisor/views/students_add.html'" ng-init="hidestudentadd = true" ng-hide="hidestudentadd"></div>
<p class="text-left" ng-hide="slide.show">
<a ng-click="showForm()" class="btn btn-success btn-sm" role="button">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> {{ 'add_student' | translate }}
</a>
</p>
<!-- Add Student button and Search row -->
<div class="row">
<div class="col-xs-3">
<p class="text-left" ng-hide="!user.isSupAdmin || !hidestudentadd">
<a ng-click="resetForm(); hidestudentadd = false" class="btn btn-success btn-sm" role="button">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> {{ 'add_student' | translate }}
</a>
</p>
</div>
<div class="col-xs-6 input-group">
<p class="text-left" ng-show="slide.show">
<a ng-click="hideForm()" class="btn btn-danger btn-sm" role="button">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> {{ 'close' | translate }}
</a>
</p>
</div>
<div class="col-xs-4 margin-top20">
<div class=" input-group">
<input type="text" ng-model="search_students" id="search_students" placeholder="{{ 'filter' | translate }}" class="form-control" aria-describedby="basic-addon2">
<span class="input-group-addon"><span class="glyphicon glyphicon-search" id="basic-addon2" aria-hidden="true"></span></span>
</div>
<div class="col-xs-3">
</div>
</div>
</div>
<!-- Fin .panel-body -->
</div>
<!-- Add Student Form -->
<div ng-include="'modules/supervisor/views/students_add.html'" hidden="true" id="addform"></div>
</div>
<!-- Fin .panel-body -->
<!-- Table -->
<div ng-show="students.length == 0">
{{ no_students_for_user | translate }}
</div>
<div class="table-responsive">
<table id="table_students" class="table table-hover">
<tr ng-repeat="student in students | filter:search_students | orderBy: ['surname', 'name']">
<td>
......@@ -39,8 +45,10 @@
</div>
</td>
<td>
<i ng-show="!student.licenseIsValid" class="fa fa-exclamation-circle fa-lg text-danger license-warning" aria-hidden="true" popover="{{ 'license_missing' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="student.licenseIsValid" class="fa fa-certificate fa-lg text-primary license-warning" aria-hidden="true" popover="{{ 'license_pro' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="student.license.isValid && !student.license.isTrial" class="fa fa-certificate fa-lg text-primary license-warning" aria-hidden="true" popover="{{ 'license_pro' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="student.license.isTrial && student.license.isValid" class="fa fa-flask fa-lg text-warning license-warning" aria-hidden="true" popover="{{ 'trial_license' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="!student.license.isValid && student.license.isOfficial" class="fa fa-certificate fa-lg text-danger license-warning" aria-hidden="true" popover="{{ 'license_missing_official' | translate}}" popover-trigger="mouseenter"></i>
<i ng-show="!student.license.isValid && student.license.isTrial" class="fa fa-flask fa-lg text-danger license-warning" aria-hidden="true" popover="{{ 'license_missing_trial' | translate}}" popover-trigger="mouseenter"></i>
</td>
<td>
<h4>{{student.surname}}, {{student.name}}</h4>
......@@ -50,32 +58,69 @@
</td>
<td> <!-- BUTTONS -->
<a class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/collections" alt="{{ 'collections' | translate}}" popover="{{ 'collections' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision != 0"><span class="glyphicon glyphicon-th" aria-hidden="true"></span></a>
<span class="btn btn-default btn-lg" role="button" alt="{{ 'collections' | translate}}" popover="{{ 'collections' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision == 0"><span class="glyphicon glyphicon-th" style="color: #bbb" aria-hidden="true"></span></span>
<a class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/instructions" alt="{{ 'instructions' | translate}}" popover="{{ 'instructions' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision == 2"><span class="glyphicon glyphicon-tasks" aria-hidden="true"></span></a>
<span class="btn btn-default btn-lg" role="button" alt="{{ 'instructions' | translate}}" popover="{{ 'instructions' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision != 2"><span class="glyphicon glyphicon-tasks" aria-hidden="true" style="color: #bbb" ></span></span>
<a class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/session" alt="{{ 'session' | translate}}" popover="{{ 'session' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision == 2"><span class="glyphicon glyphicon-transfer" aria-hidden="true"></span></a>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/collections"
alt="{{ 'collections' | translate }}" popover="{{ 'collections' | translate }}" popover-trigger="mouseenter" ng-if="student.license.isValid || student.license.isOfficial">
<span class="glyphicon glyphicon-th" aria-hidden="true"></span>
</a>
<span
class="btn btn-default btn-lg" role="button"
alt="{{ 'collections' | translate }}" popover="{{ 'collections' | translate }}" popover-trigger="mouseenter" ng-if="!student.license.isValid && student.license.isTrial">
<span class="glyphicon glyphicon-th" aria-hidden="true" style="color: #bbb" ></span>
</span>
<span class="btn btn-default btn-lg" role="button" alt="{{ 'session' | translate}}" popover="{{ 'session' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision != 2"><span class="glyphicon glyphicon-transfer" aria-hidden="true" style="color: #bbb"></span></span>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/instructions"
alt="{{ 'instructions' | translate }}" popover="{{ 'instructions' | translate }}" popover-trigger="mouseenter" ng-if="!user.isTutor && student.license.isValid">
<span class="glyphicon glyphicon-tasks" aria-hidden="true"></span>
</a>
<span
class="btn btn-default btn-lg" role="button"
alt="{{ 'instructions' | translate }}" popover="{{ 'instructions' | translate }}" popover-trigger="mouseenter" ng-if="user.isTutor || !student.license.isValid">
<span class="glyphicon glyphicon-tasks" aria-hidden="true" style="color: #bbb" ></span>
</span>
<a class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/reports" alt="{{ 'reports' | translate}}" popover="{{ 'reports' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision != 1"><i class="fa fa-bar-chart" aria-hidden="true"></i></a>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/session"
alt="{{ 'session' | translate }}" popover="{{ 'session' | translate }}" popover-trigger="mouseenter" ng-if="!user.isTutor && student.license.isValid">
<span class="glyphicon glyphicon-transfer" aria-hidden="true"></span>
</a>
<span
class="btn btn-default btn-lg" role="button"
alt="{{ 'session' | translate }}" popover="{{ 'session' | translate }}" popover-trigger="mouseenter" ng-if="user.isTutor || !student.license.isValid">
<span class="glyphicon glyphicon-transfer" aria-hidden="true" style="color: #bbb"></span>
</span>
<span class="btn btn-default btn-lg" role="button" alt="{{ 'reports' | translate}}" popover="{{ 'reports' | translate}}" popover-trigger="mouseenter" ng-if="student.supervision == 1"><i class="fa fa-bar-chart" aria-hidden="true" style="color: #bbb"></i></span>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/reports"
alt="{{ 'reports' | translate }}" popover="{{ 'reports' | translate }}" popover-trigger="mouseenter" ng-if="!user.isTutor && student.license.isValid">
<i class="fa fa-bar-chart" aria-hidden="true"></i>
</a>
<span class="btn btn-default btn-lg" role="button"
alt="{{ 'reports' | translate }}" popover="{{ 'reports' | translate }}" popover-trigger="mouseenter" ng-if="user.isTutor || !student.license.isValid">
<i class="fa fa-bar-chart" aria-hidden="true" style="color: #bbb"></i>
</span>
<a class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/setup" alt="{{ 'setup' | translate}}" popover="{{ 'setup' | translate}}" popover-trigger="mouseenter"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span></a>
<a
class="btn btn-default btn-lg" role="button" href="/app/#/student/{{student.id}}/setup"
alt="{{ 'setup' | translate }}" popover="{{ 'setup' | translate}}" popover-trigger="mouseenter">
<span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
</a>
</td> <!-- /BUTTONS -->
<td>
<a ng-if="user.isSupAdmin" ng-click="delete_student(student)" class="delete_stu" title="{{ 'delete' | translate}}">
<a ng-click="unlink_student(student)" class="delete_stu" title="{{ 'unlink' | translate}}">
<span class="glyphicon glyphicon-remove-circle text-danger" aria-hidden="true"></span>
</a>
</td>
</tr>
</table>
<div class="alert alert-warning" ng-if="students.length == 0">
<strong translate>no_students</strong>. {{ 'no_students_desc' | translate }}.
</div>
</div>
<!-- Fin de row -->
<h3 class="color_green" translate>add_student</h3>
<form name="AddStudentForm" role="form" ng-submit="add_student()" ng-controller="StudentAddCtrl">
<div class="row">
<div class="col-sm-6">
<fieldset>
<legend translate>account</legend>
<div class="form-group">
<input type="username" class="form-control" id="setup_username" placeholder="{{ 'username' | translate }}" required ng-model="formdatastudent.username" />
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" ng-model="formdatastudent.password" required />
<div class="switch-panel-body height400" ng-switch="slide.state">
<!--
SLIDE 1: Account type selection
-->
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="accounts">
<div class="row">
<div class="col-md-4">
<legend translate>add_existing</legend>
<div class="text-center">
<a ng-click="slide.rightTo('existing')">
<img src="img/child-existing.png" alt="{{'parents_tutor' | translate}}" title="{{'parents_tutor' | translate}}"
ng-class="{'img-120': hover_existing}"
ng-mouseenter="hover_existing = true"
ng-mouseleave="hover_existing = false"/>
</a>
</div>
</div>
<div class="col-md-4">
<legend translate>add_new_official</legend>
<div class="text-center">
<a ng-click="slide.rightTo('new')">
<img src="img/child-new.png" alt="{{'therapist' | translate}}" title="{{'therapist' | translate}}"
ng-class="{'img-120': hover_new}"
ng-mouseenter="hover_new = true"
ng-mouseleave="hover_new = false"/>
</a>
</div>
</div>
<div class="col-md-4">
<legend translate>new_test_account</legend>
<div class="text-center">
<a ng-click="slide.rightTo('test')">
<img src="img/child-test.png" alt="{{'office_center' | translate}}" title="{{'office_center' | translate}}"
ng-class="{'img-120': hover_test}"
ng-mouseenter="hover_test = true"
ng-mouseleave="hover_test = false"/>
</a>
</div>
</div>
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" ng-model="formdatastudent.password_confirm" required />
<div class="row">
<div class="col-md-4">
<p translate>add_existing_desc</p>
</div>
<div class="col-md-4">
<p translate>add_new_official_desc</p>
</div>
<div class="col-md-4">
<p translate>new_test_account_desc</p>
</div>
</div>
</div>
<div class="form-group">
{{ 'language' | translate }}: <select class="form-control" name="student_language" id="student_language" ng-model="formdatastudent.lang">
<option value="es-es" selected>Español</option>
<option value="en-us">English</option>
</select>
<!--
SLIDE 2: Associate existing account
-->
<form name="forms.existing" role="form" ng-submit="addExisting()" novalidate>
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="existing">
<legend translate>add_existing</legend>
<div class="row">
<div class="col-md-4 col-md-offset-2 text-center">
<img src="img/child-existing.png" alt="{{'parents_tutor' | translate}}" title="{{'parents_tutor' | translate}}" />
</div>
<div class="form-group col-md-4">
<label translate>license_number</label>
<input class="form-control" type="text" id="student_license" mask="wwww-wwww-wwww-wwww" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formdata.license_number" required>
</div>
</div>
<div class="row form-group">
<div class="col-md-4 col-md-offset-2 ">
<button class="btn btn-default" ng-click="slide.leftTo('accounts')">&lt;&lt; {{ 'back' | translate }} </button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-primary float-right" ng-disabled="forms.existing.$invalid">{{ 'link' | translate }} &gt;&gt; </button>
</div>
</div>
</div>
<div class="form-group">
<input class="form-control" type="text" id="student_license" mask="wwww-wwww-wwww-wwww" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formdatastudent.license_number" required>
</form>
<!--
SLIDE 3: New official account
-->
<form name="forms.new" role="form" ng-submit="addNew('new')" novalidate>
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="new">
<legend translate>add_new_official</legend>
<div class="row">
<div class="col-md-4 col-md-offset-2 text-center">
<img src="img/child-new.png" alt="{{'therapist' | translate}}" title="{{'therapist' | translate}}" />
</div>
<div class="form-group col-md-4">
<div class="form-group">
<label translate>username</label>
<input type="username" class="form-control" id="setup_username" placeholder="{{ 'username_default' | translate }}" required ng-model="formdata.username" />
</div>
<div class="form-group">
<label translate>password</label>
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" name="password" ng-model="formdata.password" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.new.password.$dirty && forms.new.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" ng-model="formdata.password_confirm" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.new.password.$dirty && forms.new.password_confirm.$dirty" translate>password_match</span>
</div>
<div class="form-group">
<label translate>license_number</label>
<input class="form-control" type="text" id="student_license" mask="wwww-wwww-wwww-wwww" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formdata.license_number" required>
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-4 col-md-offset-2 ">
<button class="btn btn-default" ng-click="slide.leftTo('accounts')">&lt;&lt; {{ 'back' | translate }} </button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-primary float-right" ng-disabled="forms.new.$invalid">{{ 'create_account' | translate }} &gt;&gt; </button>
</div>
</div>
</div>
</form>
<!--
SLIDE 5: Office account form
-->
<form name="forms.test" role="form" ng-submit="addNew('test')" novalidate>
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="test">
<legend translate>new_test_account</legend>
<div class="row">
<div class="col-md-4 col-md-offset-2 text-center">
<img src="img/child-test.png" alt="{{'office_center' | translate}}" title="{{'office_center' | translate}}" />
</div>
<div class="form-group col-md-4" id="office_form">
<div class="form-group">
<label translate>username</label>
<input type="username" class="form-control" id="setup_username" placeholder="{{ 'username_default' | translate }}" required ng-model="formdata.username" />
</div>
<div class="form-group">
<label translate>password</label>
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" name="password" ng-model="formdata.password" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.test.password.$dirty && forms.test.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" ng-model="formdata.password_confirm" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.test.password.$dirty && forms.test.password_confirm.$dirty" translate>password_match</span>
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-4 col-md-offset-2 ">
<button class="btn btn-default" ng-click="slide.leftTo('accounts')">&lt;&lt; {{ 'back' | translate }} </button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-primary float-right" ng-disabled="forms.test.$invalid">{{ 'create_account' | translate }} &gt;&gt; </button>
</div>
</div>
</div>
</div>
<div class="col-sm-6">
<legend translate>personal_data</legend>
<div class="form-group">
<input type="text" class="form-control" id="student_name" placeholder="{{ 'name' | translate }}" required ng-model="formdatastudent.name" />
</div>
<div class="form-group">
<input type="text" class="form-control" id="student_surname" placeholder="{{ 'surname' | translate }}" required ng-model="formdatastudent.surname" />
</div>
</form>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<p class="input-group">
<input type="text" class="form-control" datepicker-popup="{{ 'day_format' | translate }}" ng-model="formdatastudent.birthdate" placeholder="{{ 'birthdate' | translate }}" is-open="opened_cal_student" close-text="{{'close' | translate}}" required />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open_calendar($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<select class="form-control" name="student_gender" id="student_gender" ng-model="formdatastudent.gender" required>
<option value="F" selected translate>woman</option>
<option value="M" translate>man</option>
</select>
</div>
</div>
<!--
SLIDE 6: Confirmation message
-->
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="confirmation">
</div>
<h2>{{ 'account_available' | translate }} </h2>
<p translate>student_account_confirm</p>
<br>
<img src="img/child.png"/>
<div class="form-group">
<span translate>country</span>:
<select class="form-control" name="student_country" id="student_country" ng-model="formdatastudent.country" required>
<option value="ES" selected>España</option>
<option value="US">United States</option>
<option value="UK">United Kingdom</option>
<option value="IE">Ireland</option>
</select>
</div>
</div>
</div>
<!-- Fin de row -->
<div class="form-group text-center">
<button type="button" class="btn btn-default" ng-click="resetForm()">{{'cancel'|translate}}</button>
<button type="submit" class="btn btn-primary" translate>add</button>
</div>
</form>
</div>
<hr />
......@@ -4,37 +4,60 @@
<div class="panel-heading">
<div class="row">
<div class="col-xs-4">
<h5 translate>supervisors</h5>
<h3 translate>supervisors</h3>
</div>
<div class="col-xs-4">
<div class="col-xs-4 margin-top20">
<div class=" input-group">
<input type="text" ng-model="inputs.email" placeholder="{{ 'email' | translate }}" class="form-control">
<span class="input-group-btn" popover="{{ 'link_supervisor_desc' | translate }}" popover-trigger="mouseenter">
<button ng-click="searchSup()" class="btn btn-success btn-sm" role="button">
{{ 'link_supervisor' | translate }}
</button>
</span>
</div>
<!-- Alert and success messages for supervisor found -->
<div ng-show="{{ 'showmessagesupfound' }}" class="alert alert-info overlap-result">
<!-- Imagen de perfil del tutor -->
<img ng-src="{{supToAdd.pic}}" class="profile" alt="" title="" /> {{ supToAdd.name }} {{ supToAdd.surname }}
<a class="btn btn-default btn-sm pull-right" role="button" ng-click="confirmLink()" translate>add</a>
</div>
</div>
<div class="col-xs-4">
<div class="col-xs-4 margin-top20">
<div class=" input-group">
<input type="text" ng-model="search_sups" id="search_sups" placeholder="{{ 'filter' | translate }}" class="form-control" aria-describedby="basic-addon2">
<input type="text" ng-model="inputs.search_str" id="search_sups" placeholder="{{ 'filter' | translate }}" class="form-control" aria-describedby="basic-addon2">
<span class="input-group-addon"><span class="glyphicon glyphicon-search" id="basic-addon2" aria-hidden="true"></span></span>
</div>
</div>
</div>
</div>
</div>
<!-- Fin .panel-body -->
<div class="table-responsive">
<table class="table">
<table class="table" id="table_supervisors">
<thead class="thead-default">
<tr>
<th translate>supervisors</th>
<th translate>students</th>
<th class="col-xs-8" translate>supervisors</th>
<th class="col-xs-4" translate>students</th>
</tr>
</thead>
<tbody>
<tr class="active" ng-repeat="supervisor in supervisors_list | filter:search_sups | orderBy: 'name'">
<tr class="active" ng-repeat="supervisor in supervisors_list | filter:inputs.search_str | orderBy: 'name'">
<td>
<div>
<div class="row">
<div class="col-xs-2">
<div class="thumbnail">
<img ng-src="/upload/supervisorAvatar/{{supervisor.pic}}" alt="Supervisor" title="Supervisor" />
<img ng-src="{{supervisor.pic}}" alt="Supervisor" title="Supervisor" />
</div>
</div>
<div class="col-xs-10">
<div class="col-xs-1">
<a ng-click="unlinkSupervisor(supervisor.id)" class="delete_sup" title="{{ 'unlink' | translate }}">
<span class="glyphicon glyphicon-remove-circle text-danger" aria-hidden="true"></span>
</a>
</div>
<div class="col-xs-9">
<h4>{{supervisor.name}} {{supervisor.surname}}</h4>
<p><i class="fa fa-envelope" aria-hidden="true">&nbsp</i><a href="mailto:{{supervisor.email}}">{{supervisor.email}}</a></p>
<p><i class="fa fa-phone-square" aria-hidden="true"></i>&nbsp<a href="tel:{{supervisor.phone}}">{{supervisor.phone}}</a></p>
......@@ -52,6 +75,9 @@
</tr>
</tbody>
</table>
<div class="alert alert-warning" ng-if="supervisors_list.length == 0">
<strong translate>no_supervisors</strong> {{ 'no_supervisors_desc' | translate }}
</div>
</div>
</div>
......@@ -8,6 +8,7 @@ dashboardControllers.controller('TranslateController', function(
$scope,
$window,
$http,
$timeout,
config,
ngToast,
vcRecaptchaService
......@@ -44,7 +45,7 @@ dashboardControllers.controller('TranslateController', function(
//Server PUT
$http.put(config.backend + '/sup/' + $scope.user.id, { "lang": langKey })
.success(function (data) {
ngToast.success({ content: $translate.instant('data_saved') });
ngToast.success({ content: $translate.instant('language_change_warning') });
console.log("OK: Update supervisor language");
})
.error(function () {
......@@ -63,7 +64,5 @@ dashboardControllers.controller('TranslateController', function(
vcRecaptchaService.useLang(0, langKey.substr(0,2));
} catch (err) {}
// Reload page
$window.location.reload();
};
});
......@@ -58,10 +58,18 @@
margin-top: 15px;
}
.margin-top20 {
margin-top: 20px;
}
.margin-top7 {
margin-top: 7px;
}
.margin-top10 {
margin-top: 10px;
}
.table .table-striped .striped {
background-color: lightgray !important;
}
......@@ -870,7 +878,8 @@ img.profile{
#user_tutors .list-group-item:hover .delete_tutor,
#user_sups .list-group-item:hover .delete_sup,
#table_students tr:hover .delete_stu{
#table_supervisors tr:hover .delete_sup,
#table_students tr:hover .delete_stu {
opacity: 1;
}
......@@ -1098,3 +1107,82 @@ input.editable.scene-name {
font-size: 16px;
font-weight: 600;
}
.float-right {
float: right;
}
.float-left {
float: left;
}
/* Cambiar tamaño imagen */
.img-200 {
margin-top: 25px;
width: 200px;
}
.img-120 {
margin-top: 25px;
width: 120px;
}
/* Estilos para ngSwitch */
.switch-panel-body {
position:relative;
width: 930px;
margin: auto;
overflow:hidden;
}
.height600 {
height: 600px;
}
.height400 {
height: 400px;
}
.switch-animation,
.switch-animation-back {
width: 900px;
}
.switch-animation.ng-enter,
.switch-animation.ng-leave,
.switch-animation-back.ng-enter,
.switch-animation-back.ng-leave {
-webkit-transition:0.5s linear all;
-moz-transition:0.5s linear all;
-o-transition:0.5s linear all;
transition: 0.5s linear all;
position:absolute;
}
.switch-animation.ng-enter,
.switch-animation-back.ng-leave.ng-leave-active {
left:100%;
}
.switch-animation.ng-leave,
.switch-animation.ng-enter.ng-enter-active,
.switch-animation-back.ng-leave,
.switch-animation-back.ng-enter.ng-enter-active {
left:0;
}
.switch-animation.ng-leave.ng-leave-active,
.switch-animation-back.ng-enter {
left:-100%;
}
.switch-panel {
overflow:hidden;
}
.overlap-result {
z-index:20;
position:absolute;
width:100%
}
......@@ -29,11 +29,13 @@
padding: 0.5em;
&__fullname,
&__office {
&__office,
&__role {
text-align: right;
}
&__office {
&__office,
&__role {
opacity: 0.75;
}
}
......
......@@ -8,5 +8,6 @@
"therapist_office_request": "{{ name }}, with email {{ email }}, is requesting to be linked as therapist to any of your students.",
"tutor_office_request": "{{ name }}, with email {{ email }}, is requesting to be linked as tutor/father/mother to any of your students.",
"welcome_msg1": "Welcome to Pictogram, {{ name }}!",
"welcome_msg2": "Your account is now active. You can proceed to"
"welcome_msg2": "Your account is now active. You can proceed to",
"office_link": "The office/center \"{{ name }}\" with email \"{{ email }}\" has added you as part of its team in Pictogram."
}
......@@ -8,5 +8,6 @@
"therapist_office_request": "El/la terapeuta {{ name }}, con correo electrónico {{ email }}, pide ser asociado a algún estudiante.",
"tutor_office_request": "El/la tutor/a/padre/madre {{ name }}, con correo electrónico {{ email }}, pide ser asociado a algún estudiante.",
"welcome_msg1": "¡Bienvenido a Pictogram, {{ name }}!",
"welcome_msg2": "Su cuenta está ahora activa, por lo que puede"
"welcome_msg2": "Su cuenta está ahora activa, por lo que puede",
"office_link": "El centro/gabinete \"{{ name }}\", con correo electrónico \"{{ email }}\" le ha añadido como parte de su equipo."
}
......@@ -21,7 +21,7 @@ module.exports.pictogram = {
],
serialSize: 10, // number of characters in generated serial numbers
pageLimit: 10, // number of elements per "page"
trial_license_duration: 3, // number of moths the trial license is valid
password_minlength: 8, // minimal size for the password string
urls: {
......@@ -54,11 +54,11 @@ module.exports.pictogram = {
*/
getSupervisorCustomPictoUrl: function (filename) {
return `/upload/supervisorCustomPicto/${filename}`;
},
},
/**
* Gets the public url of a sound for a given picto
* @param {String} filename filename of sound
* @return {String} Public url of the picto sound
* @return {String} Public url of the picto sound
*/
getSoundUrl: function (filename) {
return `/upload/pictoSound/${filename}`;
......@@ -72,7 +72,7 @@ module.exports.pictogram = {
supervisorAvatarDirectory: path.join(UPLOAD_PATH, 'supervisorAvatar'),
studentAvatarDirectory: path.join(UPLOAD_PATH, 'studentAvatar'),
supervisorCustomPictoDirectory: path.join(UPLOAD_PATH, 'supervisorCustomPicto'),
pictoSoundDirectory: path.join(UPLOAD_PATH, 'pictoSound'),
pictoSoundDirectory: path.join(UPLOAD_PATH, 'pictoSound'),
/**
* Get a random name used for uploaded file names
* @param {string} randomString String used for generating the name
......
......@@ -21,6 +21,8 @@ module.exports.policies = {
'*': false,
// TODO: habría que revisar estas políticas, porque creo que hay bastantes brechas abiertas
ActionController: {
create: ['tokenAuth'],
createlist: ['tokenAuth']
......@@ -44,11 +46,11 @@ module.exports.policies = {
},
MetaMethodController: {
supVisible: ['tokenAuth'],
supOwned: ['tokenAuth'],
create: ['tokenAuth'],
update: ['tokenAuth'],
destroy: ['tokenAuth']
supVisible: ['tokenAuth'],
supOwned: ['tokenAuth'],
create: ['tokenAuth'],
update: ['tokenAuth'],
destroy: ['tokenAuth']
},
MethodController: {
......@@ -59,13 +61,6 @@ module.exports.policies = {
destroy: ['tokenAuth'],
},
OfficeController: {
getAll: true,
get: ['tokenAuth'],
getBasic: true,
supervisors: ['tokenAuth', 'isAdminOrIsSupAdmin']
},
PictoController: {
upload: ['tokenAuth'],
add_tag: ['tokenAuth'],
......@@ -81,13 +76,13 @@ module.exports.policies = {
},
SceneController:{
create: ['tokenAuth', 'isSupervisorOfStudent'],
update: ['tokenAuth', 'isSupervisorOfStudent'],
destroy: ['tokenAuth', 'isSupervisorOfStudent'],
duplicate: ['tokenAuth', 'isSupervisorOfStudent'],
getScene: ['tokenAuth'],
getStudentScenes: ['tokenAuth'],
scene: true
create: ['tokenAuth', 'isSupervisorOfStudent'],
update: ['tokenAuth', 'isSupervisorOfStudent'],
destroy: ['tokenAuth', 'isSupervisorOfStudent'],
duplicate: ['tokenAuth', 'isSupervisorOfStudent'],
getScene: ['tokenAuth'],
getStudentScenes: ['tokenAuth'],
scene: true
},
ServerController: {
......@@ -97,11 +92,11 @@ module.exports.policies = {
StudentController: {
eternal: true,
getInfo: ['tokenAuth', 'isSupervisorOfStudentOrIsSupAdminOrIsStudent'],
getInfo: ['tokenAuth', 'isStudentOrSupervisorOfStudent'],
supervisors: ['tokenAuth'],
therapists: ['tokenAuth'],
tutors: ['tokenAuth'],
link_supervisor: ['tokenAuth', 'isSupAdmin'],
link_supervisor: ['tokenAuth'],
pictos: ['tokenAuth'],
methods: ['tokenAuth'],
lasttries: ['tokenAuth'],
......@@ -113,7 +108,7 @@ module.exports.policies = {
update_legend: ['tokenAuth'],
update_category: ['tokenAuth', 'isSupervisorOfStudent'],
login: true,
create: ['tokenAuth', 'isSupAdmin'],
create: ['tokenAuth'],
upload: ['tokenAuth'],
upload_sound: ['tokenAuth'],
add_picto: ['tokenAuth', 'isSupervisorOfStudent'],
......@@ -123,8 +118,8 @@ module.exports.policies = {
action: true,
config: true,
actions_batch: ['tokenAuth'],
delete: ['tokenAuth', 'isSupAdmin'],
unlink_supervisor: ['tokenAuth', 'isSupAdmin'],
delete: ['tokenAuth', 'isAdmin'],
unlink_supervisor: ['tokenAuth', 'isSupervisorOfStudent'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent'],
getActiveScene: ['tokenAuth'],
getScenes: ['tokenAuth'],
......@@ -143,7 +138,8 @@ module.exports.policies = {
list: ['tokenAuth', 'isAdmin'],
students: ['tokenAuth'],
pictos: ['tokenAuth'],
getByEmail: ['tokenAuth'],
getByEmail: ['tokenAuth', 'isOffice'],
getFromOfficeByEmail: ['tokenAuth', 'isOffice'],
update: ['tokenAuth'],
create: true,
login: true,
......@@ -154,7 +150,10 @@ module.exports.policies = {
upload: ['tokenAuth'],
subscribe: ['tokenAuth'],
unsubscribe: ['tokenAuth'],
delete: ['tokenAuth', 'isAdmin']
delete: ['tokenAuth', 'isAdmin'],
supervisors: ['tokenAuth', 'isOffice'],
link_supervisor: ['tokenAuth', 'isOffice'],
unlink_supervisor: ['tokenAuth', 'isOffice']
},
TryController: {
......
......@@ -55,11 +55,6 @@ module.exports.routes = {
'PUT /method/template/:id': 'MetaMethodController.update',
'DELETE /method/template/:id': 'MetaMethodController.destroy',
'GET /office/get_all': 'OfficeController.getAll',
'GET /office/:code': 'OfficeController.getBasic',
'GET /office/get/:id': 'OfficeController.get',
'GET /office/get/:id/supervisors': 'OfficeController.supervisors',
'GET /picto/:lang/pic_categories/:id_cat': 'PictoController.categories',
'GET /picto/:lang/pic_fromcategory/:id_cat': 'PictoController.fromcategory',
'GET /picto/:lang/pic_fromSymbolStx/page/:page/limit/:limit': 'PictoController.fromSymbolStx',
......@@ -87,8 +82,7 @@ module.exports.routes = {
'GET /stu/:id_stu': 'StudentController.getInfo',
'GET /stu/:id_stu/supervisors': 'StudentController.supervisors',
'GET /stu/:id_stu/therapists': 'StudentController.therapists',
'GET /stu/:id_stu/tutors': 'StudentController.tutors',
'POST /stu/license/sup/:id_sup': "StudentController.link_supervisor",
'POST /stu/:id_stu/sup/:id_sup': 'StudentController.link_supervisor',
'GET /stu/:id_stu/pictos': 'StudentController.pictos',
'GET /stu/:id_stu/activeScene': 'StudentController.getActiveScene',
......@@ -104,7 +98,7 @@ module.exports.routes = {
'PUT /stu/:id_stu/legend/:legend_value': 'StudentController.update_legend',
'PUT /stu/:id_stu/picto': 'StudentController.update_picto',
'PUT /stu/:id_stu/cat': 'StudentController.update_category',
'PUT /stu/:id_stu/activeScene/:id_scene': 'StudentController.updateActiveScene',
'PUT /stu/:id_stu/activeScene/:id_scene': 'StudentController.updateActiveScene',
'POST /stu/login': 'StudentController.login',
'POST /stu': 'StudentController.create',
'POST /stu/upload': 'StudentController.upload',
......@@ -125,9 +119,13 @@ module.exports.routes = {
'GET /sup/all': 'SupervisorController.list',
'GET /sup/:id/students': 'SupervisorController.students',
'GET /sup/:id/supervisors': 'SupervisorController.supervisors',
'POST /sup/:id_sup/off/:id_off': 'SupervisorController.link_supervisor',
'DELETE /sup/:id_sup/off/:id_off': 'SupervisorController.unlink_supervisor',
'GET /sup/:id/pictos': 'SupervisorController.pictos',
'GET /sup/email/:email': 'SupervisorController.getByEmail',
'GET /sup/off/email/:email': 'SupervisorController.getFromOfficeByEmail',
'GET /sup/changepass/:email': 'SupervisorController.request_change_password',
'GET /sup/arasaac_license/:id': 'SupervisorController.accept_arasaac',
'PUT /sup/changepass': 'SupervisorController.change_password',
......
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