Compare commits

...

20 Commits

Author SHA1 Message Date
Adrien Marquès 177752fdc4 npm packages update 2018-06-09 15:26:17 +02:00
Adrien Marquès 782d2084ca fix http vs. https for CAS service (redirection) 2018-06-09 15:08:46 +02:00
Adrien Marquès 047efa100c update package (vue-template-compiler) 2018-06-09 14:58:04 +02:00
Adrien Marquès 8bd98484aa make login HOST generic 2018-06-09 12:22:20 +02:00
Adrien Marquès 47c90d8737 add dedicated page 'fiche' for teachers only (not 'cas_admin') + router management + add logout btn 2018-05-17 15:16:30 +02:00
xdrm-brackets 1bfd97009e fix [modules.json] format + fix 'teacher/pdf' to return data even if no formation is found (+remove dumb data from pdf) 2018-05-14 12:03:11 +02:00
xdrm-brackets cfb9e0df23 remove page 'fiche' 2018-05-14 11:56:11 +02:00
Unknown 8f909821b6 add version delete/update restrictions 2018-05-14 01:03:18 +02:00
Unknown 24b0bb3798 Implement non-admin user pdf download 2018-05-14 00:57:57 +02:00
Unknown 9dea19b9b1 Fix version update 2018-05-13 23:41:32 +02:00
xdrm-brackets edbd2da4eb Merge branch 'master' of https://git.xdrm.io/ptut/vhost 2018-05-12 16:48:13 +02:00
xdrm-brackets 799116d1a4 remove debug 2018-05-12 16:48:07 +02:00
xdrm-brackets f62674cb0b fix export extension 2018-05-12 16:46:23 +02:00
xdrm-brackets 50f99f6a44 fix export extension 2018-05-12 16:45:47 +02:00
xdrm-brackets c52893ffd6 added global department's version export 2018-05-12 16:42:49 +02:00
xdrm-brackets 56eb72ac55 department/export now uses the download system 2018-05-12 16:42:28 +02:00
xdrm-brackets 9093ce2d38 department.create/delete(unimplemented server-side)/switch 2018-05-12 16:17:27 +02:00
Unknown a745daa506 Add fiche download auth check 2018-05-10 15:43:02 +02:00
Unknown e9579c8956 Implemented Excel export of version 2018-05-10 15:09:40 +02:00
Unknown 6af33306af Merge branch 'verions-new' 2018-05-10 12:37:51 +02:00
18 changed files with 537 additions and 9553 deletions

View File

@ -100,7 +100,7 @@ class casController{
/* (2) Check ticket (validate)
---------------------------------------------------------*/
/* (1) Build useful variables */
$service = ($_SERVER['SERVER_NAME'] == 'ptut.com' ) ? 'http' : 'https';
$service = ($_SERVER['SERVER_PORT'] == 80) ? 'http' : 'https';
$service .= '://'.$_SERVER['HTTP_HOST'].'/api/v/1.0/cas/'.$popup_mode;
$ticket = urlencode($_GET['ticket']);
$validate_url = "https://sso.univ-pau.fr/cas/serviceValidate?ticket=$ticket&service=$service";
@ -259,4 +259,4 @@ class casController{
}
}
}

View File

@ -0,0 +1,182 @@
<?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

@ -155,9 +155,9 @@ class departmentController
//update user session
$departments = $metaRepo->get_prof_departments($user["casLogin"]);
$_SESSION['AvailableDepartments'] = $departments;
//we are good now
return ["success" => true];
return [];
}

View File

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

View File

@ -49,7 +49,11 @@ class PDOWrapper extends \PDO
if($this->stacking){
return new PDOStatementWrapper($statement, $this);
}else{
return parent::prepare($statement, $options);
$st = parent::prepare($statement, $options);
if($st === false){
throw new \PDOException("There is an error in your SQL statement");
}
return $st;
}
}

View File

@ -262,7 +262,7 @@ class meta extends Repo_i {
$versionData = $st->fetch();
if( !is_array($versionData) ){
if( !is_array($versionData) || $versionData["default"] == 1){
return false;
}
@ -306,6 +306,12 @@ class meta extends Repo_i {
}
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 = [];
@ -315,8 +321,15 @@ class meta extends Repo_i {
}
if($default != null){
$set .= "default=:default,";
$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,",");

View File

@ -290,4 +290,13 @@ class ue extends Repo_i {
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,19 +33,43 @@
}
/* (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";
/* (2) If page does not exist -> 404 */
/* (4) If page does not exist -> 404 */
if( !file_exists($page_fname) )
include __PUBLIC__.'/page/404.php';
/* (3) Set URI arguments */
/* (5) Set URI arguments */
$_GET['uri'] = explode('/', $this->uri);
/* (4) Load page */
/* (6) Load page */
include __PUBLIC__."/page/".$this->pagename.".php";
}

View File

@ -96,7 +96,7 @@
"par": {
"URL0": {"des": "Department id", "typ": "id", "ren": "department" }
},
"output": {
"out": {
"switched": { "des": "Whether the department has been switched", "typ": "bool" }
}
@ -117,6 +117,14 @@
}
}
},
"export":{
"GET": {
"des": "Export the data of the current department and version to a Excel file",
"per": [["cas_admin"]],
"par": {},
"opt": { "download": true }
}
},
"version":{
"switch":{
"GET": {
@ -125,7 +133,7 @@
"par": {
"URL0": { "des": "The version id", "typ": "id", "ren": "version" }
},
"output": {
"out": {
"sucess": { "des": "success of the operation", "typ": "bool" }
}
}
@ -134,7 +142,7 @@
"des": "Get the list of the versions of the department",
"per": [["cas_admin"]],
"par": {},
"output": {
"out": {
"versions": { "des": "List of available versions", "typ": "array" }
}
},
@ -142,9 +150,9 @@
"des": "Create a backup if the name is empty, execute the backup if the name is set",
"per": [["cas_admin"]],
"par": {
"label": { "des": "Label of the version","typ": "text"}
"label": { "des": "Label of the version", "typ": "text" }
},
"output": {
"out": {
"created_id": { "des": "The id of the created version", "typ": "varchar(10,10,alphanumeric)" }
}
},
@ -152,11 +160,11 @@
"des": "Update a version and switch to this version",
"per": [["cas_admin"]],
"par": {
"URL0": { "des": "id of the version","typ": "id","ren": "version"},
"label" : { "des": "Label de la version", "typ": "text", "opt":true},
"default": { "des": "true if this version is the one that should be used by default on login", "typ": "bool","opt":true}
"URL0": { "des": "id of the version", "typ": "id", "ren": "version" },
"label": { "des": "Label de la version", "typ": "text", "opt": true },
"default": { "des": "Whether this version should be used on login", "typ": "bool", "opt": true }
},
"output": {
"out": {
"updated": { "des": "Whether the version has been switched|applied", "typ": "bool" }
}
},
@ -166,7 +174,7 @@
"par": {
"URL0": { "des": "The version id", "typ": "id", "ren": "version" }
},
"output": {
"out": {
"deleted": { "des": "Whether the version has been deleted", "typ": "bool" }
}
}
@ -253,7 +261,7 @@
"GET": {
"des": "Get a professor's fiche",
"per": [["cas_admin"]],
"per": [["cas_admin"], ["cas_user"]],
"par": {
"URL0": { "des": "Optional professor UID.", "typ": "id", "ren": "prof_id" }
},
@ -338,7 +346,7 @@
"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": [] }
},
"output": {
"out": {
"created_id" : { "des": "The id of the created Cours", "typ": "id" },
"formations" : { "des": "The ids of the linked formations", "typ": "array<id>" }
}
@ -362,7 +370,7 @@
"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": [] }
},
"output": {
"out": {
"updated" : { "des": "Whether it has been updated", "typ": "bool" }
}
},
@ -373,7 +381,7 @@
"par": {
"URL0": { "des": "Id of the Cours", "typ": "id", "ren": "idCours" }
},
"output": {
"out": {
"deleted" : { "des": "Whether it has been deleted", "typ": "bool" }
}
}
@ -391,7 +399,7 @@
"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": [] }
},
"output": {
"out": {
"created_id" : { "des": "The id of the created TD", "typ": "id" },
"formations" : { "des": "The ids of the linked formations", "typ": "array<id>" }
}
@ -415,7 +423,7 @@
"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": [] }
},
"output": {
"out": {
"updated" : { "des": "Whether it has been updated", "typ": "bool" }
}
},
@ -426,7 +434,7 @@
"par": {
"URL0": { "des": "Id of the TD", "typ": "id", "ren": "idTD" }
},
"output": {
"out": {
"deleted" : { "des": "Whether it has been deleted", "typ": "bool" }
}
}
@ -444,7 +452,7 @@
"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": [] }
},
"output": {
"out": {
"created_id" : { "des": "The id of the created TP", "typ": "id" },
"formations" : { "des": "The ids of the linked formations", "typ": "array<id>" }
}
@ -468,7 +476,7 @@
"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": [] }
},
"output": {
"out": {
"updated" : { "des": "Whether it has been updated", "typ": "bool" }
}
},
@ -479,7 +487,7 @@
"par": {
"URL0": { "des": "Id of the TP", "typ": "id", "ren": "idTP" }
},
"output": {
"out": {
"deleted" : { "des": "Whether it has been deleted", "typ": "bool" }
}
}

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",
"sass-loader": "^6.0.6",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.5.9",
"vue-template-compiler": "^2.5.16",
"webpack": "^3.8.1",
"webpack-dev-server": "^2.9.5"
}

View File

@ -7,42 +7,29 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Gestion des enseignants</title>
<title>Espace enseignant</title>
<!-- Icon -->
<link rel='shortcut icon' href='/favicon.ico'>
<!-- Icon -->
<link rel='shortcut icon' href='/favicon.ico'>
<!-- CSS dependencies -->
<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/menu.css'>
<link rel='stylesheet' type='text/css' href='/css/header.css'>
<link rel='stylesheet' type='text/css' href='/css/container.css'>
<!-- CSS dependencies -->
<link href="https://fonts.googleapis.com/css?family=Fira+Sans" rel="stylesheet">
<link rel='stylesheet' type='text/css' href='/css/layout.css'>
<!-- JS dependencies -->
<script type='text/javascript' src='/js/_SERVER.js'></script>
<body>
</head>
<body class='loading'>
<div id="WRAPPER" class='login'>
<div id='main-vue'></div>
<!-- POPUP WINDOW -->
<div id='POPUP'>
<div class='header'></div>
<div class='body'></div>
<div class='footer'></div>
<div id='LOGIN_REDIRECT'>
<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>
</div>
<div id='POPUP-BG'></div>
<!-- Main loop -->
<script type='text/javascript' src='/js/bundle@fiche.js' onload="document.body.className=''"></script>
</div>
</body>
</html>

View File

@ -7,24 +7,24 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>PTUT web title</title>
<title>Connexion</title>
<!-- Icon -->
<link rel='shortcut icon' href='/favicon.ico'>
<!-- Icon -->
<link rel='shortcut icon' href='/favicon.ico'>
<!-- CSS dependencies -->
<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/menu.css'>
<link rel='stylesheet' type='text/css' href='/css/header.css'>
<link rel='stylesheet' type='text/css' href='/css/container.css'>
<link rel='stylesheet' type='text/css' href='/css/container/svg.css'>
<!-- CSS dependencies -->
<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/menu.css'>
<link rel='stylesheet' type='text/css' href='/css/header.css'>
<link rel='stylesheet' type='text/css' href='/css/container.css'>
<link rel='stylesheet' type='text/css' href='/css/container/svg.css'>
<!-- JS dependencies -->
<script type='text/javascript' src='/js/_SERVER.js'></script>
<!-- JS dependencies -->
<script type='text/javascript' src='/js/_SERVER.js'></script>
</head>
<body class='loading'>
@ -46,4 +46,5 @@
<!-- Main loop -->
<script type='text/javascript' src='/js/bundle@home.js' onload="document.body.className=''"></script>
</body>
</html>

View File

@ -72,18 +72,6 @@ module.exports = [ {
module: mod_common,
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",

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');
/* (4) API instance */
window.api = new APIClient(gstore.get.is_local ? 'http://ptut.com:8080/api/v/1.0/' : 'https://ptut.xdrm.io/api/v/1.0/');
window.api = new APIClient(gstore.get.is_local ? 'http://ptut.com:8080/api/v/1.0/' : `${gstore.get.HOST}/api/v/1.0/`);
/* (5) PopUp instance */
window.popup = new PopUp();
@ -49,10 +49,6 @@ gstore.add('menu_item', {
label: 'Gestion UE',
url: 'ue',
icon: 'ue'
}, fiche: {
label: 'Fiches',
url: 'fiche',
icon: 'fiche'
}, settings: {
label: 'Administration',
url: 'settings',

View File

@ -22,11 +22,12 @@
z-index: 150;
/* (1) Version management */
/* (1) left-side managers */
& > div.departments,
& > div.versions{
& > div.versions,
& > div.global-export{
/* (1.1) Version status */
/* (1.1) Current status */
& > div.current{
display: block;
position: relative;
@ -34,6 +35,7 @@
margin-left: 1em;
padding: .5em 1em;
padding-left: .7em;
border: 1px solid #ddd;
border-radius: 3px;
@ -46,24 +48,37 @@
// hover animation
&:hover{ box-shadow: 0 2px 2px darken(#fff,10%); }
}
// current version: EDIT + REMOVE
&.versions > div.current{
// current: EXPORT / CREATE / EDIT / REMOVE icons
span.export,
span.create,
span.edit,
span.remove{
display: inline-block;
position: relative;
top: .2em;
width: 1.1em;
height: 1.1em;
width: 1em;
height: 1em;
border-radius: 3px;
background: center center no-repeat;
background-size: 80% auto;
&.export{
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{
background-image: url('/asset/svg/plus.svg@b8c0c8');
&:hover{
background-image: url('/asset/svg/plus.svg@#{$rd-form-valid-color}');
}
}
&.edit{
background-image: url('/asset/svg/a.svg@b8c0c8');
&:hover{
@ -82,6 +97,10 @@
margin-right: .5em;
}
}
&:hover > span.export{
background-image: url('/asset/svg/fiche.svg@#{$rd-form-invalid-color}');
}
overflow: hidden;
// editable input
@ -177,16 +196,20 @@
}
/* (2) Department | Version layout */
/* (2) Department | Version | Export layout */
& > div.departments > div.current{
margin-right: 0;
padding-left: 1em;
border-radius: 3px 0 0 3px;
&:before{ content: none; }
}
& > div.versions > div.current{
margin-left: 0;
border-radius: 0;
border-left: 0;
}
& > div.global-export > div.current{
margin-left: 0;
border-radius: 0 3px 3px 0;
border-left: 0;

View File

@ -281,5 +281,13 @@ 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,9 +5,15 @@
<!-- Department management -->
<div class='departments' data-unblur-department>
<div class='current' @click='d_dialog=!d_dialog' data-unblur-department>{{ get_dcurrent().label || 'département à jour' }}</div>
<div class='department-dialog' v-show='d_dialog' data-unblur-department>
<span v-for='d in dpts' v-show='d.id!=dep_id' @click='d_switch(d.id)' data-unblur-department>{{ d.label }}</span>
<div class='current' data-unblur-department>
<span class='create' @click='!department.create?(department.newLabel="")+(department.create=true):d_create()'></span>
<span class='remove' @click='d_remove()'></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>
@ -28,7 +34,14 @@
</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>
@ -43,9 +56,13 @@ export default {
gstore: gstore.get,
is_connected: _SERVER.session.connected,
d_dialog: false,
dep_id: _SERVER.session.department_id,
dpts: _SERVER.session.departments,
department: {
dialog: false,
current: _SERVER.session.department_id,
list: _SERVER.session.departments,
create: false,
newLabel: ''
},
version: {
dialog: false,
@ -62,15 +79,15 @@ export default {
---------------------------------------------------------*/
get_dcurrent(id){
// use @dep_id, if invalid argument @id
( isNaN(id) ) && ( id = this.dep_id );
// use @current, if invalid argument @id
( isNaN(id) ) && ( id = this.department.current );
// search in @dpts where id is @dep_id
for( var d in this.dpts )
if( this.dpts[d].id == id )
return this.dpts[d];
// search in @list where id is @current
for( var d in this.department.list )
if( this.department.list[d].id == id )
return this.department.list[d];
return { id: null, label: null };
return { id: -2, name: null };
},
@ -95,11 +112,11 @@ export default {
d_switch(id){
// 1. De-activate dialogs
this.d_dialog = false;
this.department.dialog = false;
this.version.dialog = false;
// 2. Do nothing if no change
if( this.dep_id == id )
if( this.department.current == id )
return;
// 3. Ask for department change
@ -110,7 +127,7 @@ export default {
return;
// 2. Update GUI
this.dep_id = id;
this.department.current = id;
// 3. Reload page if needed
setTimeout(() => { document.location = ''; }, 200);
@ -124,7 +141,7 @@ export default {
v_switch(id){
// 1. De-activate dialogs
this.d_dialog = false;
this.department.dialog = false;
this.version.dialog = false;
// 2. Do nothing if no change
@ -148,12 +165,66 @@ 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
---------------------------------------------------------*/
v_create(){
// 1. De-activate dialogs
this.d_dialog = false;
this.department.dialog = false;
this.version.dialog = false;
// 2. Popup confirm
@ -186,7 +257,7 @@ export default {
}
// 3. Update GUI
this.version.list.push( { id: parseInt(rs.created_id), name: newVersionName, new_name: newVersionName } );
this.version.list.push( { id: parseInt(rs.created_id), name: newVersionName } );
}.bind(this));
@ -246,6 +317,62 @@ export default {
},
/* (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(){
@ -300,8 +427,35 @@ export default {
});
},
/* (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(){
@ -339,7 +493,7 @@ export default {
// only hide not [data-unblur-department] elements
if( e.target.getAttribute('data-unblur-department') === null )
this.d_dialog = false;
this.department.dialog = false;
// only hide not [data-unblur-version] elements
if( e.target.getAttribute('data-unblur-version') === null )