Compare commits

..

No commits in common. "master" and "page-home" have entirely different histories.

51 changed files with 10039 additions and 2486 deletions

View File

@ -26,7 +26,7 @@
if( !isset($_SESSION['CAS']) || !is_array($_SESSION['CAS']) ) $_SESSION['CAS'] = []; if( !isset($_SESSION['CAS']) || !is_array($_SESSION['CAS']) ) $_SESSION['CAS'] = [];
if( !isset($_SESSION['AUTH']) || !is_array($_SESSION['AUTH']) ) $_SESSION['AUTH'] = []; if( !isset($_SESSION['AUTH']) || !is_array($_SESSION['AUTH']) ) $_SESSION['AUTH'] = [];
if( !isset($_SESSION['AvailableDepartments']) || !is_array($_SESSION['AvailableDepartments']) ) $_SESSION['AvailableDepartments'] = []; if( !isset($_SESSION['AvailableDepartments']) || !is_array($_SESSION['AvailableDepartments']) ) $_SESSION['AvailableDepartments'] = [];
if( !isset($_SESSION['VERSION']) || !is_array($_SESSION['VERSION']) ) $_SESSION['VERSION'] = []; if( !isset($_SESSION['VERSION']) || !is_string($_SESSION['VERSION']) ) $_SESSION['VERSION'] = null;
if( !isset($_SESSION['CurrentDepartmentId']) || !is_int($_SESSION['CurrentDepartmentId']) ) $_SESSION['CurrentDepartmentId'] = null; if( !isset($_SESSION['CurrentDepartmentId']) || !is_int($_SESSION['CurrentDepartmentId']) ) $_SESSION['CurrentDepartmentId'] = null;

View File

@ -100,7 +100,7 @@ class casController{
/* (2) Check ticket (validate) /* (2) Check ticket (validate)
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Build useful variables */ /* (1) Build useful variables */
$service = ($_SERVER['SERVER_PORT'] == 80) ? 'http' : 'https'; $service = ($_SERVER['SERVER_NAME'] == 'ptut.com' ) ? 'http' : 'https';
$service .= '://'.$_SERVER['HTTP_HOST'].'/api/v/1.0/cas/'.$popup_mode; $service .= '://'.$_SERVER['HTTP_HOST'].'/api/v/1.0/cas/'.$popup_mode;
$ticket = urlencode($_GET['ticket']); $ticket = urlencode($_GET['ticket']);
$validate_url = "https://sso.univ-pau.fr/cas/serviceValidate?ticket=$ticket&service=$service"; $validate_url = "https://sso.univ-pau.fr/cas/serviceValidate?ticket=$ticket&service=$service";
@ -146,33 +146,14 @@ class casController{
$_SESSION['AvailableDepartments'] = $departments; $_SESSION['AvailableDepartments'] = $departments;
/* (4) Choose first department by default */ /* (4) Choose first department by default */
$_SESSION['CurrentDatabase'] = $departments[0]['dbName'];
$_SESSION['CurrentDepartmentId'] = $departments[0]['idDep']; $_SESSION['CurrentDepartmentId'] = $departments[0]['idDep'];
$_SESSION['VERSION'] = [
'list' => $departments[0]['versions'],
'current' => null
];
/* (5) select version with default = 1 */ /* (5) Use this department's database */
foreach($_SESSION['VERSION']['list'] as $v){
if( $v['default'] == 1 ){
$_SESSION['VERSION']['current'] = intval($v['iddatabase']);
$_SESSION['CurrentDatabase'] = $v['dbName'];
break;
}
}
/* (6) if no default -> select first */
if( !is_int($_SESSION['VERSION']) ){
$_SESSION['VERSION']['current'] = intval($_SESSION['VERSION']['list'][0]['iddatabase']);
$_SESSION['CurrentDatabase'] = $_SESSION['VERSION']['list'][0]['dbName'];
}
/* (7) Use this department's database */
Repo::switchDatabase($_SESSION['CurrentDatabase']); Repo::switchDatabase($_SESSION['CurrentDatabase']);
/* (4) Fetch @cas_login professor data /* (4) Fetch @cas_login professor data
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Try to fetch professor */ /* (1) Try to fetch professor */

View File

@ -1,182 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: lucas
* Date: 10/05/18
* Time: 13:03
*/
namespace api\module\department;
use database\core\Repo;
use database\repo\cours;
use database\repo\formation;
use database\repo\td;
use database\repo\tp;
use database\repo\ue;
use PhpOffice\PhpSpreadsheet\Reader\Xls\Style\Border;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Borders;
class exportController
{
public function get($args){
/** @var ue $ueRepo */
$ueRepo = Repo::getRepo("ue");
/** @var cours $cmRepo */
$cmRepo = Repo::getRepo("cours");
/** @var td $tdRepo */
$tdRepo = Repo::getRepo("td");
/** @var tp $tpRepo */
$tpRepo = Repo::getRepo("tp");
/** @var formation $formationRepo */
$formationRepo = Repo::getRepo("formation");
$ues = $ueRepo->exportUE();
$formations = [];
//cache formations labels
foreach ($formationRepo->get(null) as $form){
$formations[$form["idForm"]] = $form["labelForm"];
}
$formatFormations = function(String $formationsId) use ($formations) : String{
$returned = "";
foreach (json_decode($formationsId,true) as $form){
$returned .= $formations[$form]."+";
}
return rtrim($returned,"+");
};
$spreadsheet = new Spreadsheet();
$excel = $spreadsheet->getActiveSheet();
//set up base document
$arrayHeaders = ["Code","Intitulé","Statut","V.H.","Cours","NbGr","Enseignant","TD","NbGr","Enseignant","TP","NbGr","Enseignant","Equ. TD","Total"];
$excel->setCellValue("B2","CODIFICATION DES UE");
$i = 1;
foreach ($arrayHeaders as $header){
$excel->setCellValueByColumnAndRow($i,4,$header);
$i++;
}
$excel->freezePane("O5");
//set up state variables
$currentFormation = null;
$currentLine = 5;
foreach ($ues as $ue){
if($currentFormation != $ue["labelFormation"]){
$currentFormation = $ue["labelFormation"];
$excel->setCellValue("A$currentLine",$ue["labelFormation"]);
$excel->getStyle("A$currentLine")->getFont()->setBold(true)->setSize(11);
$excel->getStyle("A$currentLine:O$currentLine")->getBorders()->getTop()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_DOUBLE);
$currentLine += 2;
}
//get all groups data
$cm = $cmRepo->getGroups($ue["code"]);
$td = $tdRepo->getGroups($ue["code"]);
$tp = $tpRepo->getGroups($ue["code"]);
//set UE header
$nbrGroupeCM = count($cm);
$nbrGroupeTD = count($td);
$nbrGroupeTP = count($tp);
$volumeUE = $ue["volumeCours"] + $ue["volumeTD"] + $ue["volumeTP"];
$equiTDUE = $nbrGroupeCM*1.5*$ue["volumeCours"] + $nbrGroupeTD*$ue["volumeTD"] + $nbrGroupeTP*$ue["volumeTP"];
$excel->setCellValue("A$currentLine",$ue["code"]);
$excel->setCellValue("B$currentLine",$ue["label"]);
$excel->setCellValue("C$currentLine",$ue["required"] == 1? "OBL" : "OPT");
$excel->setCellValue("D$currentLine","$volumeUE");
$excel->setCellValue("E$currentLine","{$ue["volumeCours"]}");
$excel->setCellValue("F$currentLine","$nbrGroupeCM");
$excel->setCellValue("H$currentLine","{$ue["volumeTD"]}");
$excel->setCellValue("I$currentLine","$nbrGroupeTD");
$excel->setCellValue("K$currentLine","{$ue["volumeTP"]}");
$excel->setCellValue("L$currentLine","$nbrGroupeTP");
$excel->setCellValue("O$currentLine","$equiTDUE");
$excel->getStyle("A$currentLine:O$currentLine")->getFont()->setBold( true )->setSize(9);
$currentLine++;
$nbrLine = max($nbrGroupeCM,$nbrGroupeTD,$nbrGroupeTP)-1;
foreach (range(0,$nbrLine) as $n){
$excel->setCellValue("A$currentLine",$ue["code"]);
$excel->setCellValue("B$currentLine",$ue["label"]);
$equiTD = 0;
if(isset($cm[$n])){
$excel->setCellValue("E$currentLine","{$cm[$n]["volume"]}");
$excel->setCellValue("F$currentLine",$formatFormations($cm[$n]["formations"]));
$excel->setCellValue("G$currentLine",$cm[$n]["lastName"]." ".$cm[$n]["firstName"]);
$equiTD += 1.5*$cm[$n]["volume"];
}
if(isset($td[$n])){
$excel->setCellValue("H$currentLine","{$td[$n]["volume"]}");
$excel->setCellValue("I$currentLine",$formatFormations($td[$n]["formations"]));
$excel->setCellValue("J$currentLine",$td[$n]["lastName"]." ".$td[$n]["firstName"]);
$equiTD += $td[$n]["volume"];
}
if(isset($tp[$n])){
$excel->setCellValue("K$currentLine","{$tp[$n]["volume"]}");
$excel->setCellValue("L$currentLine",$formatFormations($tp[$n]["formations"]));
$excel->setCellValue("M$currentLine",$tp[$n]["lastName"]." ".$tp[$n]["firstName"]);
$equiTD += $tp[$n]["volume"];
}
$excel->setCellValue("N$currentLine","$equiTD");
$excel->getStyle("A$currentLine:O$currentLine")->getFont()->setSize(8);
$currentLine++;
}
$currentLine++;
}
//resize all columns
foreach(range('A','O') as $columnID) {
$excel->getColumnDimension($columnID)->setAutoSize(true);
}
//set content type headers
// header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//reating writer
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xls($spreadsheet);
//as phpSpreadSheet do not support output on the buffer, we have to write in a temp file then read it
//create temporary file;
$file = tmpfile();
//get URI
$metaDatas = stream_get_meta_data($file);
$tmpFilename = $metaDatas['uri'];
//close file pointer
fclose($file);
//write data
$writer->save("$tmpFilename");
//get file content
return [
'headers' => [
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'Content-Disposition' => 'attachment; filename=archive.xls'
],
'body' => file_get_contents($tmpFilename)
];
}
}

View File

@ -1,28 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: lucas
* Date: 07/05/18
* Time: 17:59
*/
namespace api\module\department\version;
use database\core\Repo;
class switchController
{
public function get($args){
$version = null;
extract($args);
$versionData = Repo::getRepo("meta")->getVersionById($version);
$_SESSION['CurrentDatabase'] = $versionData["dbName"];
$_SESSION['VERSION']['current'] = intval( $version );
return ["success" => true];
}
}

View File

@ -10,7 +10,6 @@ namespace api\module\department;
use database\core\Repo; use database\core\Repo;
use database\repo\meta;
use error\core\Error; use error\core\Error;
use error\core\Err; use error\core\Err;
use database\repo\department; use database\repo\department;
@ -19,6 +18,95 @@ use Ifsnop\Mysqldump\Mysqldump;
class versionController{ class versionController{
/* Attributes
---------------------------------------------------------*/
private $backup_path;
private $origin_dbname;
/* (1) Initialize object
*
---------------------------------------------------------*/
public function __construct(){
$this->backup_path = null;
$this->origin_dbname = null;
}
/* (2) Initializes a directory
*
* @db_name<String> The database name
*
* @return outName<outType> outDesc
*
--------------------------------------------------------*/
private function initDir(string $db_name){
/* (1) Manage 'BACKUP' root directory
---------------------------------------------------------*/
/* (1) If not exists -> try to create it */
if( !is_dir(__BACKUP__) )
mkdir(__BACKUP__);
/* (2) Try to override permissions */
chmod(__BACKUP__, 0775);
/* (2) Manage sub-directory
---------------------------------------------------------*/
/* (1) If @db_name is 'preview_@database_hash' -> extract @database */
if( preg_match('/^preview_(\w+)_[a-f0-9]+$/', $db_name, $m) )
$db_name = $m[1];
/* (2) Store @db_name as origin */
$this->origin_dbname = $db_name;
/* (3) Store backup path */
$this->backup_path =__BACKUP__."/$db_name";
/* (4) If dir. already exists -> do nothing more */
if( is_dir($this->backup_path) )
return;
/* (4) Else -> try to create + set permissions */
mkdir($this->backup_path);
chmod($this->backup_path, 0775);
}
/* (3) Scan directory files
*
* @path<String> Directory path
*
* @return files<array> Array containing file names
*
---------------------------------------------------------*/
private function scandir(string $path) : array {
/* (1) Return [] if not a directory */
if( !is_dir($path) )
return [];
/* (2) Scan the directory */
$files = scandir($path);
/* (3) Remove '.' and '..' (2 first elements) */
$files = array_slice($files, 2);
/* (4) Return file list */
return $files;
}
/* (4) List available versions for this department /* (4) List available versions for this department
* *
* @return versions<array> Version list * @return versions<array> Version list
@ -26,12 +114,17 @@ class versionController{
---------------------------------------------------------*/ ---------------------------------------------------------*/
public function get($args){ public function get($args){
//search for the current department in the session and return its versions /* (1) Initialize directory for current database (department) */
/** @var meta $depRepo */ $this->initDir( $_SESSION['CurrentDatabase'] );
$depRepo = Repo::getRepo("meta");
//if no department found, return an empty array /* (2) Strip extensions */
return ['versions' => $depRepo->getAllVersions($_SESSION['CurrentDepartmentId']) ]; $versions = array_map(
function($e){ return pathinfo($e, PATHINFO_FILENAME); },
$this->scandir($this->backup_path)
);
/* (3) Return versions */
return ['versions' => $versions ];
} }
@ -39,7 +132,7 @@ class versionController{
/* (5) Remove an existing version for this department /* (5) Remove an existing version for this department
* *
* @version<int> Version name (typically snapshot date) * @version<String> Version name (typically snapshot date)
* *
* @return deleted<bool> Whether the version has been deleted * @return deleted<bool> Whether the version has been deleted
* *
@ -48,35 +141,11 @@ class versionController{
$version = null; $version = null;
extract($args); extract($args);
/* (1) Try to delete */ /* (1) Initialize directory for current database (department) */
$deleted = Repo::getRepo("meta")->deleteVersion($version); $this->initDir( $_SESSION['CurrentDatabase'] );
if( !$deleted )
return ['error' => new Error(Err::ModuleError)];
/* (2) Update version list */
$_SESSION['VERSION']['list'] = Repo::getRepo("meta")->getAllVersions($_SESSION['CurrentDepartmentId']);
/* (3) Update current */
$_SESSION['VERSION']['current'] = null;
// select version with default = 1
foreach($_SESSION['VERSION']['list'] as $v){
if( $v['default'] == 1 ){
$_SESSION['VERSION']['current'] = intval($v['iddatabase']);
$_SESSION['CurrentDatabase'] = $v['dbName'];
break;
}
}
// if no default -> select first
if( !is_int($_SESSION['VERSION']) ){
$_SESSION['VERSION']['current'] = intval($_SESSION['VERSION']['list'][0]['iddatabase']);
$_SESSION['CurrentDatabase'] = $_SESSION['VERSION']['list'][0]['dbName'];
}
return ['deleted' => true];
/* (2) Dispatch 'unlink' result */
return [ 'deleted' => unlink($this->backup_path."/$version.sql") ];
} }
@ -87,8 +156,10 @@ class versionController{
* *
---------------------------------------------------------*/ ---------------------------------------------------------*/
public function post($args){ public function post($args){
$label = null;
extract($args);
/* (1) Initialize directory for current database (department) */
$this->initDir( $_SESSION['CurrentDatabase'] );
/* (2) Try to create the snapshot */ /* (2) Try to create the snapshot */
try{ try{
@ -97,33 +168,21 @@ class versionController{
$conf = Repo::getDBConfig(); $conf = Repo::getDBConfig();
/* (2.2) Try to dump the database */ /* (2.2) Try to dump the database */
/** @var Mysqldump*/
$dump = new Mysqldump( $dump = new Mysqldump(
'mysql:host='.$conf['host'].';dbname='.$_SESSION['CurrentDatabase'], 'mysql:host='.$conf['host'].';dbname='.$conf['dbname'],
$conf['username'], $conf['username'],
$conf['password'] $conf['password'],
[ "compress" => Mysqldump::GZIP ]
); );
//create temporary file; /* (2.3) Get current date (for naming the version) */
$file = tmpfile(); $current_date = date('d-m-Y');
//get URI
$metaDatas = stream_get_meta_data($file);
$tmpFilename = $metaDatas['uri'];
//close file pointer
fclose($file);
//fill the file with sql dump
$dump->start($tmpFilename);
/** @var department $depRepo */ /* (2.4) Store the version */
$depRepo = Repo::getRepo("department"); $dump->start($this->backup_path."/$current_date.sql");
$dbName = $depRepo->createVersionDatabase($_SESSION['CurrentDepartmentId'],file_get_contents($tmpFilename));
/** @var meta $metaRep */
$metaRep = Repo::getRepo("meta");
$versionId = $metaRep->createVersion($label, $dbName,$_SESSION['CurrentDepartmentId'] ,false);
/* (2.5) Return status */ /* (2.5) Return status */
return ['created_id' => $versionId ]; return ['created_id' => $current_date ];
/* (3) On error -> dispatch error */ /* (3) On error -> dispatch error */
}catch(\Exception $e){ }catch(\Exception $e){
@ -135,24 +194,106 @@ class versionController{
} }
/* (6) Modify a version and use it /* (6) ( Switches to preview || Applies on prod ) for a version
* *
* @apply<int> If 0 -> preview version
* If 1 -> apply version into prod database
* @version<String> [OPT] Version name to use (if ommited, switch back to prod database)
* *
* @return bool success * @return created_id<String> The created version id (date)
* *
---------------------------------------------------------*/ ---------------------------------------------------------*/
public function put($args){ public function put($args){
$label = null; $apply = null;
$version = null; $version = null;
$default = null;
extract($args); extract($args);
/** @var meta $metaRepo */
$metaRepo = Repo::getRepo("meta"); /* (1) Initialisation
---------------------------------------------------------*/
/* (1) Initialize directory for current database (department) */
$this->initDir( $_SESSION['CurrentDatabase'] );
/* (2) Get department repository */
/** @var department $dept_repo */
$dept_repo = Repo::getRepo('department');
/* (3) Check whether we have to [apply OR preview] */
$apply = ( $apply === '1' );
/* (2) If back to 'prod' database
---------------------------------------------------------*/
if( is_null($version) ){
/* (1) Reset database to 'prod' */
$_SESSION['CurrentDatabase'] = $this->origin_dbname;
$_SESSION['VERSION'] = null;
/* (2) Return success */
return [ 'updated' => true ];
}
/* (3) Read the backup version
---------------------------------------------------------*/
/* (1) Start buffer */
ob_start();
/* (2) Read backup file */
readgzfile($this->backup_path."/$version.sql");
/* (3) Store & Flush buffer into variable */
$snapshot = ob_get_clean();
/* (4) Manage error */
if( strlen($snapshot) === 0 )
return ['error' => new Error(Err::RepoError)];
/* (4) APPLY into 'prod' database
---------------------------------------------------------*/
if( $apply ){
/* (1) Restore from this version */
$restored = $dept_repo->restore($this->origin_dbname, $snapshot);
$_SESSION['VERSION'] = null;
/* (2) Dispatch repo execution status */
return [ 'updated' => $restored ];
}
/* (5) PREVIEW version database
---------------------------------------------------------*/
/* (1) Try to get 'preview' database name */
$preview_dbname = $dept_repo->previewExists($this->origin_dbname, $version);
/* (2) If does not exist -> create it */
if( is_null($preview_dbname) ){
/* 1. Try to create preview */
$preview_dbname = $dept_repo->createPreview($this->origin_dbname, $version);
/* 2. Switch to preview */
$dept_repo->restore($preview_dbname, $snapshot);
}
/* (3) Store 'preview' database in session */
$_SESSION['CurrentDatabase'] = $preview_dbname;
$_SESSION['VERSION'] = $version;
/* (4) Return status */ /* (4) Return status */
return [ 'updated' => $metaRepo->updateVersion($version,$label,$default) ]; return [ 'updated' => true ];
} }
} }

View File

@ -10,10 +10,7 @@ namespace api\module;
use database\core\Repo; use database\core\Repo;
use database\repo\database;
use database\repo\department;
use database\repo\meta; use database\repo\meta;
use database\repo\professor;
class departmentController class departmentController
{ {
@ -78,29 +75,11 @@ class departmentController
foreach($deps as $dep){ foreach($deps as $dep){
if( $dep['idDep'] == $department ){ if( $dep['idDep'] == $department){
$_SESSION['AvailableDepartments'] = $deps; $_SESSION['AvailableDepartments'] = $deps;
$_SESSION['CurrentDatabase'] = $dep['dbName'];
$_SESSION['CurrentDepartmentId'] = $dep['idDep']; $_SESSION['CurrentDepartmentId'] = $dep['idDep'];
$_SESSION['VERSION'] = [
'list' => $dep['versions'],
'current' => null
];
// select version with default = 1
foreach($_SESSION['VERSION']['list'] as $v){
if( $v['default'] == 1 ){
$_SESSION['VERSION']['current'] = intval($v['iddatabase']);
$_SESSION['CurrentDatabase'] = $v['dbName'];
break;
}
}
// if no default -> select first
if( !is_int($_SESSION['VERSION']) ){
$_SESSION['VERSION']['current'] = intval($_SESSION['VERSION']['list'][0]['iddatabase']);
$_SESSION['CurrentDatabase'] = $_SESSION['VERSION']['list'][0]['dbName'];
}
return ['switched' => true]; return ['switched' => true];
@ -113,52 +92,4 @@ class departmentController
} }
public function post($args){
$name = null;
extract($args);
/** @var meta $metaRepo */
$metaRepo = Repo::getRepo("meta");
/** @var professor $profRep */
$profRep = Repo::getRepo("professor");
/** @var database $dbRepo */
$dbRepo = Repo::getRepo("database");
//create the department in the meta database
$depId = $metaRepo->createDepartment($name);
//link the current user to that department
$metaRepo->link($_SESSION['CAS']['login'],$depId);
//create the database and init the structure
$dbName = $dbRepo->init($depId);
//link the new database to the department
$metaRepo->createVersion("Version 1",$dbName,$depId,true);
//get the current user data from current department
$user = $profRep->get($_SESSION['CAS']['id'])[0];
//switch our connexion to that database
Repo::switchDatabase($dbName);
//create the default admin in the new database (categories are common to all department)
$profRep->create($user["lastName"],
$user["firstName"],
$user["Categorie_idCategorie"],
$user["hoursToDo"],
$user["abreviation"],
true,
$user["casLogin"]);
//update user session
$departments = $metaRepo->get_prof_departments($user["casLogin"]);
$_SESSION['AvailableDepartments'] = $departments;
//we are good now
return [];
}
} }

View File

@ -14,7 +14,7 @@ use database\core\Repo;
class formationController class formationController
{ {
public function get($args){ public static function get($args){
$form_id = null; $form_id = null;
extract($args); extract($args);
@ -24,37 +24,4 @@ class formationController
return ['formations' => $repo->get($form_id)]; return ['formations' => $repo->get($form_id)];
} }
public function post($args){
$label = null;
$isInternal = null;
extract($args);
/** @var \database\repo\formation $repo */
$repo = Repo::getRepo("formation");
return ['idFormation' => $repo->create($label,$isInternal)];
}
public function put($args){
$idFormation = null;
$label = null;
$isInternal = null;
extract($args);
/** @var \database\repo\formation $repo */
$repo = Repo::getRepo("formation");
return ['success' => $repo->update($idFormation,$label,$isInternal)];
}
public function delete($args){
$idFormation = null;
extract($args);
/** @var \database\repo\formation $repo */
$repo = Repo::getRepo("formation");
return ['success' => $repo->delete($idFormation)];
}
} }

View File

@ -22,17 +22,9 @@ class pdfController{
* @return download<File> The PDF fiche * @return download<File> The PDF fiche
---------------------------------------------------------*/ ---------------------------------------------------------*/
public static function get($args){ public static function get($args){
$prof_id = -1; $prof_id = -1;
extract($args); extract($args);
if(!$_SESSION["CAS"]["admin"] && $_SESSION["CAS"]["id"] != $prof_id){
return [
'headers' => ["Content-Type" => "text/html"],
'body' => "Unauthorized access"
];
}
/* (0) Initialize /* (0) Initialize
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Initialize data structure */ /* (1) Initialize data structure */
@ -132,7 +124,7 @@ class pdfController{
$fetched = $form_repo->get(null); $fetched = $form_repo->get(null);
/* (2) Error: no formation found */ /* (2) Error: no formation found */
if( !is_array($fetched) ) if( count($fetched) < 1 )
return ['error' => new Error(Err::RepoError)]; return ['error' => new Error(Err::RepoError)];
/* (3) Reference formations by key = idForm */ /* (3) Reference formations by key = idForm */
@ -285,6 +277,10 @@ class pdfController{
Il est à noter qu\'elle contient les données générées au '.$date.'. Elle peut ne plus être à jour. Il est à noter qu\'elle contient les données générées au '.$date.'. Elle peut ne plus être à jour.
</blockquote> </blockquote>
<p>
Si un problème persiste veuillez contacter les responsables à l\'addresse mail suivante <span style="color: red;">&lt;mail_display_error&gt;</span>.
</p>
<br><br><br> <br><br><br>
@ -313,12 +309,12 @@ class pdfController{
</tr> </tr>
<tr> <tr>
<td class="ar">Sous service</td> <td class="ar">Heures manquantes</td>
<td>'.( $missing_h>0 ? "$svg_warning $missing_h" : $missing_h).' h</td> <td>'.( $missing_h>0 ? "$svg_warning $missing_h" : $missing_h).' h</td>
</tr> </tr>
<tr> <tr>
<td class="ar">Sur service</td> <td class="ar">Heures sup.</td>
<td>'.$sup_h.' h</td> <td>'.$sup_h.' h</td>
</tr> </tr>
</tbody> </tbody>
@ -348,6 +344,10 @@ class pdfController{
Il est à noter qu\'elle contient les données générées au '.$date.'. Elle peut ne plus être à jour. Il est à noter qu\'elle contient les données générées au '.$date.'. Elle peut ne plus être à jour.
</blockquote> </blockquote>
<p>
Si un problème persiste veuillez contacter les responsables à l\'addresse mail suivante <span style="color: red;">&lt;mail_display_error&gt;</span>.
</p>
<br><br><br> <br><br><br>
<table> <table>

View File

@ -25,31 +25,10 @@ class coursController{
$formations = []; $formations = [];
extract($args); extract($args);
/* Get the repos */ /* Get the cours repo */
/** @var cours $cours_repo */ /** @var cours $cours_repo */
$cours_repo = Repo::getRepo('cours'); $cours_repo = Repo::getRepo('cours');
/** @var ue $ue_repo */
$ue_repo = Repo::getRepo('ue');
/* (1) Fetch default formation from UE
---------------------------------------------------------*/
/* (1) Try to fetch the cours' UE */
$fetched_ue = $ue_repo->get($code);
/* (2) Manage error */
if( !is_array($fetched_ue) || count($fetched_ue) < 1 )
return ['error' => new Error(Err::RepoError)];
$defaultForm = intval($fetched_ue[0]['idForm']);
/* (3) Add to formation list if got a valid default formation */
if( is_int($defaultForm) && $defaultForm >= 0 && !in_array($defaultForm, $formations) )
$formations[] = $defaultForm;
/* (2) Create the cours
---------------------------------------------------------*/
/* (1) Try to create cours */ /* (1) Try to create cours */
$created_id = $cours_repo->create($code, $idProf, $volume, $formations); $created_id = $cours_repo->create($code, $idProf, $volume, $formations);
@ -57,7 +36,7 @@ class coursController{
if( is_null($created_id) || !is_int($created_id) ) if( is_null($created_id) || !is_int($created_id) )
return ['error' => new Error(Err::RepoError)]; return ['error' => new Error(Err::RepoError)];
return ['created_id' => $created_id, 'formations' => $formations]; return ['created_id' => $created_id];
} }

View File

@ -25,31 +25,10 @@ class tdController{
$formations = []; $formations = [];
extract($args); extract($args);
/* Get the repos */ /* Get the td repo */
/** @var td $td_repo */ /** @var td $td_repo */
$td_repo = Repo::getRepo('td'); $td_repo = Repo::getRepo('td');
/** @var ue $ue_repo */
$ue_repo = Repo::getRepo('ue');
/* (1) Fetch default formation from UE
---------------------------------------------------------*/
/* (1) Try to fetch the TD' UE */
$fetched_ue = $ue_repo->get($code);
/* (2) Manage error */
if( !is_array($fetched_ue) || count($fetched_ue) < 1 )
return ['error' => new Error(Err::RepoError)];
$defaultForm = intval($fetched_ue[0]['idForm']);
/* (3) Add to formation list if got a valid default formation */
if( is_int($defaultForm) && $defaultForm >= 0 && !in_array($defaultForm, $formations) )
$formations[] = $defaultForm;
/* (2) Create the TD
---------------------------------------------------------*/
/* (1) Try to create td */ /* (1) Try to create td */
$created_id = $td_repo->create($code, $idProf, $volume, $formations); $created_id = $td_repo->create($code, $idProf, $volume, $formations);
@ -57,7 +36,7 @@ class tdController{
if( is_null($created_id) || !is_int($created_id) ) if( is_null($created_id) || !is_int($created_id) )
return ['error' => new Error(Err::RepoError)]; return ['error' => new Error(Err::RepoError)];
return ['created_id' => $created_id, 'formations' => $formations]; return ['created_id' => $created_id];
} }

View File

@ -25,31 +25,10 @@ class tpController{
$formations = []; $formations = [];
extract($args); extract($args);
/* Get the repos */ /* Get the tp repo */
/** @var tp $tp_repo */ /** @var tp $tp_repo */
$tp_repo = Repo::getRepo('tp'); $tp_repo = Repo::getRepo('tp');
/** @var ue $ue_repo */
$ue_repo = Repo::getRepo('ue');
/* (1) Fetch default formation from UE
---------------------------------------------------------*/
/* (1) Try to fetch the TP' UE */
$fetched_ue = $ue_repo->get($code);
/* (2) Manage error */
if( !is_array($fetched_ue) || count($fetched_ue) < 1 )
return ['error' => new Error(Err::RepoError)];
$defaultForm = intval($fetched_ue[0]['idForm']);
/* (3) Add to formation list if got a valid default formation */
if( is_int($defaultForm) && $defaultForm >= 0 && !in_array($defaultForm, $formations) )
$formations[] = $defaultForm;
/* (2) Create the TP
---------------------------------------------------------*/
/* (1) Try to create tp */ /* (1) Try to create tp */
$created_id = $tp_repo->create($code, $idProf, $volume, $formations); $created_id = $tp_repo->create($code, $idProf, $volume, $formations);
@ -57,7 +36,7 @@ class tpController{
if( is_null($created_id) || !is_int($created_id) ) if( is_null($created_id) || !is_int($created_id) )
return ['error' => new Error(Err::RepoError)]; return ['error' => new Error(Err::RepoError)];
return ['created_id' => $created_id, 'formations' => $formations]; return ['created_id' => $created_id];
} }

View File

@ -49,11 +49,7 @@ class PDOWrapper extends \PDO
if($this->stacking){ if($this->stacking){
return new PDOStatementWrapper($statement, $this); return new PDOStatementWrapper($statement, $this);
}else{ }else{
$st = parent::prepare($statement, $options); return parent::prepare($statement, $options);
if($st === false){
throw new \PDOException("There is an error in your SQL statement");
}
return $st;
} }
} }
@ -158,19 +154,23 @@ class PDOWrapper extends \PDO
//find the given pattern in the request, then call our function and replace the matched string by the return value of our function //find the given pattern in the request, then call our function and replace the matched string by the return value of our function
$finalStatement .= rtrim(preg_replace_callback("/(:[a-z_\-0-9]*)/is",function($matches) use (&$i,&$tempParametes){ $finalStatement .= rtrim(preg_replace_callback("/(:[a-z_\-0-9]*)/is",function($matches) use (&$i,&$tempParametes){
//get next number
$i++;
//delete the ':' at the beginning of the string
$tempKey = ltrim($matches[0],':');
//copy the parameter with the modified index //copy the parameter with the modified index
$tempParametes[":$i"] = $tempParametes[$matches[0]]; $tempParametes[$tempKey.$i] = $tempParametes[$tempKey];
//delete the old index //delete the old index
unset($tempParametes[$matches[0]]); unset($tempParametes[$tempKey]);
//return the modified string for replacement //return the modified string for replacement
return ":".$i++; return $matches[0].$i;
},$statement),';').';'; },$statement),';').';';
$finalExecute += $tempParametes; $finalExecute = array_merge($finalExecute,$tempParametes);
} }
//disable stacking //disable stacking
@ -184,7 +184,6 @@ class PDOWrapper extends \PDO
$req = $this->prepare($finalStatement); $req = $this->prepare($finalStatement);
$success = $req->execute($finalExecute); $success = $req->execute($finalExecute);
//as we execute multiple query that we don't fetch, we have to close the cursor if we want to do other requests later //as we execute multiple query that we don't fetch, we have to close the cursor if we want to do other requests later
$req->closeCursor(); $req->closeCursor();
$this->commit(); $this->commit();

View File

@ -78,7 +78,7 @@
} }
public static function switchDatabase(string $dbName){ public static function switchDatabase(string $dbName){
return static::$driver->pdo()->exec("USE $dbName;SET autocommit=1;"); return static::$driver->pdo()->prepare("USE $dbName")->execute();
} }
public static function getDBConfig() : array{ public static function getDBConfig() : array{

View File

@ -1,266 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: lucas
* Date: 09/05/18
* Time: 16:55
*/
namespace database\repo;
use database\core\Repo;
use database\core\Repo_i;
class database extends Repo_i {
/**
* @param int $depId
* @return String the name of the department database
* @throws \Exception
*/
public function init(int $depId) : String{
/** @var department $metaRep */
$metaRep = Repo::getRepo("department");
$SQL = "
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- -----------------------------------------------------
-- Table `Categorie`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `Categorie` (
`idCategorie` INT(11) NOT NULL,
`labelCategorie` VARCHAR(100) NOT NULL,
PRIMARY KEY (`idCategorie`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `Professeur`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `Professeur` (
`idProfesseur` INT(11) NOT NULL AUTO_INCREMENT,
`casLogin` VARCHAR(50) NULL DEFAULT NULL,
`lastName` VARCHAR(50) NULL DEFAULT NULL,
`firstName` VARCHAR(50) NULL DEFAULT NULL,
`abreviation` VARCHAR(10) NULL DEFAULT NULL COMMENT 'Abreviation used in the excel document',
`admin` TINYINT(4) NOT NULL DEFAULT 0,
`hoursToDo` INT(11) NOT NULL DEFAULT 0,
`Categorie_idCategorie` INT(11) NOT NULL,
PRIMARY KEY (`idProfesseur`),
INDEX `fk_Professeur_Categorie1_idx` (`Categorie_idCategorie` ASC),
CONSTRAINT `fk_Professeur_Categorie1`
FOREIGN KEY (`Categorie_idCategorie`)
REFERENCES `Categorie` (`idCategorie`)
ON DELETE NO ACTION
ON UPDATE CASCADE)
ENGINE = InnoDB
AUTO_INCREMENT = 34
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `Formation`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `Formation` (
`idFormation` INT(11) NOT NULL AUTO_INCREMENT,
`labelFormation` VARCHAR(50) NULL DEFAULT NULL,
`isInternal` TINYINT(4) NULL DEFAULT 1,
PRIMARY KEY (`idFormation`))
ENGINE = InnoDB
AUTO_INCREMENT = 20
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `UE`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `UE` (
`code` VARCHAR(20) NOT NULL,
`label` VARCHAR(100) NOT NULL,
`required` TINYINT(4) NOT NULL DEFAULT 1,
`volumeCours` FLOAT NOT NULL DEFAULT 0,
`volumeTP` FLOAT NOT NULL DEFAULT 0,
`volumeTD` FLOAT NOT NULL,
`disabled` TINYINT(4) NOT NULL DEFAULT 0,
`Formation_idFormation` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`code`),
INDEX `fk_UE_Formation1_idx` (`Formation_idFormation` ASC),
CONSTRAINT `fk_UE_Formation1`
FOREIGN KEY (`Formation_idFormation`)
REFERENCES `Formation` (`idFormation`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1
COMMENT = 'Table contenant le code et le label des UE';
-- -----------------------------------------------------
-- Table `Cours`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `Cours` (
`idCours` INT(11) NOT NULL AUTO_INCREMENT,
`UE_code` VARCHAR(20) NOT NULL,
`Professeur_idProfesseur` INT(11) NULL DEFAULT NULL,
`volume` FLOAT NOT NULL DEFAULT 0,
PRIMARY KEY (`idCours`),
INDEX `fk_Cours_UE_idx` (`UE_code` ASC),
INDEX `fk_Cours_Professeur1_idx` (`Professeur_idProfesseur` ASC),
CONSTRAINT `fk_Cours_Professeur1`
FOREIGN KEY (`Professeur_idProfesseur`)
REFERENCES `Professeur` (`idProfesseur`)
ON DELETE SET NULL
ON UPDATE SET NULL,
CONSTRAINT `fk_Cours_UE`
FOREIGN KEY (`UE_code`)
REFERENCES `UE` (`code`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
AUTO_INCREMENT = 88
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `GroupeCours`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `GroupeCours` (
`Formation_idFormation` INT(11) NOT NULL,
`Cours_idCours` INT(11) NOT NULL,
PRIMARY KEY (`Formation_idFormation`, `Cours_idCours`),
INDEX `fk_Formation_has_Cours_Cours1_idx` (`Cours_idCours` ASC),
INDEX `fk_Formation_has_Cours_Formation1_idx` (`Formation_idFormation` ASC),
CONSTRAINT `fk_Formation_has_Cours_Cours1`
FOREIGN KEY (`Cours_idCours`)
REFERENCES `Cours` (`idCours`)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_Formation_has_Cours_Formation1`
FOREIGN KEY (`Formation_idFormation`)
REFERENCES `Formation` (`idFormation`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `TD`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `TD` (
`idTD` INT(11) NOT NULL AUTO_INCREMENT,
`UE_code` VARCHAR(20) NOT NULL,
`Professeur_idProfesseur` INT(11) NULL DEFAULT NULL,
`volume` FLOAT NOT NULL DEFAULT 0,
PRIMARY KEY (`idTD`),
INDEX `fk_TD_UE1_idx` (`UE_code` ASC),
INDEX `fk_TD_Professeur1_idx` (`Professeur_idProfesseur` ASC),
CONSTRAINT `fk_TD_Professeur1`
FOREIGN KEY (`Professeur_idProfesseur`)
REFERENCES `Professeur` (`idProfesseur`)
ON DELETE SET NULL
ON UPDATE SET NULL,
CONSTRAINT `fk_TD_UE1`
FOREIGN KEY (`UE_code`)
REFERENCES `UE` (`code`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
AUTO_INCREMENT = 107
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `GroupeTD`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `GroupeTD` (
`Formation_idFormation` INT(11) NOT NULL,
`TD_idTD` INT(11) NOT NULL,
PRIMARY KEY (`Formation_idFormation`, `TD_idTD`),
INDEX `fk_Formation_has_TD_TD1_idx` (`TD_idTD` ASC),
INDEX `fk_Formation_has_TD_Formation1_idx` (`Formation_idFormation` ASC),
CONSTRAINT `fk_Formation_has_TD_Formation1`
FOREIGN KEY (`Formation_idFormation`)
REFERENCES `Formation` (`idFormation`)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_Formation_has_TD_TD1`
FOREIGN KEY (`TD_idTD`)
REFERENCES `TD` (`idTD`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `TP`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `TP` (
`idTP` INT(11) NOT NULL AUTO_INCREMENT,
`UE_code` VARCHAR(20) NOT NULL,
`Professeur_idProfesseur` INT(11) NULL DEFAULT NULL,
`volume` FLOAT NOT NULL DEFAULT 0,
PRIMARY KEY (`idTP`),
INDEX `fk_TP_UE1_idx` (`UE_code` ASC),
INDEX `fk_TP_Professeur1_idx` (`Professeur_idProfesseur` ASC),
CONSTRAINT `fk_TP_Professeur1`
FOREIGN KEY (`Professeur_idProfesseur`)
REFERENCES `Professeur` (`idProfesseur`)
ON DELETE SET NULL
ON UPDATE SET NULL,
CONSTRAINT `fk_TP_UE1`
FOREIGN KEY (`UE_code`)
REFERENCES `UE` (`code`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
AUTO_INCREMENT = 164
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `GroupeTP`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `GroupeTP` (
`Formation_idFormation` INT(11) NOT NULL,
`TP_idTP` INT(11) NOT NULL,
PRIMARY KEY (`Formation_idFormation`, `TP_idTP`),
INDEX `fk_Formation_has_TP_TP1_idx` (`TP_idTP` ASC),
INDEX `fk_Formation_has_TP_Formation1_idx` (`Formation_idFormation` ASC),
CONSTRAINT `fk_Formation_has_TP_Formation1`
FOREIGN KEY (`Formation_idFormation`)
REFERENCES `Formation` (`idFormation`)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_Formation_has_TP_TP1`
FOREIGN KEY (`TP_idTP`)
REFERENCES `TP` (`idTP`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
LOCK TABLES `Categorie` WRITE;
/*!40000 ALTER TABLE `Categorie` DISABLE KEYS */;
INSERT INTO `Categorie` VALUES (1,'Professeurs et Maîtres de Conférences'),(2,'ATERs'),(3,'CDDs enseignement'),(4,'Doctorants Vacataires'),(5,'Permanents UPPA'),(6,'Vacataires extérieurs');
/*!40000 ALTER TABLE `Categorie` ENABLE KEYS */;
UNLOCK TABLES;
";
return $metaRep->createVersionDatabase($depId,$SQL);
}
}

View File

@ -167,13 +167,36 @@ class department extends Repo_i
} }
public function createVersionDatabase(String $depId, String $SQL) : String{ public function restore(string $dbName, string $SQL) : bool{
$dbName = uniqid($depId)."";
$this->pdo->exec("CREATE DATABASE $dbName; USE $dbName;".$SQL."USE {$_SESSION["CurrentDatabase"]};SET autocommit=1;"); //get the list of command to execute
$this->pdo->setAttribute(\PDO::ATTR_AUTOCOMMIT,1); $this->pdo->exec("DROP DATABASE $dbName;");
$this->pdo->exec("CREATE DATABASE $dbName;");
$this->pdo->exec("USE $dbName;");
return $dbName; return $this->pdo->exec($SQL);
}
private static function generatePreviewDBName(string $bdName, string $backupName) : string{
return "preview_{$bdName}_".sha1($bdName.$backupName);
}
public function previewExists(string $dbName, string $backupname) : ?string {
$previewDBName = static::generatePreviewDBName($dbName,$backupname);
$st = $this->pdo->prepare("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = :dbName");
$st->execute(["dbName" => $previewDBName]);
if($st->fetch() === false) return null;
else return $previewDBName;
}
public function createPreview(string $dbName, string $backupname) : string {
$previewDBName = static::generatePreviewDBName($dbName,$backupname);
$this->pdo->exec("CREATE OR REPLACE DATABASE $previewDBName");
return $previewDBName;
} }
} }

View File

@ -42,26 +42,6 @@ class formation extends Repo_i {
} }
public function update(int $idFormation, ?String $label, ?bool $isInternal) : bool{
$req = "";
$execute = [];
if($label != null){
$req .= "labelFormation=:label,";
$execute["label"] = $label;
}
if($isInternal != null){
$req .= "isInternal=:isInternal,";
$execute["isInternal"] = $isInternal?1:0;
}
$req = rtrim($req,",");
$execute["idFormation"] = $idFormation;
$st = $this->pdo->prepare("UPDATE `Formation` SET $req WHERE idFormation=:idFormation");
return $st->execute($execute);
}
/* (2) Check if a formation exists (by its label) /* (2) Check if a formation exists (by its label)

View File

@ -88,7 +88,7 @@ class meta extends Repo_i {
public function get_prof_departments(String $casLogin) : array{ public function get_prof_departments(String $casLogin) : array{
/* (1) Prepare Statement */ /* (1) Prepare Statement */
$st = $this->pdo->prepare("SELECT d2.iddepartement idDep, d2.label labelDep $st = $this->pdo->prepare("SELECT d2.iddepartement idDep, d2.label labelDep, d2.databaseName dbName
FROM meta_vhost.casUser FROM meta_vhost.casUser
JOIN meta_vhost.linkedDep D ON casUser.casLogin = D.casUser_casLogin JOIN meta_vhost.linkedDep D ON casUser.casLogin = D.casUser_casLogin
JOIN meta_vhost.departement d2 ON D.departement_iddepartement = d2.iddepartement JOIN meta_vhost.departement d2 ON D.departement_iddepartement = d2.iddepartement
@ -112,17 +112,7 @@ class meta extends Repo_i {
if( $fetched === false ) if( $fetched === false )
return []; return [];
/* (7) Add all possible databases to the department */ /* (7) Return data */
foreach ($fetched as &$dep){
$st = $this->pdo->prepare("SELECT *
FROM meta_vhost.`databases`
WHERE departement_iddepartement = :idDep
ORDER BY meta_vhost.`databases`.`default` DESC ");
$st->execute(["idDep" => $dep["idDep"]]);
$dep["versions"] = $st->fetchAll();
}
/* (8) Return data */
return $fetched; return $fetched;
} }
@ -155,6 +145,15 @@ class meta extends Repo_i {
} }
/* (5) Check if a link exists /* (5) Check if a link exists
* *
* @casLogin<String> The professor's cas login * @casLogin<String> The professor's cas login
@ -255,97 +254,4 @@ class meta extends Repo_i {
} }
public function deleteVersion(int $version) : bool{
//get version data
$st = $this->pdo->prepare("SELECT * FROM meta_vhost.`databases` WHERE iddatabase = :id");
$st->execute(["id" => $version]);
$versionData = $st->fetch();
if( !is_array($versionData) || $versionData["default"] == 1){
return false;
}
//delete database
$versionDatabase = $versionData['dbName'];
$this->pdo->exec("DROP DATABASE $versionDatabase;");
//remove from meta
$st = $this->pdo->prepare("DELETE FROM meta_vhost.`databases` WHERE iddatabase = :id");
return $st->execute(["id" => $version]);
}
public function createVersion(String $label, String $dbName, int $depId, bool $isDefault = false) : int{
$st = $this->pdo->prepare("INSERT INTO meta_vhost.`databases`(label, dbName, `default`, departement_iddepartement)
VALUE (:label,:dbName,:default,:depId)");
$st->execute([
"label" => $label,
"dbName" => $dbName,
"default" => $isDefault? 1 : 0,
"depId" => $depId
]);
return $this->pdo->lastInsertId();
}
public function getVersionById(int $id) : array{
$st = $this->pdo->prepare("SELECT * FROM meta_vhost.`databases` WHERE iddatabase = :idVersion");
$st->execute(["idVersion" => $id]);
$fetched = $st->fetch();
return $fetched == false ? [] : $fetched;
}
public function getAllVersions(int $idDep) : array {
$st = $this->pdo->prepare("SELECT * FROM meta_vhost.`databases` WHERE departement_iddepartement = :idDep");
$st->execute(["idDep" => $idDep]);
return $st->fetchAll();
}
public function updateVersion(int $version, ?String $label, ?bool $default) : bool{
//you can't un-default a version, you have to choose another version to be the default one
if($default == false){
return false;
}
$set = "";
$execute = [];
if($label != null){
$set .= "label=:label,";
$execute["label"] = $label;
}
if($default != null){
$set .= "`default`=:default,";
$execute["default"] = $default?1:0;
//if default = true, set previous default version to non-default
if($default == true){
$req = $this->pdo->prepare("UPDATE meta_vhost.`databases` SET `default`=0 WHERE departement_iddepartement=:idDep");
$req->execute(["idDep" => $_SESSION['CurrentDepartmentId']]);
}
}
$set = rtrim($set,",");
$execute["idVersion"] = $version;
$st = $this->pdo->prepare("UPDATE meta_vhost.`databases` SET $set WHERE iddatabase=:idVersion");
return $st->execute($execute);
}
public function createDepartment(String $name) : int{
$st = $this->pdo->prepare("INSERT INTO meta_vhost.departement(label) VALUE (:label)");
$st->execute(["label" => $name]);
return $this->pdo->lastInsertId();
}
} }

View File

@ -321,7 +321,7 @@ class professor extends Repo_i {
$parm = is_null($prof_id) ? [] : [':id' => $prof_id]; $parm = is_null($prof_id) ? [] : [':id' => $prof_id];
/* (2) Prepare Statement */ /* (2) Prepare Statement */
$st = $this->pdo->prepare("SELECT * FROM `Professeur`$cond ORDER BY firstName, lastName ASC"); $st = $this->pdo->prepare("SELECT * FROM `Professeur`$cond ORDER BY abreviation ASC");
/* (3) Bind params and execute statement */ /* (3) Bind params and execute statement */
if( is_bool($st) ) return []; if( is_bool($st) ) return [];
@ -433,8 +433,7 @@ class professor extends Repo_i {
AND VHTp.idProf = Prof.idProfesseur AND VHTp.idProf = Prof.idProfesseur
AND VHTd.idProf = Prof.idProfesseur AND VHTd.idProf = Prof.idProfesseur
GROUP BY GROUP BY
Prof.idProfesseur Prof.idProfesseur;");
ORDER BY Prof.firstName, Prof.lastName ASC;");
/* (3) Bind params and execute statement */ /* (3) Bind params and execute statement */
if( is_bool($st) ) return []; if( is_bool($st) ) return [];

View File

@ -180,8 +180,7 @@ class ue extends Repo_i {
$parm = is_null($code) ? [] : [':code' => $code]; $parm = is_null($code) ? [] : [':code' => $code];
/* (2) Prepare Statement */ /* (2) Prepare Statement */
$st = $this->pdo->prepare(" $st = $this->pdo->prepare("SELECT
SELECT
ue.code, ue.code,
ue.label, ue.label,
ue.disabled, ue.disabled,
@ -191,31 +190,12 @@ class ue extends Repo_i {
ue.volumeTP, ue.volumeTP,
IFNULL(ue.Formation_idFormation, -1) idForm, IFNULL(ue.Formation_idFormation, -1) idForm,
fdef.labelFormation labelForm, fdef.labelFormation labelForm,
IFNULL(formlist.formations, '[]') formations, IFNULL(formlist.formations, '[]') formations
IFNULL(formlist.nbrCours,0) nbrCours,
IFNULL(formlist.nbrTD,0) nbrTD,
IFNULL(formlist.nbrTP,0) nbrTP,
IFNULL(formlist.modCours,0) modCours,
IFNULL(formlist.modTD,0) modTD,
IFNULL(formlist.modTP,0) modTP,
IFNULL(formlist.nbrProfCours,0) nbrProfCours,
IFNULL(formlist.nbrProfTD,0) nbrProfTD,
IFNULL(formlist.nbrProfTP,0) nbrProfTP
FROM UE ue FROM UE ue
LEFT JOIN Formation fdef ON ue.Formation_idFormation = fdef.idFormation LEFT JOIN Formation fdef ON ue.Formation_idFormation = fdef.idFormation
LEFT JOIN ( LEFT JOIN (
SELECT ue2.code code, CONCAT('[',GROUP_CONCAT(DISTINCT Formation.idFormation), ']') formations, SELECT ue2.code code, CONCAT('[',GROUP_CONCAT(DISTINCT Formation.idFormation), ']') formations
count(DISTINCT C.idCours) nbrCours, count(DISTINCT T.idTD) nbrTD, count(DISTINCT T2.idTP) nbrTP,
MOD(volC.vol,ue2.volumeCours) modCours,
MOD(volTD.vol,ue2.volumeTD) modTD,
MOD(volTP.vol,ue2.volumeTP) modTP,
count(DISTINCT C.Professeur_idProfesseur,C.idCours) nbrProfCours,
count(DISTINCT T.Professeur_idProfesseur,T.idTD) nbrProfTD,
count(DISTINCT T2.Professeur_idProfesseur,T2.idTP) nbrProfTP
FROM UE ue2 FROM UE ue2
LEFT JOIN (SELECT sum(CO.volume) vol, CO.UE_code FROM Cours CO GROUP BY CO.UE_code) volC ON ue2.code = volC.UE_code
LEFT JOIN (SELECT sum(TD2.volume) vol, TD2.UE_code FROM TD TD2 GROUP BY TD2.UE_code) volTD ON ue2.code = volTD.UE_code
LEFT JOIN (SELECT sum(TP2.volume) vol, TP2.UE_code FROM TP TP2 GROUP BY TP2.UE_code) volTP ON ue2.code = volTP.UE_code
LEFT JOIN Cours C ON ue2.code = C.UE_code LEFT JOIN Cours C ON ue2.code = C.UE_code
LEFT JOIN TD T ON ue2.code = T.UE_code LEFT JOIN TD T ON ue2.code = T.UE_code
LEFT JOIN TP T2 ON ue2.code = T2.UE_code LEFT JOIN TP T2 ON ue2.code = T2.UE_code
@ -290,13 +270,4 @@ class ue extends Repo_i {
return $fetched; return $fetched;
} }
public function exportUE() : array{
$st = $this->pdo->prepare("SELECT * FROM UE
LEFT JOIN Formation
ON UE.Formation_idFormation = Formation.idFormation
ORDER BY Formation_idFormation IS NULL DESC, Formation_idFormation ASC");
$st->execute();
return $st->fetchAll();
}
} }

View File

@ -33,43 +33,19 @@
} }
/* (2) Only teacher */
if( !in_array('cas_admin', $_SESSION['AUTH']) ){
// redirection
if( $this->pagename != "fiche" ){
header('Location: /fiche/');
die();
}
// deconnection
if( $this->uri == 'logout' || $this->uri == 'logout/' ){
\session_destroy();
header('Location: /');
die();
}
// load page
include __PUBLIC__."/page/fiche.php";
die();
}
/* (1) Build page file name */
/* (3) Build page file name */
$page_fname = __PUBLIC__."/page/".$this->pagename.".php"; $page_fname = __PUBLIC__."/page/".$this->pagename.".php";
/* (4) If page does not exist -> 404 */ /* (2) If page does not exist -> 404 */
if( !file_exists($page_fname) ) if( !file_exists($page_fname) )
include __PUBLIC__.'/page/404.php'; include __PUBLIC__.'/page/404.php';
/* (5) Set URI arguments */ /* (3) Set URI arguments */
$_GET['uri'] = explode('/', $this->uri); $_GET['uri'] = explode('/', $this->uri);
/* (6) Load page */ /* (4) Load page */
include __PUBLIC__."/page/".$this->pagename.".php"; include __PUBLIC__."/page/".$this->pagename.".php";
} }

View File

@ -29,7 +29,6 @@
"phpstan/phpstan": "^0.9.2", "phpstan/phpstan": "^0.9.2",
"ifsnop/mysqldump-php": "2.*", "ifsnop/mysqldump-php": "2.*",
"setasign/fpdf": "1.8.1", "setasign/fpdf": "1.8.1",
"mpdf/mpdf": "^7.0", "mpdf/mpdf": "^7.0"
"php" : ">= 7.1"
} }
} }

Binary file not shown.

View File

@ -82,21 +82,13 @@
} }
}, },
"POST": {
"des": "Create a new Department",
"per": [["cas_user"]],
"par": {
"name": { "des": "Name of the department", "typ": "text"}
}
},
"PUT":{ "PUT":{
"des": "Switch the user on another department database", "des": "Switch the user on another department database",
"per": [["cas_user"]], "per": [["cas_user"]],
"par": { "par": {
"URL0": {"des": "Department id", "typ": "id", "ren": "department" } "URL0": {"des": "Department id", "typ": "id", "ren": "department" }
}, },
"out": { "output": {
"switched": { "des": "Whether the department has been switched", "typ": "bool" } "switched": { "des": "Whether the department has been switched", "typ": "bool" }
} }
@ -117,54 +109,31 @@
} }
} }
}, },
"export":{
"GET": {
"des": "Export the data of the current department and version to a Excel file",
"per": [["cas_admin"]],
"par": {},
"opt": { "download": true }
}
},
"version":{ "version":{
"switch":{
"GET": {
"des": "Switch database version for the current session",
"per": [["cas_admin"]],
"par": {
"URL0": { "des": "The version id", "typ": "id", "ren": "version" }
},
"out": {
"sucess": { "des": "success of the operation", "typ": "bool" }
}
}
},
"GET": { "GET": {
"des": "Get the list of the versions of the department", "des": "Get the list of the versions of the department",
"per": [["cas_admin"]], "per": [["cas_admin"]],
"par": {}, "par": {},
"out": { "output": {
"versions": { "des": "List of available versions", "typ": "array" } "versions": { "des": "List of available versions", "typ": "array" }
} }
}, },
"POST": { "POST": {
"des": "Create a backup if the name is empty, execute the backup if the name is set", "des": "Create a backup if the name is empty, execute the backup if the name is set",
"per": [["cas_admin"]], "per": [["cas_admin"]],
"par": { "par": {},
"label": { "des": "Label of the version", "typ": "text" } "output": {
},
"out": {
"created_id": { "des": "The id of the created version", "typ": "varchar(10,10,alphanumeric)" } "created_id": { "des": "The id of the created version", "typ": "varchar(10,10,alphanumeric)" }
} }
}, },
"PUT": { "PUT": {
"des": "Update a version and switch to this version", "des": "Switches to a older version or to current state",
"per": [["cas_admin"]], "per": [["cas_admin"]],
"par": { "par": {
"URL0": { "des": "id of the version", "typ": "id", "ren": "version" }, "URL0": { "des": "0 to preview, 1 to apply", "typ": "id", "ren": "apply" },
"label": { "des": "Label de la version", "typ": "text", "opt": true }, "URL1": { "des": "The version name, current state if ommited", "typ": "varchar(10,10,alphanumeric)", "ren": "version", "opt": true }
"default": { "des": "Whether this version should be used on login", "typ": "bool", "opt": true }
}, },
"out": { "output": {
"updated": { "des": "Whether the version has been switched|applied", "typ": "bool" } "updated": { "des": "Whether the version has been switched|applied", "typ": "bool" }
} }
}, },
@ -172,9 +141,9 @@
"des": "Delete a backup", "des": "Delete a backup",
"per": [["cas_admin"]], "per": [["cas_admin"]],
"par": { "par": {
"URL0": { "des": "The version id", "typ": "id", "ren": "version" } "URL0": { "des": "The version name", "typ": "varchar(10,10,alphanumeric)", "ren": "version" }
}, },
"out": { "output": {
"deleted": { "des": "Whether the version has been deleted", "typ": "bool" } "deleted": { "des": "Whether the version has been deleted", "typ": "bool" }
} }
} }
@ -261,7 +230,7 @@
"GET": { "GET": {
"des": "Get a professor's fiche", "des": "Get a professor's fiche",
"per": [["cas_admin"], ["cas_user"]], "per": [["cas_admin"]],
"par": { "par": {
"URL0": { "des": "Optional professor UID.", "typ": "id", "ren": "prof_id" } "URL0": { "des": "Optional professor UID.", "typ": "id", "ren": "prof_id" }
}, },
@ -346,9 +315,8 @@
"volume": { "des": "Number of hours for Cours", "typ": "id", "opt": true, "def": 0 }, "volume": { "des": "Number of hours for Cours", "typ": "id", "opt": true, "def": 0 },
"formations": { "des": "List of formations (ids)", "typ": "array<id>", "opt": true, "def": [] } "formations": { "des": "List of formations (ids)", "typ": "array<id>", "opt": true, "def": [] }
}, },
"out": { "output": {
"created_id" : { "des": "The id of the created Cours", "typ": "id" }, "created_id" : { "des": "The id of the created Cours", "typ": "id" }
"formations" : { "des": "The ids of the linked formations", "typ": "array<id>" }
} }
}, },
@ -370,7 +338,7 @@
"add_form": { "des": "Id of formations to add", "typ": "array<id>", "opt": true, "def": [] }, "add_form": { "des": "Id of formations to add", "typ": "array<id>", "opt": true, "def": [] },
"rem_form": { "des": "Id of formations to remove", "typ": "array<id>", "opt": true, "def": [] } "rem_form": { "des": "Id of formations to remove", "typ": "array<id>", "opt": true, "def": [] }
}, },
"out": { "output": {
"updated" : { "des": "Whether it has been updated", "typ": "bool" } "updated" : { "des": "Whether it has been updated", "typ": "bool" }
} }
}, },
@ -381,7 +349,7 @@
"par": { "par": {
"URL0": { "des": "Id of the Cours", "typ": "id", "ren": "idCours" } "URL0": { "des": "Id of the Cours", "typ": "id", "ren": "idCours" }
}, },
"out": { "output": {
"deleted" : { "des": "Whether it has been deleted", "typ": "bool" } "deleted" : { "des": "Whether it has been deleted", "typ": "bool" }
} }
} }
@ -399,9 +367,8 @@
"volume": { "des": "Number of hours for TD", "typ": "id", "opt": true, "def": 0 }, "volume": { "des": "Number of hours for TD", "typ": "id", "opt": true, "def": 0 },
"formations": { "des": "List of formations (ids)", "typ": "array<id>", "opt": true, "def": [] } "formations": { "des": "List of formations (ids)", "typ": "array<id>", "opt": true, "def": [] }
}, },
"out": { "output": {
"created_id" : { "des": "The id of the created TD", "typ": "id" }, "created_id" : { "des": "The id of the created TD", "typ": "id" }
"formations" : { "des": "The ids of the linked formations", "typ": "array<id>" }
} }
}, },
@ -423,7 +390,7 @@
"add_form": { "des": "Id of formations to add", "typ": "array<id>", "opt": true, "def": [] }, "add_form": { "des": "Id of formations to add", "typ": "array<id>", "opt": true, "def": [] },
"rem_form": { "des": "Id of formations to remove", "typ": "array<id>", "opt": true, "def": [] } "rem_form": { "des": "Id of formations to remove", "typ": "array<id>", "opt": true, "def": [] }
}, },
"out": { "output": {
"updated" : { "des": "Whether it has been updated", "typ": "bool" } "updated" : { "des": "Whether it has been updated", "typ": "bool" }
} }
}, },
@ -434,7 +401,7 @@
"par": { "par": {
"URL0": { "des": "Id of the TD", "typ": "id", "ren": "idTD" } "URL0": { "des": "Id of the TD", "typ": "id", "ren": "idTD" }
}, },
"out": { "output": {
"deleted" : { "des": "Whether it has been deleted", "typ": "bool" } "deleted" : { "des": "Whether it has been deleted", "typ": "bool" }
} }
} }
@ -452,9 +419,8 @@
"volume": { "des": "Number of hours for TP", "typ": "id", "opt": true, "def": 0 }, "volume": { "des": "Number of hours for TP", "typ": "id", "opt": true, "def": 0 },
"formations": { "des": "List of formations (ids)", "typ": "array<id>", "opt": true, "def": [] } "formations": { "des": "List of formations (ids)", "typ": "array<id>", "opt": true, "def": [] }
}, },
"out": { "output": {
"created_id" : { "des": "The id of the created TP", "typ": "id" }, "created_id" : { "des": "The id of the created TP", "typ": "id" }
"formations" : { "des": "The ids of the linked formations", "typ": "array<id>" }
} }
}, },
@ -476,7 +442,7 @@
"add_form": { "des": "Id of formations to add", "typ": "array<id>", "opt": true, "def": [] }, "add_form": { "des": "Id of formations to add", "typ": "array<id>", "opt": true, "def": [] },
"rem_form": { "des": "Id of formations to remove", "typ": "array<id>", "opt": true, "def": [] } "rem_form": { "des": "Id of formations to remove", "typ": "array<id>", "opt": true, "def": [] }
}, },
"out": { "output": {
"updated" : { "des": "Whether it has been updated", "typ": "bool" } "updated" : { "des": "Whether it has been updated", "typ": "bool" }
} }
}, },
@ -487,7 +453,7 @@
"par": { "par": {
"URL0": { "des": "Id of the TP", "typ": "id", "ren": "idTP" } "URL0": { "des": "Id of the TP", "typ": "id", "ren": "idTP" }
}, },
"out": { "output": {
"deleted" : { "des": "Whether it has been deleted", "typ": "bool" } "deleted" : { "des": "Whether it has been deleted", "typ": "bool" }
} }
} }
@ -503,33 +469,6 @@
"par": { "par": {
"URL0":{"des" : "Id of the formation", "typ": "id", "ren": "form_id", "opt" : true } "URL0":{"des" : "Id of the formation", "typ": "id", "ren": "form_id", "opt" : true }
} }
},
"POST":{
"des": "Create a new formation",
"per": [["cas_admin"]],
"par": {
"label":{"des" : "name of the formation", "typ": "text" },
"isInternal":{"des" : "is this formation internal to the department", "typ": "bool" }
}
},
"PUT":{
"des": "Update a formation",
"per": [["cas_admin"]],
"par": {
"URL0": { "des": "Id of the formation", "typ": "id", "ren": "idFormation" },
"label":{"des" : "name of the formation", "typ": "text", "opt":true },
"isInternal":{"des" : "is this formation internal to the department", "typ": "bool", "opt":true }
}
},
"DELETE":{
"des": "Delete a formation",
"per": [["cas_admin"]],
"par": {
"URL0": { "des": "Id of the formation", "typ": "id", "ren": "idFormation" }
}
} }
}, },

9419
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@
"node-sass": "^4.7.2", "node-sass": "^4.7.2",
"sass-loader": "^6.0.6", "sass-loader": "^6.0.6",
"vue-loader": "^13.0.5", "vue-loader": "^13.0.5",
"vue-template-compiler": "^2.5.16", "vue-template-compiler": "^2.5.9",
"webpack": "^3.8.1", "webpack": "^3.8.1",
"webpack-dev-server": "^2.9.5" "webpack-dev-server": "^2.9.5"
} }

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="32px"
id="Layer_1"
style="enable-background:new 0 0 32 32;"
version="1.1"
viewBox="0 0 32 32"
width="32px"
xml:space="preserve"
sodipodi:docname="back.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"><metadata
id="metadata9"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1015"
id="namedview5"
showgrid="false"
inkscape:zoom="7.375"
inkscape:cx="16"
inkscape:cy="16"
inkscape:window-x="0"
inkscape:window-y="29"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" /><path
d="M 12,6 C 11.469,6 11.005141,6.1930781 10.619141,6.5800781 L 2.6621094,14.537109 C 2.3341094,14.865109 2,15.271 2,16 c 0,0.729 0.2794844,1.080266 0.6464844,1.447266 l 7.9726566,7.972656 C 11.005141,25.806922 11.469,26 12,26 c 1.188,0 2,-1.016 2,-2 0,-0.516 -0.186078,-0.986859 -0.580078,-1.380859 L 8.8007812,18 H 28 c 1.104,0 2,-0.896 2,-2 0,-1.104 -0.896,-2 -2,-2 H 8.8007812 L 13.419922,9.3808594 C 13.813922,8.9868594 14,8.516 14,8 14,7.016 13.187,6 12,6 Z"
id="fill-edit"
inkscape:connector-curvature="0" /></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
enable-background="new 0 0 500 500"
height="500px"
id="Layer_1"
version="1.1"
viewBox="0 0 500 500"
width="500px"
xml:space="preserve"
sodipodi:docname="pin-disabled.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"><metadata
id="metadata9"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1015"
id="namedview5"
showgrid="false"
inkscape:zoom="0.6675088"
inkscape:cx="186.10652"
inkscape:cy="69.51775"
inkscape:window-x="0"
inkscape:window-y="29"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1"
inkscape:snap-page="true" /><path
style="clip-rule:evenodd;fill:#010101;fill-rule:evenodd"
d="M 463.1543 1 L 349.9375 114.2168 L 349.9375 77.375 L 363.56836 77.375 C 376.10336 77.375 386.2832 67.198109 386.2832 54.662109 C 386.2832 42.126109 376.10336 31.949219 363.56836 31.949219 L 136.43164 31.949219 C 123.89564 31.949219 113.71875 42.126109 113.71875 54.662109 C 113.71875 67.199109 123.89564 77.375 136.43164 77.375 L 150.06055 77.375 L 150.06055 232.73828 L 82.828125 300.60742 C 79.465125 303.87442 77.376953 308.50466 77.376953 313.59766 C 77.376953 323.58866 85.459234 331.77148 95.365234 331.77148 L 132.38281 331.77148 L 1 463.1543 L 36.845703 499 L 499 36.845703 L 463.1543 1 z M 213.6582 77.375 C 223.6532 77.375 231.83008 85.552828 231.83008 95.548828 L 231.83008 213.65625 C 231.83008 223.65225 223.6542 231.82812 213.6582 231.82812 C 203.6642 231.82812 195.48633 223.65225 195.48633 213.65625 L 195.48633 95.548828 C 195.48633 85.552828 203.6642 77.375 213.6582 77.375 z M 352.55469 235.29102 L 222.74414 365.10156 L 222.74414 445.33984 C 222.74414 457.87584 232.92103 468.05078 245.45703 468.05078 C 257.99403 468.05078 268.17188 457.87584 268.17188 445.33984 L 268.17188 331.77148 L 404.63281 331.77148 C 414.53181 331.77148 422.62305 323.58866 422.62305 313.59766 C 422.62305 308.60466 420.61847 304.06211 417.35547 300.78711 L 352.55469 235.29102 z "
id="fill-edit" /></svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -32,14 +32,13 @@
inkscape:window-height="1015" inkscape:window-height="1015"
id="namedview5" id="namedview5"
showgrid="false" showgrid="false"
inkscape:zoom="0.6675088" inkscape:zoom="0.472"
inkscape:cx="186.10652" inkscape:cx="14.830508"
inkscape:cy="69.51775" inkscape:cy="250"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="29" inkscape:window-y="29"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" inkscape:current-layer="Layer_1" /><path
inkscape:snap-page="true" /><path
d="m 150.061,232.739 -67.232,67.868 c -3.363,3.267 -5.453,7.898 -5.453,12.991 0,9.991 8.083,18.173 17.989,18.173 H 222.744 V 445.34 c 0,12.536 10.177,22.711 22.713,22.711 12.537,0 22.715,-10.175 22.715,-22.711 V 331.771 h 136.46 c 9.899,0 17.992,-8.182 17.992,-18.173 0,-4.993 -2.006,-9.536 -5.269,-12.811 L 349.938,232.644 V 77.375 h 13.631 c 12.535,0 22.715,-10.177 22.715,-22.713 0,-12.536 -10.18,-22.713 -22.715,-22.713 H 136.432 c -12.536,0 -22.713,10.177 -22.713,22.713 0,12.537 10.177,22.713 22.713,22.713 h 13.629 V 232.739 Z M 231.83,95.548 v 118.109 c 0,9.996 -8.176,18.172 -18.172,18.172 -9.994,0 -18.171,-8.176 -18.171,-18.172 V 95.548 c 0,-9.996 8.177,-18.173 18.171,-18.173 9.995,0 18.172,8.177 18.172,18.173 z" d="m 150.061,232.739 -67.232,67.868 c -3.363,3.267 -5.453,7.898 -5.453,12.991 0,9.991 8.083,18.173 17.989,18.173 H 222.744 V 445.34 c 0,12.536 10.177,22.711 22.713,22.711 12.537,0 22.715,-10.175 22.715,-22.711 V 331.771 h 136.46 c 9.899,0 17.992,-8.182 17.992,-18.173 0,-4.993 -2.006,-9.536 -5.269,-12.811 L 349.938,232.644 V 77.375 h 13.631 c 12.535,0 22.715,-10.177 22.715,-22.713 0,-12.536 -10.18,-22.713 -22.715,-22.713 H 136.432 c -12.536,0 -22.713,10.177 -22.713,22.713 0,12.537 10.177,22.713 22.713,22.713 h 13.629 V 232.739 Z M 231.83,95.548 v 118.109 c 0,9.996 -8.176,18.172 -18.172,18.172 -9.994,0 -18.171,-8.176 -18.171,-18.172 V 95.548 c 0,-9.996 8.177,-18.173 18.171,-18.173 9.995,0 18.172,8.177 18.172,18.173 z"
id="fill-edit" id="fill-edit"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="32"
viewBox="0 0 32 32"
width="32"
version="1.1"
id="svg6"
sodipodi:docname="switch.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1022"
id="namedview8"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="4.9166667"
inkscape:cx="24"
inkscape:cy="29.898306"
inkscape:window-x="0"
inkscape:window-y="29"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
d="M 23.384615,24.615384 V 18.461538 H 8.615385 v 6.153846 L 0,15.999999 8.615385,7.3846151 v 6.1538459 h 14.76923 V 7.3846151 L 32,15.999999 Z"
id="fill-edit"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc"
style="stroke-width:1.23076928" />
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
enable-background="new 0 0 24 24"
height="24px"
id="Layer_1"
version="1.1"
viewBox="0 0 24 24"
width="24px"
xml:space="preserve"
sodipodi:docname="time.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"><metadata
id="metadata13"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs11" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1015"
id="namedview9"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="29"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" /><path
d="m 12,2.0344069 c -5.5018378,0 -9.9631017,4.4620943 -9.9631017,9.9655931 0,5.503499 4.4612639,9.965593 9.9631017,9.965593 5.502668,0 9.963102,-4.462094 9.963102,-9.965593 0,-5.5034988 -4.460434,-9.9655931 -9.963102,-9.9655931 z m 3.664016,13.8762581 -0.290663,0.290663 c -0.241665,0.241666 -0.649424,0.253292 -0.903547,0.02408 l -3.753707,-3.28449 C 10.460316,12.71254 10.266817,12.244987 10.283427,11.902835 l 0.347965,-5.9245446 c 0.01827,-0.3429825 0.313086,-0.6220191 0.656068,-0.6220191 h 0.40942 c 0.342982,0 0.636967,0.2790366 0.653577,0.6211886 l 0.28485,4.9279861 c 0.01744,0.342982 0.217582,0.830466 0.444299,1.08708 l 2.610985,3.012931 c 0.226718,0.256614 0.215921,0.663542 -0.02657,0.905208 z"
id="fill-edit"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-width:0.83046609" /></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -7,29 +7,42 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Espace enseignant</title> <title>Gestion des enseignants</title>
<!-- Icon --> <!-- Icon -->
<link rel='shortcut icon' href='/favicon.ico'> <link rel='shortcut icon' href='/favicon.ico'>
<!-- CSS dependencies --> <!-- CSS dependencies -->
<link href="https://fonts.googleapis.com/css?family=Fira+Sans" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Fira+Sans" rel="stylesheet">
<link rel='stylesheet' type='text/css' href='/css/font-loader.css'>
<link rel='stylesheet' type='text/css' href='/css/global.css'>
<link rel='stylesheet' type='text/css' href='/css/pop-up.css'>
<link rel='stylesheet' type='text/css' href='/css/layout.css'> <link rel='stylesheet' type='text/css' href='/css/layout.css'>
<link rel='stylesheet' type='text/css' href='/css/menu.css'>
<link rel='stylesheet' type='text/css' href='/css/header.css'>
<link rel='stylesheet' type='text/css' href='/css/container.css'>
<body> <!-- JS dependencies -->
<script type='text/javascript' src='/js/_SERVER.js'></script>
<div id="WRAPPER" class='login'> </head>
<body class='loading'>
<div id='LOGIN_REDIRECT'> <div id='main-vue'></div>
<div class='icon'></div>
<div class='title'><b>P</b><i>lateforme</i> <b>A</b><i>ssistée de</i> <b>T</b><i>raitement</i> <b>A</b><i>dministratif des</i> <b>T</b><i>aches d'</i><b>E</b><i>nseignement</i></div>
<a href="/api/v/1.0/professor/pdf/<?php echo $_SESSION['CAS']["id"]; ?>"><button style='font-weight: normal; margin-bottom: 1em;'>Télécharger ma fiche</button></a>
<a href="/fiche/logout"><button style='font-weight: normal'>Me déconnecter</button></a> <!-- POPUP WINDOW -->
<div id='POPUP'>
<div class='header'></div>
<div class='body'></div>
<div class='footer'></div>
</div> </div>
<div id='POPUP-BG'></div>
</div> <!-- Main loop -->
<script type='text/javascript' src='/js/bundle@fiche.js' onload="document.body.className=''"></script>
</body> </body>
</html> </html>

View File

@ -7,7 +7,7 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Connexion</title> <title>PTUT web title</title>
<!-- Icon --> <!-- Icon -->
<link rel='shortcut icon' href='/favicon.ico'> <link rel='shortcut icon' href='/favicon.ico'>
@ -46,5 +46,4 @@
<!-- Main loop --> <!-- Main loop -->
<script type='text/javascript' src='/js/bundle@home.js' onload="document.body.className=''"></script> <script type='text/javascript' src='/js/bundle@home.js' onload="document.body.className=''"></script>
</body> </body>
</html> </html>

View File

@ -72,6 +72,18 @@ module.exports = [ {
module: mod_common, module: mod_common,
devtool: (process.env.NODE_ENV==='development') ? '#eval-source-map' : false devtool: (process.env.NODE_ENV==='development') ? '#eval-source-map' : false
}, {
name: "fiche",
entry: './webpack/page/fiche.js',
output: {
path: path.resolve(__dirname, './public_html/js/bundle'),
publicPath: '/js/bundle/',
filename: 'fiche@0.js'
},
module: mod_common,
devtool: (process.env.NODE_ENV==='development') ? '#eval-source-map' : false
}, { }, {
name: "settings", name: "settings",

View File

@ -1,7 +1,7 @@
<template> <template>
<div id='CONTAINER' class='list'> <div id='CONTAINER' class='list'>
<svg xmlns="http://www.w3.org/2000/svg" :viewBox="gstore.viewBox"> <svg xmlns="http://www.w3.org/2000/svg">
<template v-if="gstore.dimensions"> <template v-if="gstore.dimensions">
<path <path
:d="'m ' + (gstore.dimensions.padding + gstore.dimensions.text.size) + ',' + (gstore.dimensions.padding) + ' ' + :d="'m ' + (gstore.dimensions.padding + gstore.dimensions.text.size) + ',' + (gstore.dimensions.padding) + ' ' +

View File

@ -33,10 +33,6 @@
</h1> </h1>
<div class='table'> <div class='table'>
<div title='équivalents TD'>
<span>0</span>
<span>HETD</span>
</div>
<div> <div>
<span><input type='text' placeholder='???' v-model='gstore.create_h'></span> <span><input type='text' placeholder='???' v-model='gstore.create_h'></span>
<span>heures à faire</span> <span>heures à faire</span>
@ -47,7 +43,6 @@
<div class='footer'> <div class='footer'>
<button class='valid' @click='gstore.ic_handler()'>Créer l'enseignant</button> <button class='valid' @click='gstore.ic_handler()'>Créer l'enseignant</button>
<button class='neutral' @click='gstore.ic_reset(); gstore.create_card=false'>Annuler</button>
</div> </div>
</section> </section>
@ -88,24 +83,22 @@
<div class='table'> <div class='table'>
<div>
<!-- if VIEW MODE -->
<span v-show='gstore.edit_i!=pi'>{{prof.hoursToDo}}</span>
<!-- if EDIT MODE -->
<span v-show='gstore.edit_i==pi'><input type='text' placeholder='???' v-model='gstore.edit_h'></span>
<!-- endif -->
<span>heures à faire</span>
</div>
<div title='équivalents TD'> <div title='équivalents TD'>
<span>{{ prof.equiTD }}</span> <span>{{ prof.equiTD }}</span>
<span>HETD</span> <span>HETD</span>
</div> </div>
<!-- if EDIT MODE -->
<div v-show='gstore.edit_i==pi'>
<span><input type='text' placeholder='???' v-model='gstore.edit_h'></span>
<span>heures à faire</span>
</div>
<!-- endif -->
<div title='heures de décalage' v-show='gstore.edit_i!=pi'>
<span :data-error='prof.equiTD < prof.hoursToDo?1:0' :data-success='prof.equiTD < prof.hoursToDo?0:1'>{{ Math.floor( (prof.equiTD < prof.hoursToDo ? prof.hoursToDo-prof.equiTD : prof.equiTD-prof.hoursToDo)*100 )/100 }}</span>
<span>{{ prof.equiTD < prof.hoursToDo ? 'sous-service' : 'sur-service' }}</span>
</div>
</div> </div>
<!-- if VIEW MODE --> <!-- if VIEW MODE -->
<div v-show='gstore.edit_i!=pi' class='sub' title='total des heures prévues'><strong>{{ prof.VHCours + prof.VHTd + prof.VHTp }}</strong> heures présentielles</div>
<div v-show='gstore.edit_i!=pi' class='pdfdl' title='Télécharger la fiche' @click='gstore.id_handler(prof.idProfesseur)'>fiche</div> <div v-show='gstore.edit_i!=pi' class='pdfdl' title='Télécharger la fiche' @click='gstore.id_handler(prof.idProfesseur)'>fiche</div>
<!-- if EDIT MODE --> <!-- if EDIT MODE -->
<div v-show='gstore.edit_i==pi' :class="gstore.edit_err.length > 0 ? 'sub warning' : 'sub'" :data-valid='gstore.edit_err_valid?1:0'>{{ gstore.edit_err }}</div> <div v-show='gstore.edit_i==pi' :class="gstore.edit_err.length > 0 ? 'sub warning' : 'sub'" :data-valid='gstore.edit_err_valid?1:0'>{{ gstore.edit_err }}</div>
@ -113,7 +106,7 @@
<div class='footer'> <div class='footer'>
<!-- if VIEW MODE --> <!-- if VIEW MODE -->
<span v-show='gstore.edit_i!=pi' :class="(prof.VHCours == 0) ? 'course' : 'course active'">{{ prof.VHCours }}h <span>CM</span></span> <span v-show='gstore.edit_i!=pi' :class="(prof.VHCours == 0) ? 'course' : 'course active'">{{ prof.VHCours }}h <span>Cours</span></span>
<hr v-show='gstore.edit_i!=pi'> <hr v-show='gstore.edit_i!=pi'>
<span v-show='gstore.edit_i!=pi' :class="(prof.VHTd == 0) ? 'td' : 'td active'" >{{ prof.VHTd }}h <span>TD</span></span> <span v-show='gstore.edit_i!=pi' :class="(prof.VHTd == 0) ? 'td' : 'td active'" >{{ prof.VHTd }}h <span>TD</span></span>
<hr v-show='gstore.edit_i!=pi'> <hr v-show='gstore.edit_i!=pi'>
@ -123,12 +116,6 @@
<button v-show='gstore.edit_i==pi' class='grey' @click='gstore.ie_toggle(-1)'>Annuler</button> <button v-show='gstore.edit_i==pi' class='grey' @click='gstore.ie_toggle(-1)'>Annuler</button>
<!-- endif --> <!-- endif -->
</div> </div>
<div class='info'>
<strong>{{ prof.hoursToDo }}h</strong> à faire, <strong>{{ prof.VHCours + prof.VHTd + prof.VHTp }}h</strong> présentielles
</div>
</section> </section>
</div> </div>

View File

@ -5,16 +5,13 @@
<div class='list container' data-anim-incoming='1' :data-anim-bounce='gstore.nav_anim.out?1:0'> <div class='list container' data-anim-incoming='1' :data-anim-bounce='gstore.nav_anim.out?1:0'>
<section class='filter'>
<button class='back reflow search' @click='$router.back()'>Retour</button>
</section>
<!-- FILTERS --> <!-- FILTERS -->
<section class='filter'> <section class='filter'>
<div style='flex-basis: 3.2em'></div>
<div :data-filter='gstore.order.current===0?1:0' @click='gstore.order_toggle(0)'>enseignant <span class='arrow' :data-way='gstore.order.way'></span></div> <div>enseignant</div>
<div :data-filter='gstore.order.current===1?1:0' @click='gstore.order_toggle(1)'>volume horaire <span class='arrow' :data-way='gstore.order.way'></span></div> <div class='null'></div>
<div :data-filter='gstore.order.current===2?1:0' @click='gstore.order_toggle(2)'>formations <span class='arrow' :data-way='gstore.order.way'></span></div> <div>volume horaire</div>
<div>formations</div>
</section> </section>
@ -32,7 +29,7 @@
</select> </select>
<select v-model='gstore.ccrea.type' class='min'> <select v-model='gstore.ccrea.type' class='min'>
<option value='-' disabled>Type</option> <option value='-' disabled>Type</option>
<option value='0'>CM</option> <option value='0'>Cours</option>
<option value='1'>TD</option> <option value='1'>TD</option>
<option value='2'>TP</option> <option value='2'>TP</option>
</select> </select>
@ -48,22 +45,17 @@
<!-- COURS --> <!-- COURS -->
<section class='bcours' <section class='cours'
v-for='(c,i) in gstore.manage.cours' v-for='(c,i) in gstore.manage.cours'
:data-id='c.idCours' :data-id='c.idCours'>
data-anim-incoming='1'
:data-anim-bounce='gstore.nav_anim.out?1:0'
:data-prof='c.idProf'
:data-vol='c.volume'
:data-form='c.formations.join(`|`)'>
<div class='icon remove' @click='gstore.rem(0, i)'></div> <div class='icon remove' @click='gstore.rem(0, i)'></div>
<select v-model='c.new_prof' @change='gstore.upd_prof(0, i)'> <select v-model='c.new_prof' @change='gstore.upd_prof(0, i)'>
<option value='-1' v-show='c.idProf!=-1'>Aucun enseignant affecté</option> <option value='-1' v-show='c.idProf!=-1'>Aucun enseignant affecté</option>
<option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=c.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option> <option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=c.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option>
</select> </select>
<div class='cm reflow active'>{{ c.volume }}</div> <div>Cours</div>
<div><span class='mono'>{{ c.volume }}</span> heures</div>
<div class='taglist'> <div class='taglist'>
<div v-for='f in c.formations' data-action> <div v-for='f in c.formations' data-action>
<span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span> <span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span>
@ -86,22 +78,19 @@
<!-- TD --> <!-- TD -->
<section class='btd' <section class='td'
v-for='(td,i) in gstore.manage.td' v-for='(td,i) in gstore.manage.td'
:data-id='td.idTD' :data-id='td.idTD'
data-anim-incoming='1' data-anim-incoming='1'
:data-anim-bounce='gstore.nav_anim.out?1:0' :data-anim-bounce='gstore.nav_anim.out?1:0'>
:data-prof='td.idProf'
:data-vol='td.volume'
:data-form='td.formations.join(`|`)'>
<div class='icon remove' @click='gstore.rem(1, i)'></div> <div class='icon remove' @click='gstore.rem(1, i)'></div>
<select v-model='td.new_prof' @change='gstore.upd_prof(1, i)'> <select v-model='td.new_prof' @change='gstore.upd_prof(1, i)'>
<option value='-1' v-show='td.idProf!=-1'>Aucun enseignant affecté</option> <option value='-1' v-show='td.idProf!=-1'>Aucun enseignant affecté</option>
<option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=td.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option> <option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=td.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option>
</select> </select>
<div class='td reflow active'>{{ td.volume }}</div> <div>TD</div>
<div><span class='mono'>{{ td.volume }}</span> heures</div>
<div class='taglist'> <div class='taglist'>
<div v-for='f in td.formations' data-action> <div v-for='f in td.formations' data-action>
<span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span> <span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span>
@ -124,22 +113,19 @@
<!-- TP --> <!-- TP -->
<section class='btp' <section class='tp'
v-for='(tp,i) in gstore.manage.tp' v-for='(tp,i) in gstore.manage.tp'
:data-id='tp.idTP' :data-id='tp.idTP'
data-anim-incoming='1' data-anim-incoming='1'
:data-anim-bounce='gstore.nav_anim.out?1:0' :data-anim-bounce='gstore.nav_anim.out?1:0'>
:data-prof='tp.idProf'
:data-vol='tp.volume'
:data-form='tp.formations.join(`|`)'>
<div class='icon remove' @click='gstore.rem(2, i)'></div> <div class='icon remove' @click='gstore.rem(2, i)'></div>
<select v-model='tp.new_prof' @change='gstore.upd_prof(2, i)'> <select v-model='tp.new_prof' @change='gstore.upd_prof(2, i)'>
<option value='-1' v-show='tp.idProf!=-1'>Aucun enseignant affecté</option> <option value='-1' v-show='tp.idProf!=-1'>Aucun enseignant affecté</option>
<option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=tp.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option> <option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=tp.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option>
</select> </select>
<div class='tp reflow active'>{{ tp.volume }}</div> <div>TP</div>
<div><span class='mono'>{{ tp.volume }}</span> heures</div>
<div class='taglist'> <div class='taglist'>
<div v-for='f in tp.formations' data-action> <div v-for='f in tp.formations' data-action>
<span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span> <span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span>

View File

@ -2,20 +2,6 @@
<div id='CONTAINER' class='card'> <div id='CONTAINER' class='card'>
<div class='card filter'>
<div v-for='(filter_grp, gname) in gstore.filters' :title='gname' data-unblur-filter>
<div class='fold-toggle' :data-show='gstore.filters[gname][0].visible?1:0' @click='gstore.show_fgroup(gname)' :data-count='gstore.filters[gname][0].active.length' data-unblur-filter>{{ gname }}</div>
<div class='fold' data-unblur-filter>
<span v-for='(data, i) in filter_grp' v-if='i > 0' :class="data.active == true ? 'active' : ''" @click='gstore.toggle_filter(gname, i); gstore.filter_handler(gname);' :title='data.code' data-unblur-filter>{{ data.name }}</span>
</div>
</div>
</div>
<div class='card container' :data-anim-outgoing='gstore.nav_anim.in?1:0'> <div class='card container' :data-anim-outgoing='gstore.nav_anim.in?1:0'>
<input data-anim='0' class='card instant-search neutral' type='text' @keyup='gstore.is_handler($event)' placeholder='Recherche instantannée' id='ue_view_instant_search'> <input data-anim='0' class='card instant-search neutral' type='text' @keyup='gstore.is_handler($event)' placeholder='Recherche instantannée' id='ue_view_instant_search'>
@ -29,23 +15,11 @@
<option v-for='form in gstore.formations' :value='form.idForm'>{{ form.labelForm }}</option> <option v-for='form in gstore.formations' :value='form.idForm'>{{ form.labelForm }}</option>
</select> </select>
<h1 class='pin'> <h1>
<input type='text' placeholder='Libellé' v-model='gstore.create_label'> <input type='text' placeholder='Libellé' v-model='gstore.create_label'>
<span data-visible='1'>(<input type='text' placeholder='code' v-model='gstore.create_code'>)</span> <span data-visible='1'>(<input type='text' placeholder='code' v-model='gstore.create_code'>)</span>
</h1> </h1>
<div class='table little'>
<div>
<span class='notlast active reflow' data-error='0'>0 CM</span>
</div>
<div>
<span class='notlast active reflow' data-error='0'>0 TD</span>
</div>
<div>
<span class='notlast active reflow' data-error='0'>0 TP</span>
</div>
</div>
<div :class="gstore.create_err.length > 0 ? 'sub warning' : 'sub'" :data-valid='gstore.create_err_valid?1:0'>{{ gstore.create_err }}</div> <div :class="gstore.create_err.length > 0 ? 'sub warning' : 'sub'" :data-valid='gstore.create_err_valid?1:0'>{{ gstore.create_err }}</div>
<div class='footer'> <div class='footer'>
@ -58,7 +32,6 @@
<div class='footer'> <div class='footer'>
<button class='valid' @click='gstore.ic_handler()'>Créer l'UE</button> <button class='valid' @click='gstore.ic_handler()'>Créer l'UE</button>
<button class='neutral' @click='gstore.ic_reset(); gstore.create_card=false'>Annuler</button>
</div> </div>
</section> </section>
@ -73,7 +46,6 @@
<!-- if VIEW MODE --> <!-- if VIEW MODE -->
<div class='goo-menu' v-show='gstore.edit_i!=pi'> <div class='goo-menu' v-show='gstore.edit_i!=pi'>
<div class='enabled' :data-enabled='ue.code' :data-active='ue.disabled?0:1' title='UE activée' @click="gstore.ia_handler(pi)"></div> <div class='enabled' :data-enabled='ue.code' :data-active='ue.disabled?0:1' title='UE activée' @click="gstore.ia_handler(pi)"></div>
<div class='required' :data-required='ue.code' :data-active='ue.required?1:0' title='UE obligatoire' @click="gstore.io_handler(pi)"></div>
<div class='remove' :data-remove='ue.code' title='Supprimer' @click="gstore.ir_handler(ue.code)"></div> <div class='remove' :data-remove='ue.code' title='Supprimer' @click="gstore.ir_handler(ue.code)"></div>
<div class='edit' :data-edit='ue.code' title='Modifier' @click="gstore.ie_toggle(pi)"></div> <div class='edit' :data-edit='ue.code' title='Modifier' @click="gstore.ie_toggle(pi)"></div>
</div> </div>
@ -89,35 +61,19 @@
<!-- endif --> <!-- endif -->
<!-- if VIEW MODE --> <!-- if VIEW MODE -->
<h1 v-show='gstore.edit_i!=pi' :class='ue.required?`pin`:`pin disabled`' :title='ue.required?`obligatoire`:`optionnelle`'><span :data-strike='ue.disabled?1:0'>{{ ue.label }}</span><span :data-visible='1'>({{ ue.code }})</span></h1> <h1 v-show='gstore.edit_i!=pi'>{{ ue.label }}<span :data-visible='1'>({{ ue.code }})</span></h1>
<!-- if EDIT MODE --> <!-- if EDIT MODE -->
<h1 v-show='gstore.edit_i==pi' :class='ue.required?`pin`:`pin disabled`'> <h1 v-show='gstore.edit_i==pi' :class="ue.required ? 'warning' : ''">
<input type='text' placeholder='Libellé' v-model='gstore.edit_label'> <input type='text' placeholder='Libellé' v-model='gstore.edit_label'>
<!-- <span :data-visible='1'>({{ ue.code }})</span> --> <!-- <span :data-visible='1'>({{ ue.code }})</span> -->
<span data-visible='1'>(<input type='text' placeholder='code' v-model='gstore.edit_code'>)</span> <span data-visible='1'>(<input type='text' placeholder='code' v-model='gstore.edit_code'>)</span>
</h1> </h1>
<!-- endif --> <!-- endif -->
<div class='table little'>
<div>
<span class='active reflow' :data-error='ue.nbrCours>ue.nbrProfCours || ue.modCours > 0?1:0'>{{ ue.nbrCours }} CM</span>
<span v-show='ue.nbrCours>ue.nbrProfCours' class='notlast user-icon reflow nospace' :data-tooltip='`${ue.nbrCours-ue.nbrProfCours} enseignant(s) manquant(s)`'></span>
<span v-show='ue.modCours > 0' class='notlast time-icon reflow nospace' :data-tooltip='`${ue.volumeCours-ue.modCours} à ajouter | ${ue.modCours} à enlever`'></span>
</div>
<div>
<span class='active reflow' :data-error='ue.nbrTD>ue.nbrProfTD || ue.modTD > 0?1:0'>{{ ue.nbrTD }} TD</span>
<span v-show='ue.nbrTD>ue.nbrProfTD' class='notlast user-icon reflow nospace' :data-tooltip='`${ue.nbrCours-ue.nbrProfCours} enseignant(s) manquant(s)`'></span>
<span v-show='ue.modTD > 0' class='notlast time-icon reflow nospace' :data-tooltip='`${ue.volumeTD-ue.modTD} à ajouter | ${ue.modTD} à enlever`'></span>
</div>
<div>
<span class='active reflow' :data-error='ue.nbrTP>ue.nbrProfTP || ue.modTP > 0?1:0'>{{ ue.nbrTP }} TP</span>
<span v-show='ue.nbrTP>ue.nbrProfTP' class='notlast user-icon reflow nospace' :data-tooltip='`${ue.nbrCours-ue.nbrProfCours} enseignant(s) manquant(s)`'></span>
<span v-show='ue.modTP > 0' class='notlast time-icon reflow nospace' :data-tooltip='`${ue.volumeTP-ue.modTP} à ajouter | ${ue.modTP} à enlever`'></span>
</div>
</div>
<!-- if VIEW MODE --> <!-- if VIEW MODE -->
<div v-show='gstore.edit_i!=pi' :class="ue.required ? 'sub pin' : 'sub pin neutral'">{{ ue.required ? 'UE obligatoire' : 'UE optionnelle' }}</div>
<div v-show='gstore.edit_i!=pi' class='sub'><strong>{{ ue.volumeCours + ue.volumeTD + ue.volumeTP }}h</strong> totales</div>
<div v-show='gstore.edit_i!=pi' class='taglist'> <div v-show='gstore.edit_i!=pi' class='taglist'>
<span v-if='ue.formations.length==0' class='tag invalid'>Aucune formation</span> <span v-if='ue.formations.length==0' class='tag invalid'>Aucune formation</span>
<span v-for='form_id in ue.formations' :class="!!gstore.form_by_id(form_id).isInternal ? 'tag search' : 'tag'">{{ gstore.form_by_id(form_id).labelForm || '???' }}</span> <span v-for='form_id in ue.formations' :class="!!gstore.form_by_id(form_id).isInternal ? 'tag search' : 'tag'">{{ gstore.form_by_id(form_id).labelForm || '???' }}</span>
@ -127,6 +83,25 @@
<div v-show='gstore.edit_i==pi' :class="gstore.edit_err.length > 0 ? 'sub warning' : 'sub'" :data-valid='gstore.edit_err_valid?1:0'>{{ gstore.edit_err }}</div> <div v-show='gstore.edit_i==pi' :class="gstore.edit_err.length > 0 ? 'sub warning' : 'sub'" :data-valid='gstore.edit_err_valid?1:0'>{{ gstore.edit_err }}</div>
<!-- endif --> <!-- endif -->
<div class='footer'>
<!-- if VIEW MODE -->
<span v-show='gstore.edit_i!=pi' :class="(ue.volumeCours == 0) ? 'course' : 'course active'">{{ ue.volumeCours }}h <span>Cours</span></span>
<hr v-show='gstore.edit_i!=pi'>
<span v-show='gstore.edit_i!=pi' :class="(ue.volumeTD == 0) ? 'td' : 'td active'">{{ ue.volumeTD }}h <span>TD</span></span>
<hr v-show='gstore.edit_i!=pi'>
<span v-show='gstore.edit_i!=pi' :class="(ue.volumeTP == 0) ? 'tp' : 'tp active'">{{ ue.volumeTP }}h <span>TP</span></span>
<!-- if EDIT MODE -->
<span v-show='gstore.edit_i==pi' class='course'><input type='text' placeholder='???' v-model='gstore.edit_vol.c'><span>Cours</span></span>
<hr v-show='gstore.edit_i==pi'>
<span v-show='gstore.edit_i==pi' class='td'><input type='text' placeholder='???' v-model='gstore.edit_vol.td'><span>TD</span></span>
<hr v-show='gstore.edit_i==pi'>
<span v-show='gstore.edit_i==pi' class='tp'><input type='text' placeholder='???' v-model='gstore.edit_vol.tp'><span>TP</span></span>
<!-- endif -->
</div>
<!-- if VIEW MODE --> <!-- if VIEW MODE -->
<div class='footer' v-show='gstore.edit_i!=pi'> <div class='footer' v-show='gstore.edit_i!=pi'>
@ -139,13 +114,6 @@
</div> </div>
<!-- endif --> <!-- endif -->
<div class='info'>
<strong class='cm reflow'>{{ ue.volumeCours}}</strong> CM
<strong class='td reflow'>{{ ue.volumeTD}}</strong> TD
<strong class='tp reflow'>{{ ue.volumeTP }}</strong> TP
<strong>{{ ue.volumeCours + ue.volumeTD + ue.volumeTP }}h</strong>
</div>
</section> </section>
</div> </div>
@ -163,21 +131,6 @@
name: 'CONTAINER_VIEW', name: 'CONTAINER_VIEW',
data(){ data(){
return { gstore: gstore.get } return { gstore: gstore.get }
},
beforeMount(){
// set onblur to hide filter
window.onblur.link('ue.filter', (e) => {
// ignore [data-unblur-filter] elements
if( e.target.getAttribute('data-unblur-filter') !== null )
return;
// else: hide
gstore.get.show_fgroup(-1);
});
} }
} }

View File

@ -19,7 +19,7 @@ gstore.add('URI', document.URL.replace(/^(?:\/\/|[^\/]+)*/, '').split('/').filte
gstore.add('is_local', document.URL.replace(/^https?:\/\/([^\/:]+).*$/, '$1') == 'ptut.com'); gstore.add('is_local', document.URL.replace(/^https?:\/\/([^\/:]+).*$/, '$1') == 'ptut.com');
/* (4) API instance */ /* (4) API instance */
window.api = new APIClient(gstore.get.is_local ? 'http://ptut.com:8080/api/v/1.0/' : `${gstore.get.HOST}/api/v/1.0/`); window.api = new APIClient(gstore.get.is_local ? 'http://ptut.com:8080/api/v/1.0/' : 'https://ptut.xdrm.io/api/v/1.0/');
/* (5) PopUp instance */ /* (5) PopUp instance */
window.popup = new PopUp(); window.popup = new PopUp();
@ -49,6 +49,10 @@ gstore.add('menu_item', {
label: 'Gestion UE', label: 'Gestion UE',
url: 'ue', url: 'ue',
icon: 'ue' icon: 'ue'
}, fiche: {
label: 'Fiches',
url: 'fiche',
icon: 'fiche'
}, settings: { }, settings: {
label: 'Administration', label: 'Administration',
url: 'settings', url: 'settings',

View File

@ -2,7 +2,7 @@
/* (1) Load statistics /* (1) Load statistics
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Initialize list */ /* (1) Initialize list */
gstore.add('stats', null); gstore.add('stats', []);
gstore.add('dimensions', null); gstore.add('dimensions', null);
/* (2) Get statistics */ /* (2) Get statistics */
@ -46,7 +46,7 @@ api.call('GET department/stats', {}, function(rs) {
gstore.get.dimensions = { gstore.get.dimensions = {
padding: 5, padding: 5,
text: { text: {
size: maxLabelLength * 8.5, size: maxLabelLength * 9.5,
alignH: 5, alignH: 5,
alignV: 20, alignV: 20,
}, },
@ -71,8 +71,6 @@ api.call('GET department/stats', {}, function(rs) {
width: 500, width: 500,
precision: 4 precision: 4
}; };
gstore.get.viewBox = `0 0 ${gstore.get.dimensions.axis.width + gstore.get.dimensions.text.size + 50} ${gstore.get.dimensions.axis.height + 30}`;
}); });
gstore.add('colors', ["blue", "yellow", "green", "red", "purple", "lightblue", "lightred", "lightyellow", "lightgreen", "lightpurple"]); gstore.add('colors', ["blue", "yellow", "green", "red", "purple", "lightblue", "lightred", "lightyellow", "lightgreen", "lightpurple"]);

View File

@ -281,17 +281,7 @@ gstore.add('create_h', '');
gstore.add('create_err_valid', false); gstore.add('create_err_valid', false);
gstore.add('create_err', ''); gstore.add('create_err', '');
/* (4) Define reset handler */ /* (4) Define create handler */
gstore.add('ic_reset', function(){
gstore.add('create_cat', '-');
gstore.add('create_name', '');
gstore.add('create_cas', '');
gstore.add('create_h', '');
gstore.add('create_err_valid', false);
gstore.add('create_err', '');
});
/* (5) Define create handler */
gstore.add('ic_handler', function(prof_id){ gstore.add('ic_handler', function(prof_id){
/* (4.1) Trim text input */ /* (4.1) Trim text input */

View File

@ -1,14 +1,9 @@
/* (1) Load formations /* (1) Load formations
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Define global filter */ /* (1) Initialize list */
gstore.add('filters', {
formations: [{ visible: false, active: [] }]
});
/* (2) Initialize list */
gstore.add('formations', []); gstore.add('formations', []);
/* (3) Get Formations */ /* (2) Get Formations */
api.call('GET formation', {}, function(rs){ api.call('GET formation', {}, function(rs){
// {1} If error -> abort // // {1} If error -> abort //
@ -19,17 +14,9 @@ api.call('GET formation', {}, function(rs){
for( var i = 0 ; i < rs.formations.length ; i++ ) for( var i = 0 ; i < rs.formations.length ; i++ )
gstore.get.formations.push( rs.formations[i] ); gstore.get.formations.push( rs.formations[i] );
// {3} Format formation list for filters
for( var i = 0 ; i < rs.formations.length ; i++ )
gstore.get.filters.formations.push({
code: rs.formations[i].idForm,
name: rs.formations[i].labelForm,
active: false
});
}); });
/* (4) Get Formation label */ /* (3) Get Formation label */
gstore.add('form_by_id', function(form_id){ gstore.add('form_by_id', function(form_id){
/* (1) Abort if wrong form_id */ /* (1) Abort if wrong form_id */
@ -50,6 +37,7 @@ gstore.add('form_by_id', function(form_id){
/* (2) Load ues /* (2) Load ues
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Initialize list */ /* (1) Initialize list */
@ -71,101 +59,10 @@ api.call('GET ue/', { vh: true }, function(rs){
/* (3) Define filters' callback
---------------------------------------------------------*/
/* (1) Define global callback */
gstore.add('filter_handler', function(){
let filter_ids = [];
// 1. Get each formation ID
for( let form of gstore.get.filters.formations ){
// 1.1. Ignore if 'code' not found
if( form.code === null )
continue;
// 1.2. If active -> add to list
( form.code != null && form.active ) && filter_ids.push(form.code);
}
// 3. For UE element
main_loop: for( let ue of gstore.get.ues ){
// 3.1. Show by default
let element = document.querySelector('section[data-id=\''+ue.code+'\']');
if( !(element instanceof Element) )
continue;
element.remClass('filter-hidden');
// 3.2. If no filter -> let all visible
if( filter_ids.length <= 0 )
continue;
// 3.3. If at least one matching formatiom id -> let visible
for( let fid of filter_ids )
if( ue.formations.indexOf(fid) > -1 )
continue main_loop;
// XXXXX. If did not match -> hide
element.addClass('filter-hidden');
}
});
/* (3) Get Filters
---------------------------------------------------------*/
/* (2) Define filter group show/hide */
gstore.add('show_fgroup', function(gname){
var opened = gstore.get.filters[gname] != null && gstore.get.filters[gname][0].visible;
// {1} hide all by default//
for( var f in gstore.get.filters )
gstore.get.filters[f][0].visible = false;
// {2} If wrong @gname -> abort //
if( gstore.get.filters[gname] == null )
return;
// {3} Show selected filter //
gstore.get.filters[gname][0].visible = !opened;
});
/* (3) Define filter item toggle */
gstore.add('toggle_filter', function(gname, i){
// {1} If wrong @gname -> abort //
if( gstore.get.filters[gname] == null )
return;
// {2} If wrong @i -> abort //
if( gstore.get.filters[gname][i] == null )
return;
// {3} Toggle filter activation //
gstore.get.filters[gname][i].active = !gstore.get.filters[gname][i].active;
// {4} Update active table //
gstore.get.filters[gname][0].active.splice(0);
for( var f = 1 ; f < gstore.get.filters[gname].length ; f++ )
if( gstore.get.filters[gname][f].active )
gstore.get.filters[gname][0].active.push(f);
});
/* (2) Manage Instant Search (IS)
/* (4) Manage Instant Search (IS)
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Define global timeout index */ /* (1) Define global timeout index */
gstore.add('is_to', null); gstore.add('is_to', null);
@ -179,7 +76,8 @@ gstore.add('is_buf', null);
gstore.add('is_handler', function(e){ gstore.add('is_handler', function(e){
/* (1) Remove last timeout */ /* (1) Remove last timeout */
!isNaN(gstore.get.is_to) && clearTimeout(gstore.get.is_to); if( gstore.get.is_to != null )
clearTimeout(gstore.get.is_to);
/* (2) Store value in buffer */ /* (2) Store value in buffer */
gstore.get.is_buf = e.target.value.trim().toLowerCase(); gstore.get.is_buf = e.target.value.trim().toLowerCase();
@ -188,54 +86,26 @@ gstore.add('is_handler', function(e){
gstore.get.is_to = setTimeout(function(){ gstore.get.is_to = setTimeout(function(){
// 1. Fetch elements // 1. Fetch elements
let local_ptr = gstore.get.ues; var local_ptr = gstore.get.ues;
let l = gstore.get.ues.length; var l = gstore.get.ues.length;
let buf = gstore.get.is_buf.replace(/[.?*+^$[\]\\(\){}|-]/g, "\\$&"); // Escape errorful regex characters
// 2. For each element // 2. For each element
main_loop: for( let e = 0 ; e < l ; e++ ){ for( var e = 0 ; e < l ; e++ ){
// 2.1. Set visible by default // 2.1. Show by default
let element = document.querySelector('section[data-id=\''+local_ptr[e].code+'\']'); var element = document.querySelector('section[data-id=\''+local_ptr[e].code+'\']');
if( !element ) continue;
if( !(element instanceof Element) )
continue;
element.remClass('search-hidden'); element.remClass('search-hidden');
// 2.2. Empty text -> let visible // 2.2. Extract name components
if( buf.length == 0 ) var code = local_ptr[e].code.trim().toLowerCase();
continue; var label = local_ptr[e].label.trim().toLowerCase();
// 2.3. Extract name components // 2.3. Hide if does not match
let code = local_ptr[e].code.toLowerCase(); var match_offset = gstore.get.is_buf.length == 0 || code.search(gstore.get.is_buf) + label.search(gstore.get.is_buf);
let label = local_ptr[e].label.toLowerCase();
let forms = local_ptr[e].formations;
// 2.4-1. Match code -> let visible if( match_offset <= -2 )
if( code.search(buf) >= 0 )
continue;
// 2.4-2. Match label -> let visible
if( label.search(buf) >= 0 )
continue;
// 2.4-3. Check for each formation
for( let f of forms ){
let fetched_form = gstore.get.form_by_id(f);
// if formation not found -> ignore
if( fetched_form == null )
continue;
// if formation LABEL matches -> let visible
if( fetched_form.labelForm.toLowerCase().search(buf) >= 0 )
continue main_loop;
}
// XXXX. Hide all that did not match
element.addClass('search-hidden'); element.addClass('search-hidden');
} }
@ -263,19 +133,7 @@ gstore.add('create_vol', { c: '', td: '', tp: ''});
gstore.add('create_err_valid', false); gstore.add('create_err_valid', false);
gstore.add('create_err', ''); gstore.add('create_err', '');
/* (4) Define reset handler */ /* (4) Define create handler */
gstore.add('ic_reset', function(){
gstore.add('create_form', '-');
gstore.add('create_label', '');
gstore.add('create_code', '');
gstore.add('create_vol', { c: '', td: '', tp: ''});
gstore.add('create_err_valid', false);
gstore.add('create_err', '');
});
/* (5) Define create handler */
gstore.add('ic_handler', function(){ gstore.add('ic_handler', function(){
/* (4.1) Trim text input */ /* (4.1) Trim text input */
@ -646,9 +504,9 @@ gstore.add('ie_handler', function(ue_i){
/* (8) Manage instant toggle /* (8) Manage instant admin
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Define 'disabled' handler */ /* (1) Define admin handler */
gstore.add('ia_handler', function(ue_i){ gstore.add('ia_handler', function(ue_i){
/* (1) Abort if wrong ue_i */ /* (1) Abort if wrong ue_i */
@ -674,32 +532,6 @@ gstore.add('ia_handler', function(ue_i){
}); });
/* (1) Define 'required' / 'optional handler */
gstore.add('io_handler', function(ue_i){
/* (1) Abort if wrong ue_i */
if( ue_i == null || isNaN(ue_i) || gstore.get.ues[ue_i] == null)
return;
/* (2) Toggle current value */
var local = gstore.get.ues[ue_i];
var is_required = local.required == '1' || local.required === true;
var new_state = !is_required;
/* (3.1) Update in database */
api.call('PUT ue/'+local.code, { required: new_state }, function(rs){
/* (3.1.1) Abort on error */
if( rs.error !== 0 || rs.updated !== true )
return console.log('Impossible de changer le status \'requis\' / \'optionnel\', erreur '+rs.error);
/* (3.1.2) Success */
gstore.get.ues[ue_i].required = new_state ? 1 : 0;
});
});
/* (9) Manage 'manage' sub-page /* (9) Manage 'manage' sub-page
---------------------------------------------------------*/ ---------------------------------------------------------*/
@ -1078,66 +910,6 @@ gstore.add('upd_prof', function(type, res_i){
}); });
});
/* (4) Ordering filters */
gstore.add('order', {
available: ['prof', 'volume', 'forms'],
current: 0,
way: 1 // 1 ASC, -1 DESC
});
gstore.add('order_toggle', function(ord_i){
// 1. Check params types
if( isNaN(ord_i) || gstore.get.order.available[ord_i] == null )
return;
// 2. If new ordering field -> toggle it
if( ord_i !== gstore.get.order.current )
gstore.get.order.current = ord_i;
// 3. If already selected -> toggle way
else
gstore.get.order.way *= -1;
// 4. Get all elements to order
let els = document.querySelectorAll('section[data-prof][data-vol][data-form]');
// 5. Ordering by formations
if( gstore.get.order.current === 2 ){
return els.forEach((el) => {
el.style.order = el.getAttribute('data-form').split('|').length * gstore.get.order.way
});
}
// 6. Ordering by 'volume'
if( gstore.get.order.current === 1 )
return els.forEach((el) => {
el.style.order = parseInt( el.getAttribute('data-vol') ) * gstore.get.order.way
});
// 7. Ordering by 'prof'
els.forEach((el) => {
var profId = parseInt( el.getAttribute('data-prof') );
// outside by default if no prof set
el.style.order = - gstore.get.order.way;
// professors are already sorted
for( pi in gstore.get.manage.prof ) {
if( gstore.get.manage.prof[pi].idProfesseur == profId ){
el.style.order = pi * gstore.get.order.way;
break;
}
}
});
}); });
@ -1274,7 +1046,7 @@ gstore.add('ccreate', function(){
/* (4) Create request */ /* (4) Create request */
var rq = { var rq = {
code: gstore.get.router.history.current.path.split('/').pop(), code: gstore.get.URI[2],
volume: parseInt(vol) volume: parseInt(vol)
}; };
@ -1310,7 +1082,7 @@ gstore.add('ccreate', function(){
newRes[`id${restyp2}`] = rs.created_id; newRes[`id${restyp2}`] = rs.created_id;
newRes[`idProf`] = prof; newRes[`idProf`] = prof;
newRes[`volume`] = vol; newRes[`volume`] = vol;
newRes[`formations`] = rs.formations; newRes[`formations`] = [];
newRes[`add_form`] = '-'; newRes[`add_form`] = '-';
newRes[`new_prof`] = prof; newRes[`new_prof`] = prof;

View File

@ -43,7 +43,7 @@ window.cas_callback = function(cas_login){
// re-activate button // re-activate button
gstore.add('popup_opened', false); gstore.add('popup_opened', false);
setTimeout(function(){ gstore.get.login_class = 'neutral'; }, 3000); setTimeout(function(){ gstore.get.login_class = 'neutral'; }, 1500);
/* (4) If error code -> display error */ /* (4) If error code -> display error */
}else if( !isNaN(cas_login) ){ }else if( !isNaN(cas_login) ){
@ -71,7 +71,7 @@ window.cas_callback = function(cas_login){
// re-activate button // re-activate button
gstore.add('popup_opened', false); gstore.add('popup_opened', false);
setTimeout(function(){ gstore.get.login_class = 'neutral'; }, 3000); setTimeout(function(){ gstore.get.login_class = 'neutral'; }, 1500);
/* (4) If login -> reload page */ /* (4) If login -> reload page */
}else{ }else{
@ -81,7 +81,7 @@ window.cas_callback = function(cas_login){
var redirect_url = `/${gstore.get.URI.join('/')}`; var redirect_url = `/${gstore.get.URI.join('/')}`;
setTimeout(function(){ document.location = redirect_url; }, 3000); setTimeout(function(){ document.location = redirect_url; }, 1500);
} }

View File

@ -23,7 +23,6 @@ $rd-form-valid-color: '20d696';
$rd-form-neutral-color: 'b8c0c8'; $rd-form-neutral-color: 'b8c0c8';
$rd-form-search-color: '1d74e5'; $rd-form-search-color: '1d74e5';
$rd-form-invalid-color: 'ea4b35'; $rd-form-invalid-color: 'ea4b35';
$rd-form-primary-color: '54627c';
// Menu // Menu
$menu-bg: #333; $menu-bg: #333;

View File

@ -110,7 +110,7 @@
$btn-size: 1.8em; $btn-size: 1.8em;
$btn-space: 0em; $btn-space: 0em;
$nb-btn: 4; $nb-btn: 3;
$nb-spc: $nb-btn - 1; $nb-spc: $nb-btn - 1;
$cont-w: $btn-size * $nb-btn + $nb-spc * $btn-space; $cont-w: $btn-size * $nb-btn + $nb-spc * $btn-space;
@ -138,14 +138,12 @@
& > div.remove[data-remove], & > div.remove[data-remove],
& > div.edit[data-edit], & > div.edit[data-edit],
& > div.enabled[data-enabled], & > div.enabled[data-enabled],
& > div.required[data-required],
& > div.admin[data-admin]{ & > div.admin[data-admin]{
background-color: darken(#fff, 12%); background-color: darken(#fff, 12%);
/* (2.1.2) displace all but 1st element */ /* (2.1.2) displace all but 1st element */
&.edit[data-edit]{ left: calc( 100% - #{$btn-size * 2 + $btn-space} ); } &.edit[data-edit]{ left: calc( 100% - #{$btn-size * 2 + $btn-space} ); }
&.remove[data-remove]{ left: calc( 100% - #{$btn-size * 3 + $btn-space * 2} ); } &.remove[data-remove]{ left: calc( 100% - #{$btn-size * 3 + $btn-space * 2} ); }
&.required[data-required]{ left: calc( 100% - #{$btn-size * 4 + $btn-space * 3} ); }
} }
@ -155,7 +153,6 @@
& > div.remove[data-remove], & > div.remove[data-remove],
& > div.edit[data-edit], & > div.edit[data-edit],
& > div.enabled[data-enabled], & > div.enabled[data-enabled],
& > div.required[data-required],
& > div.admin[data-admin]{ & > div.admin[data-admin]{
display: inline-block; display: inline-block;
position: absolute; position: absolute;
@ -209,16 +206,6 @@
&[data-active='1']:hover{ background-image: url('/asset/svg/bell.svg@f4a118'); } &[data-active='1']:hover{ background-image: url('/asset/svg/bell.svg@f4a118'); }
} }
/* (2.4) REQUIRED switch */
&.required[data-required]{
background-image: url('/asset/svg/pin-disabled.svg@aaaaaa');
z-index: 104;
&:hover{ background-image: url('/asset/svg/pin-disabled.svg@555555'); }
&[data-active='1']{ background-image: url('/asset/svg/pin.svg@f4bd18'); }
&[data-active='1']:hover{ background-image: url('/asset/svg/pin.svg@f4a118'); }
}
} }
@ -284,8 +271,6 @@
color: darken($primary-color, 5%); color: darken($primary-color, 5%);
font-size: 1em; font-size: 1em;
margin: .4em 0;
// flex // flex
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
@ -374,16 +359,9 @@
align-items: center; align-items: center;
flex-wrap: nowrap; flex-wrap: nowrap;
&.little{
font-size: .7em;
white-space: nowrap;
}
/* (6.1) Column */ /* (6.1) Column */
& > div{ & > div{
flex: 1;
display: flex; display: flex;
position: relative; position: relative;
height: 2.3em; height: 2.3em;
@ -398,7 +376,7 @@
// flex properties // flex properties
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: space-between;
align-items: center; align-items: center;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -430,7 +408,7 @@
} }
/* (6.2) Column Emphasis */ /* (6.2) Column Emphasis */
& > span:last-child:not(.notlast){ & > span:last-child{
display: block; display: block;
position: relative; position: relative;
min-width: 4em; min-width: 4em;
@ -603,26 +581,7 @@
} }
/* (9) Infobar */
& > div.info{
display: block;
position: relative;
margin-top: 2.1em;
margin-left: -2.1em;
height: auto;
width: calc( 100% + 2*2.1em - 2*1em);
margin-bottom: -2.1em;
padding: .3em 1em;
border-top: 1px solid #f3f3f3;
background-color: darken(#fafbfd,1%);
font-size: .7em;
color: #bbb;
}
} }

View File

@ -22,8 +22,6 @@
/* (1) List element */ /* (1) List element */
& > section{ & > section{
order: -100000;
flex: 1 1 90%; flex: 1 1 90%;
display: flex; display: flex;
@ -45,15 +43,11 @@
/* (1.1) Element item */ /* (1.1) Element item */
& > div:not(.icon), & > div:not(.icon),
& > select,
& > input{ & > input{
flex: 0 1 30%; flex: 1 1 0;
// fix // fix
&.taglist{ &.taglist{ margin: 0; }
margin: 0;
margin-left: 1.5em;
}
} }
/* (1.2) Hover animation */ /* (1.2) Hover animation */
@ -66,16 +60,16 @@
&.create:hover{ border-left-color: $form-valid-color; } &.create:hover{ border-left-color: $form-valid-color; }
&:hover, &:hover,
&.bcours:hover{ border-left-color: $form-search-color; } &.cours:hover{ border-left-color: $form-search-color; }
&.btd:hover{ border-left-color: $form-valid-color; } &.td:hover{ border-left-color: $form-valid-color; }
&.btp:hover{ border-left-color: $form-invalid-color; } &.tp:hover{ border-left-color: $form-invalid-color; }
} }
/* (1.3) Select elements*/ /* (1.3) Select elements*/
& > select{ & > select{
display: block; display: inline-block;
position: relative; position: relative;
height: 1.8em; height: 1.8em;
@ -99,7 +93,7 @@
-moz-appearance: none; -moz-appearance: none;
appearance: none; appearance: none;
// flex: 0 1 15em; flex: 0 1 20em;
&.min{ flex: 0 1 5em; } &.min{ flex: 0 1 5em; }
@ -138,15 +132,13 @@
background-image: url('/asset/svg/cross.svg@aaaaaa'); background-image: url('/asset/svg/cross.svg@aaaaaa');
&:hover{ background-image: url('/asset/svg/cross.svg@#{$rd-form-invalid-color}'); } &:hover{ background-image: url('/asset/svg/cross.svg@#{$rd-form-invalid-color}'); }
} }
&.hidden{ background: transparent; }
} }
} }
/* (2) Filter */ /* (2) Filter */
& > section.filter{ & > section.filter{
// padding-bottom: 0;
background-color: transparent; background-color: transparent;
@ -157,37 +149,24 @@
font-weight: bold; font-weight: bold;
text-shadow: 1px 1px 2px #fff; text-shadow: 1px 1px 2px #fff;
& > div{ & > div:after{
content: '';
cursor: default;
& > span.arrow{
display: inline-block; display: inline-block;
position: relative; position: absolute;
width: 1.5em; width: 1.5em;
height: 1.5em; height: 1.5em;
margin-bottom: -.3em; margin-top: -.25em;
margin-left: .5em;
background: url() center center no-repeat; background: url('/asset/svg/down_arrow.svg@aaaaaa') center center no-repeat;
background-size: auto 100%; background-size: auto 100%;
cursor: pointer; &[data-filter='up']{ background-image: url('/asset/svg/up_arrow.svg@aaaaaa'); }
} }
// selected filter
&[data-filter='1']{
color: $primary-color;
& > span.arrow{ & > div.null:after{ content: none; }
&[data-way='-1']{ background-image: url('/asset/svg/up_arrow.svg@555555'); }
&[data-way='1']{ background-image: url('/asset/svg/down_arrow.svg@555555'); }
}
}
}
} }

View File

@ -12,8 +12,8 @@ $svg-lightpurple: #994499;
svg { svg {
width: 100%; width: 50em;
height: 30vh; height: 20em;
margin: 10px; margin: 10px;
-webkit-touch-callout: none; /* iOS Safari */ -webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */ -webkit-user-select: none; /* Safari */

View File

@ -13,8 +13,6 @@
@import 'global/tag'; @import 'global/tag';
.error, [data-error='1']{ font-weight: bold; color: $form-invalid-color; }
.success, [data-success='1']{ color: $form-valid-color; }
@ -57,97 +55,3 @@ a{
font-family: 'Mono'; font-family: 'Mono';
font-size: .9em; font-size: .9em;
} }
/* (8) Striked text */
[data-strike='1'],
.strike{
text-decoration: line-through;
opacity: .5;
}
/* (9) Icons (1em wide) */
.user-icon, .time-icon{
display: block;
position: relative;
width: 1em;
height: 1em;
background: url('/asset/svg/teacher.svg@#{$rd-form-neutral-color}') center center no-repeat;
background-size: contain;
&.time-icon{
background-image: url('/asset/svg/time.svg@#{$rd-form-neutral-color}');
}
}
/* (10) Toggling tooltip on hover */
[data-tooltip]{
position: relative;
cursor: pointer;
&:before{
content: attr(data-tooltip);
display: block;
position: absolute;
top: calc( 100% + 1em );
left: 50%;
margin-left: -.1em;
padding: .4em .6em;
border-radius: 3px / 3px;
box-shadow: 0 0 .5em 0 #fff;
font-size: .7em;
color: #ddd;
letter-spacing: 0;
background-color: #444;
transform: translateX(-50%) translateY(-50%) scale(0);
transition: transform .1s ease-in-out;
z-index: 999;
}
&:hover:not([data-tooltip='']):before{
transform: translateX(-50%) translateY(0) scale(1);
}
&:after{
content: '';
display: block;
position: absolute;
top: calc( 100% + .6em );
left: 50%;
width: .4em;
height: .4em;
background-color: #444;
transform: translateX(-50%) rotate(45deg) scale(0);
transition: transform .1s ease-in-out;
z-index: 1000;
}
&:hover:not([data-tooltip='']):after{
transform: translateX(-50%) rotate(45deg) scale(1);
}
}

View File

@ -4,13 +4,7 @@
/* (1) Warning icon */ /* (1) Warning icon */
.warning, .warning,
.user, .pin{
.time,
.pin,
.cm,
.back,
.td,
.tp{
// add icon before // add icon before
&:before{ &:before{
@ -27,30 +21,6 @@
background-size: auto 90%; background-size: auto 90%;
} }
&.nospace:before{
margin-right: 0;
}
&.reflow{
white-space: nowrap;
&:before{
font-size: 1.2em;
background-position: center bottom;
background-size: auto 70%;
}
}
&.big{
&:before{
font-size: 1.5em;
}
}
// icon color variants // icon color variants
&.neutral:before{ background-image: url('/asset/svg/warning.svg@#{$rd-form-neutral-color}'); } &.neutral:before{ background-image: url('/asset/svg/warning.svg@#{$rd-form-neutral-color}'); }
&.valid:before{ background-image: url('/asset/svg/warning.svg@#{$rd-form-valid-color}'); } &.valid:before{ background-image: url('/asset/svg/warning.svg@#{$rd-form-valid-color}'); }
@ -70,140 +40,12 @@
// add icon before // add icon before
&:before{ &:before{
background-image: url('/asset/svg/pin.svg@f4bd18'); background-image: url('/asset/svg/pin.svg@#{$rd-form-invalid-color}');
} }
// icon color variants // icon color variants
&.disabled:before{ background-image: url('/asset/svg/pin-disabled.svg@#{$rd-form-neutral-color}'); }
&.neutral:before{ background-image: url('/asset/svg/pin.svg@#{$rd-form-neutral-color}'); } &.neutral:before{ background-image: url('/asset/svg/pin.svg@#{$rd-form-neutral-color}'); }
&.valid:before{ background-image: url('/asset/svg/pin.svg@#{$rd-form-valid-color}'); } &.valid:before{ background-image: url('/asset/svg/pin.svg@#{$rd-form-valid-color}'); }
&.search:before{ background-image: url('/asset/svg/pin.svg@#{$rd-form-search-color}'); } &.search:before{ background-image: url('/asset/svg/pin.svg@#{$rd-form-search-color}'); }
} }
/* (3) CM */
.cm{
// add icon before
&:before{
background-image: url('/asset/svg/course.svg@#{$menu-item-inactive}');
}
&.active:before{ background-image: url('/asset/svg/course.svg@5bb8f0'); }
// icon color variants
&.neutral:before{ background-image: url('/asset/svg/course.svg@#{$rd-form-neutral-color}'); }
&.valid:before{ background-image: url('/asset/svg/course.svg@#{$rd-form-valid-color}'); }
&.search:before{ background-image: url('/asset/svg/course.svg@#{$rd-form-search-color}'); }
}
/* (4) TD */
.td{
// add icon before
&:before{
background-image: url('/asset/svg/td.svg@#{$menu-item-inactive}');
}
&.active:before{ background-image: url('/asset/svg/td.svg@20b565'); }
// icon color variants
&.neutral:before{ background-image: url('/asset/svg/td.svg@#{$rd-form-neutral-color}'); }
&.valid:before{ background-image: url('/asset/svg/td.svg@#{$rd-form-valid-color}'); }
&.search:before{ background-image: url('/asset/svg/td.svg@#{$rd-form-search-color}'); }
}
/* (5) TP */
.tp{
// add icon before
&:before{
background-image: url('/asset/svg/tp.svg@#{$menu-item-inactive}');
}
&.active:before{ background-image: url('/asset/svg/tp.svg@e85456'); }
// icon color variants
&.neutral:before{ background-image: url('/asset/svg/tp.svg@#{$rd-form-neutral-color}'); }
&.valid:before{ background-image: url('/asset/svg/tp.svg@#{$rd-form-valid-color}'); }
&.search:before{ background-image: url('/asset/svg/tp.svg@#{$rd-form-search-color}'); }
}
/* (6) USER */
.user{
// add icon before
&:before{
background-image: url('/asset/svg/teacher.svg@#{$menu-item-inactive}');
}
// icon color variants
&.neutral:before{ background-image: url('/asset/svg/teacher.svg@#{$rd-form-neutral-color}'); }
&.invalid:before{ background-image: url('/asset/svg/teacher.svg@#{$rd-form-invalid-color}'); }
&.valid:before{ background-image: url('/asset/svg/teacher.svg@#{$rd-form-valid-color}'); }
&.search:before{ background-image: url('/asset/svg/teacher.svg@#{$rd-form-search-color}'); }
}
/* (7) TIME */
.time{
// add icon before
&:before{
background-image: url('/asset/svg/time.svg@#{$menu-item-inactive}');
}
// icon color variants
&.neutral:before{ background-image: url('/asset/svg/time.svg@#{$rd-form-neutral-color}'); }
&.invalid:before{ background-image: url('/asset/svg/time.svg@#{$rd-form-invalid-color}'); }
&.valid:before{ background-image: url('/asset/svg/time.svg@#{$rd-form-valid-color}'); }
&.search:before{ background-image: url('/asset/svg/time.svg@#{$rd-form-search-color}'); }
}
/* (8) BACK */
.back{
// add icon before
&:before{
background-image: url('/asset/svg/back.svg@#{$menu-item-inactive}');
}
// icon color variants
&.neutral:before{ background-image: url('/asset/svg/back.svg@#{$rd-form-neutral-color}'); }
&.invalid:before{ background-image: url('/asset/svg/back.svg@#{$rd-form-invalid-color}'); }
&.valid:before{ background-image: url('/asset/svg/back.svg@#{$rd-form-valid-color}'); }
&.search:before{ background-image: url('/asset/svg/back.svg@#{$rd-form-search-color}'); }
// hover
&:hover:before{ background-image: url('/asset/svg/back.svg@ffffff'); }
}

View File

@ -22,12 +22,11 @@
z-index: 150; z-index: 150;
/* (1) left-side managers */ /* (1) Version management */
& > div.departments, & > div.departments,
& > div.versions, & > div.versions{
& > div.global-export{
/* (1.1) Current status */ /* (1.1) Version status */
& > div.current{ & > div.current{
display: block; display: block;
position: relative; position: relative;
@ -35,7 +34,8 @@
margin-left: 1em; margin-left: 1em;
padding: .5em 1em; padding: .5em 1em;
padding-left: .7em;
padding-left: 2em;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 3px; border-radius: 3px;
@ -48,79 +48,26 @@
// hover animation // hover animation
&:hover{ box-shadow: 0 2px 2px darken(#fff,10%); } &:hover{ box-shadow: 0 2px 2px darken(#fff,10%); }
// current: EXPORT / CREATE / EDIT / REMOVE icons // color state
span.export, &:before{
span.create, content: '';
span.edit,
span.remove{
display: inline-block;
position: relative;
top: .2em;
width: 1em;
height: 1em;
border-radius: 3px; display: block;
position: absolute;
top: calc( 50% - .7em/2 );
left: calc( 1em/2 + .7em/2 );
width: .7em;
height: .7em;
background: center center no-repeat; border-radius: 50%;
background-size: 80% auto;
&.export{ background-color: $form-invalid-color;
background-image: url('/asset/svg/fiche.svg@b8c0c8');
background-size: 100% auto;
&:hover{
background-image: url('/asset/svg/fiche.svg@#{$rd-form-invalid-color}');
}
} }
&.create{ &[data-id='-1']:before{
background-image: url('/asset/svg/plus.svg@b8c0c8'); background-color: $form-valid-color;
&:hover{
background-image: url('/asset/svg/plus.svg@#{$rd-form-valid-color}');
}
} }
&.edit{
background-image: url('/asset/svg/a.svg@b8c0c8');
&:hover{
background-image: url('/asset/svg/a.svg@#{$rd-form-search-color}');
}
}
&.remove{
background-image: url('/asset/svg/cross.svg@b8c0c8');
&:hover{
background-image: url('/asset/svg/cross.svg@#{$rd-form-invalid-color}');
}
}
&:last-child{
margin-right: .5em;
}
}
&:hover > span.export{
background-image: url('/asset/svg/fiche.svg@#{$rd-form-invalid-color}');
}
overflow: hidden;
// editable input
& > input[type='text']{
display: inline-block;
position: relative;
width: 100%;
max-width: 10em;
margin: 0;
padding: 0;
border: none;
border-radius: 0;
// background-color: #f00;
font-size: inherit;
color: inherit;
}
} }
@ -140,8 +87,6 @@
border-top: 0; border-top: 0;
border-radius: 0 0 3px 3px; border-radius: 0 0 3px 3px;
&>:first-child{ border-top: 1px solid #ddd; }
background-color: #fff; background-color: #fff;
// box-shadow: 0 2px 2px #ddd; // box-shadow: 0 2px 2px #ddd;
@ -166,29 +111,24 @@
// hover animation // hover animation
&:hover{ background-color: darken(#fff, 5%); } &:hover{ background-color: darken(#fff, 5%); }
// switch+create icons // color state
&:before{ &:before{
content: ''; content: '';
display: block; display: block;
position: absolute; position: absolute;
top: calc( 50% - 1em/2 ); top: calc( 50% - .7em/2 );
left: calc( .5em/2 + 1em/2 ); left: calc( 1em/2 + .7em/2 );
width: 1em; width: .7em;
height: 1em; height: .7em;
background: url('/asset/svg/switch.svg@#{$rd-form-primary-color}') center center no-repeat; border-radius: 50%;
background-size: auto 80%;
} background-color: $form-invalid-color;
// create icon specifications
&[data-id='-1']{
&:before{
background-image: url('/asset/svg/plus.svg@#{$rd-form-valid-color}');
background-size: auto 60%;
} }
&[data-id='-1']:before{
background-color: $form-valid-color;
} }
} }
@ -196,20 +136,16 @@
} }
/* (2) Department | Version | Export layout */ /* (2) Department | Version layout */
& > div.departments > div.current{ & > div.departments > div.current{
margin-right: 0; margin-right: 0;
padding-left: 1em; padding-left: 1em;
border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px;
&:before{ content: none; }
} }
& > div.versions > div.current{ & > div.versions > div.current{
margin-left: 0;
border-radius: 0;
border-left: 0;
}
& > div.global-export > div.current{
margin-left: 0; margin-left: 0;
border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0;
border-left: 0; border-left: 0;

View File

@ -281,13 +281,5 @@ body.body404{
} }
.downloadButton{
text-decoration: none;
color: #3f4a5e;
box-shadow: 0px 0px 1px 1px #7f8d9b;
background: whitesmoke;
padding: 10px;
border-radius: 2px;
}

View File

@ -5,15 +5,9 @@
<!-- Department management --> <!-- Department management -->
<div class='departments' data-unblur-department> <div class='departments' data-unblur-department>
<div class='current' data-unblur-department> <div class='current' @click='d_dialog=!d_dialog' data-unblur-department>{{ get_dcurrent().label || 'département à jour' }}</div>
<span class='create' @click='!department.create?(department.newLabel="")+(department.create=true):d_create()'></span> <div class='department-dialog' v-show='d_dialog' data-unblur-department>
<span class='remove' @click='d_remove()'></span> <span v-for='d in dpts' v-show='d.id!=dep_id' @click='d_switch(d.id)' data-unblur-department>{{ d.label }}</span>
<input v-if='department.create' type='text' placeholder='Nouveau nom' v-model='department.newLabel' size=''>
<span v-if='!department.create' @click='department.dialog=!department.dialog' data-unblur-department>{{ get_dcurrent().label }}</span>
</div>
<div class='department-dialog' v-show='department.dialog' data-unblur-department>
<span v-for='d in department.list' v-show='d.id!=department.current' @click='d_switch(d.id)' data-unblur-department>{{ d.label }}</span>
</div> </div>
</div> </div>
@ -21,27 +15,14 @@
<!-- Version management --> <!-- Version management -->
<div class='versions' data-unblur-version> <div class='versions' data-unblur-version>
<div class='current' :data-id='get_vcurrent().id' data-unblur-version> <div class='current' @click='v_dialog=!v_dialog' :data-id='get_vcurrent().id' data-unblur-version>{{ get_vcurrent().date || 'version à jour' }}</div>
<span class='remove' @click='v_remove()'></span> <div class='version-dialog' v-show='v_dialog' data-unblur-version>
<span class='edit' @click='!version.edit?(version.newName="")+(version.edit=true):v_edit()'></span> <span v-for='v in vers' v-show='v.id!=ver_id' @click='v_switch(v.id)' :data-id='v.id' data-unblur-version>{{ v.date || 'version à jour' }}</span>
<input v-if='version.edit' type='text' :placeholder='get_vcurrent().name' v-model='version.newName' size=''> <span @click='v_create()' data-unblur-version data-id='-1'>Nouvelle version</span>
<span v-if='!version.edit' @click='version.dialog=!version.dialog' data-unblur-version>{{ get_vcurrent().name }}</span>
</div>
<div class='version-dialog' v-show='version.dialog' data-unblur-version>
<span v-for='v in version.list' @click='v_switch(v.id)' v-show='v.id!=version.current' :data-id='v.id' data-unblur-version> {{ v.name }} </span>
<span @click='v_create()' data-unblur-version data-id='-1'>Créer</span>
</div> </div>
</div> </div>
<!-- <div class='header-title'>{{ gstore.header_title }}</div> -->
<!-- Export all -->
<div class='global-export'>
<div class='current export' @click='global_export()'>
<span class='export'></span>
exporter
</div>
</div>
</div> </div>
@ -56,21 +37,17 @@ export default {
gstore: gstore.get, gstore: gstore.get,
is_connected: _SERVER.session.connected, is_connected: _SERVER.session.connected,
department: { d_dialog: false,
dialog: false, dep_id: _SERVER.session.department_id,
current: _SERVER.session.department_id, dpts: _SERVER.session.departments,
list: _SERVER.session.departments,
create: false,
newLabel: ''
},
version: { v_dialog: false,
dialog: false, ver_id: -1,
current: -1, vers: [
list: [], { id: -1, date: null },
edit: false, { id: 0, date: '01-02-2017' },
newName: '' { id: 1, date: '23-03-2017' }
} ]
}; };
}, },
methods: { methods: {
@ -79,31 +56,31 @@ export default {
---------------------------------------------------------*/ ---------------------------------------------------------*/
get_dcurrent(id){ get_dcurrent(id){
// use @current, if invalid argument @id // use @dep_id, if invalid argument @id
( isNaN(id) ) && ( id = this.department.current ); ( isNaN(id) ) && ( id = this.dep_id );
// search in @list where id is @current // search in @dpts where id is @dep_id
for( var d in this.department.list ) for( var d in this.dpts )
if( this.department.list[d].id == id ) if( this.dpts[d].id == id )
return this.department.list[d]; return this.dpts[d];
return { id: -2, name: null }; return { id: null, label: null };
}, },
/* (2) Get current version data /* (2) Get current versoin data
---------------------------------------------------------*/ ---------------------------------------------------------*/
get_vcurrent(id){ get_vcurrent(id){
// use @version.current, if invalid argument @id // use @dep_id, if invalid argument @id
( isNaN(id) ) && ( id = this.version.current ); ( isNaN(id) ) && ( id = this.ver_id );
// search in @ist where id is @id // search in @vers where id is @ver_id
for( var v in this.version.list ) for( var v in this.vers )
if( this.version.list[v].id == id ) if( this.vers[v].id == id )
return this.version.list[v]; return this.vers[v];
return { id: -2, name: '-' }; return { date: null };
}, },
@ -112,11 +89,11 @@ export default {
d_switch(id){ d_switch(id){
// 1. De-activate dialogs // 1. De-activate dialogs
this.department.dialog = false; this.d_dialog = false;
this.version.dialog = false; this.v_dialog = false;
// 2. Do nothing if no change // 2. Do nothing if no change
if( this.department.current == id ) if( this.dep_id == id )
return; return;
// 3. Ask for department change // 3. Ask for department change
@ -127,7 +104,7 @@ export default {
return; return;
// 2. Update GUI // 2. Update GUI
this.department.current = id; this.dep_id = id;
// 3. Reload page if needed // 3. Reload page if needed
setTimeout(() => { document.location = ''; }, 200); setTimeout(() => { document.location = ''; }, 200);
@ -141,22 +118,28 @@ export default {
v_switch(id){ v_switch(id){
// 1. De-activate dialogs // 1. De-activate dialogs
this.department.dialog = false; this.d_dialog = false;
this.version.dialog = false; this.v_dialog = false;
// 2. Do nothing if no change // 2. Do nothing if no change
if( this.version.current == id ) if( this.ver_id == id )
return; return;
// 3. Ask for department change // 3. Get version date
api.call(`GET department/version/switch/${id}`, {}, function(rs){ var verdate = this.get_vcurrent(id).date;
// 4. If null date -> go to current version
( verdate === null ) && ( verdate = '' );
// 5. Ask for department change
api.call(`PUT department/version/0/${verdate}`, {}, function(rs){
// 1. error -> do nothing // 1. error -> do nothing
if( rs.error !== 0 ) if( rs.error !== 0 || rs.updated !== true )
return; return;
// 2. Update GUI // 2. Update GUI
this.version.current = id; this.ver_id = id;
// 3. Reload page if needed // 3. Reload page if needed
setTimeout(() => { document.location = ''; }, 200); setTimeout(() => { document.location = ''; }, 200);
@ -165,67 +148,13 @@ export default {
}, },
/* (5) Create a new empty department
---------------------------------------------------------*/
d_create(){
// 1. De-activate dialogs
this.department.dialog = false;
this.version.dialog = false;
// get current department
var cur = this.get_dcurrent();
if( cur.id < 0 || this.department.newLabel.length < 1 ){
this.department.create = false;
return;
}
var newlabel = this.department.newLabel;
// 2. Popup confirm
(new Promise( (resolve, reject) => {
popup.ask({
title: 'Confirmation de création de département',
content: `Le nouveau département <b>${newlabel}</b> va être créé; il ne contiendra aucune donnée, il permet de gérer plusieurs départements ne partageant pas les mêmes UEs, enseignants, formations, etc<br><br>Voulez-vous créer un nouveau département vide ?`,
action: 'Créer',
type: 'valid'
}, (popup_rs) => { popup_rs && resolve() });
// 3. On popup confirm
})).then( () => {
// Call API to create a new department
api.call(`POST department/`, {name:newlabel}, function(rs){
// 1. error -> popup
if( rs.error !== 0 || !rs.hasOwnProperty('created_id') ){
return popup.ask({
title: 'Erreur ('+rs.error+')',
content: 'La création de département a échoué.',
action: 'OK',
type: 'neutral'
}, () => {});
}
// 3. Update GUI
this.department.list.push( { id: parseInt(rs.created_id), name: newlabel } );
}.bind(this));
});
},
/* (5) Create a new version from now /* (5) Create a new version from now
---------------------------------------------------------*/ ---------------------------------------------------------*/
v_create(){ v_create(){
// 1. De-activate dialogs // 1. De-activate dialogs
this.department.dialog = false; this.d_dialog = false;
this.version.dialog = false; this.v_dialog = false;
// 2. Popup confirm // 2. Popup confirm
(new Promise( (resolve, reject) => { (new Promise( (resolve, reject) => {
@ -240,224 +169,34 @@ export default {
// 3. On popup confirm // 3. On popup confirm
})).then( () => { })).then( () => {
let newVersionName = `${this.get_vcurrent().name}*`;
// Call API to create a new version // Call API to create a new version
api.call(`POST department/version/`, {label:newVersionName}, function(rs){ api.call(`POST department/version/`, {}, function(rs){
// 1. error -> popup // 1. error -> popup
if( rs.error !== 0 || !rs.hasOwnProperty('created_id') ){ if( rs.error !== 0 || !rs.hasOwnProperty('created_id') ){
return popup.ask({ return popup.ask({
title: 'Erreur ('+rs.error+')', title: 'Error ('+err_code+')',
content: 'La création de version à échoué.', content: 'La création de sauvegarde à échoué.',
action: 'OK', action: 'OK',
type: 'neutral' type: 'neutral'
}, () => {}); }, () => {});
} }
// 2. Get last version id
var last_id = this.vers[ this.vers.length-1 ].id;
// 3. Update GUI // 3. Update GUI
this.version.list.push( { id: parseInt(rs.created_id), name: newVersionName } ); this.vers.push( { id: last_id+1, date: rs.created_id } );
}.bind(this)); }.bind(this));
});
},
/* (6) Rename a version
---------------------------------------------------------*/
v_edit(){
// get current version
var cur = this.get_vcurrent();
if( cur.id < 0 || this.version.newName.length < 1 ){
this.version.edit = false;
return;
}
var newname = this.version.newName;
// 2. Popup confirm
(new Promise( (resolve, reject) => {
popup.ask({
title: 'Confirmation de modification de version',
content: `La version <b>${cur.name}</b> va être renommée en <b>${newname}</b><br><br>Voulez-vous valider cette modification ?`,
action: 'Valider',
type: 'search'
}, (popup_rs) => { popup_rs && resolve() });
// 3. On popup confirm
})).then( () => {
// Call API to create a new version
api.call(`PUT department/version/${cur.id}`, {label:newname}, function(rs){
// 1. error -> popup
if( rs.error !== 0 || !rs.hasOwnProperty('updated') ){
return popup.ask({
title: 'Erreur ('+rs.error+')',
content: 'La modification a échoué.',
action: 'OK',
type: 'neutral'
}, () => {});
}
// 3. Update GUI
cur.name = newname;
}.bind(this));
}).finally( () => {
this.version.edit = false;
}) })
},
/* (7) Remove a department
---------------------------------------------------------*/
d_remove(){
// get current department
var cur = this.get_dcurrent();
if( cur.id < 0 )
return;
// if last department -> forbid
if( this.department.list.length < 2 ){
return popup.ask({
title: 'Dernier départment',
content: `Le département <b>${cur.label}</b> ne peut être supprimé car il est le dernier disponible`,
action: 'OK',
type: 'invalid'
});
} }
// 2. Popup confirm
(new Promise( (resolve, reject) => {
popup.ask({
title: 'Confirmation de suppression',
content: `Le département <b>${cur.label}</b> va être supprimé. Toutes les données seront perdues de manière définitive</b><br><br>Voulez-vous supprimer ce département ?`,
action: 'Supprimer',
type: 'invalid'
}, (popup_rs) => { popup_rs && resolve() });
// 3. On popup confirm
})).then( () => {
// Call API to delete the current department
api.call(`DELETE department/${cur.id}`, {}, function(rs){
// 1. error -> popup
if( rs.error !== 0 || !rs.hasOwnProperty('deleted') ){
return popup.ask({
title: 'Erreur ('+rs.error+')',
content: 'La suppression a échoué.',
action: 'OK',
type: 'neutral'
}, () => {});
}
// 3. Reload page
document.location = '';
}.bind(this));
});
}, },
/* (7) Remove a version
---------------------------------------------------------*/
v_remove(){
// get current version
var cur = this.get_vcurrent();
if( cur.id < 0 )
return;
// if last version -> forbid
if( this.version.list.length < 2 ){
return popup.ask({
title: 'Dernière version',
content: `La version <b>${cur.name}</b> ne peut être supprimée car il ne reste aucune autre version pour ce département`,
action: 'OK',
type: 'invalid'
});
}
// 2. Popup confirm
(new Promise( (resolve, reject) => {
popup.ask({
title: 'Confirmation de suppression',
content: `La version <b>${cur.name}</b> va être supprimée. Toutes les données seront perdues de manière définitive</b><br><br>Voulez-vous supprimer cette version ?`,
action: 'Supprimer',
type: 'invalid'
}, (popup_rs) => { popup_rs && resolve() });
// 3. On popup confirm
})).then( () => {
// Call API to create a new version
api.call(`DELETE department/version/${cur.id}`, {}, function(rs){
// 1. error -> popup
if( rs.error !== 0 || !rs.hasOwnProperty('deleted') ){
return popup.ask({
title: 'Erreur ('+rs.error+')',
content: 'La suppression a échoué.',
action: 'OK',
type: 'neutral'
}, () => {});
}
// 3. Reload page
document.location = '';
}.bind(this));
});
},
/* (x) Exports all data about this department's version
---------------------------------------------------------*/
global_export(){
api.call(`GET department/export`, {}, function(rs){
// 1. error -> popup
if( rs.error !== 0 || !rs.hasOwnProperty('link') ){
return popup.ask({
title: 'Erreur ('+rs.error+')',
content: 'L\'export a échoué.',
action: 'OK',
type: 'neutral'
}, () => {});
}
// 2. Launch download
document.location = rs.link;
}.bind(this));
}
},
beforeMount(){ beforeMount(){
/* (1) Try to fetch versions from API */ /* (1) Try to fetch versions from API */
@ -468,22 +207,21 @@ export default {
return; return;
// 2. Init version list // 2. Init version list
this.version.list = []; this.vers = [ { id: -1, date: null } ];
var idv = 0;
// 3. Store versions // 3. Store versions
for( var ver of rs.versions ){ for( var ver of rs.versions ){
// if current version -> set @version.current // if current version -> set @ver_id
if( _SERVER.session.version.current === ver.iddatabase ) if( _SERVER.session.version === ver )
this.version.current = ver.iddatabase this.ver_id = idv
// add version to list // add version to list
this.version.list.push( { id: ver.iddatabase, name: ver.label, new_name: ver.label } ); this.vers.push( { id: idv++, date: ver } );
} }
this.version
}.bind(this) ); }.bind(this) );
@ -493,11 +231,11 @@ export default {
// only hide not [data-unblur-department] elements // only hide not [data-unblur-department] elements
if( e.target.getAttribute('data-unblur-department') === null ) if( e.target.getAttribute('data-unblur-department') === null )
this.department.dialog = false; this.d_dialog = false;
// only hide not [data-unblur-version] elements // only hide not [data-unblur-version] elements
if( e.target.getAttribute('data-unblur-version') === null ) if( e.target.getAttribute('data-unblur-version') === null )
this.version.dialog = false; this.v_dialog = false;
}); });