...
 
Commits (30)
# Create user and db
sql/db_init.sh (edit password first)
# PostgreSQL
# Connect
## Add external data
add student.csv to data
## Create user and db
sudo su postgres
sql/db_init.sh password
## Test
psql -h localhost -U apisub -d apisub
# PHP
On Ubuntu, add XML lib to PHP
## Install
apt install php-pgsql
apt install php-xml
## Connexion
cp lib/connexion-sample.php lib/connexion.php
<?php
if (!isset($_GET['api'])) {
header('Location:index.php');
}
else {
session_start();
include 'lib/cas_connect.php';
include 'lib/db.php';
include 'lib/views.php';
include 'lib/admin.php';
$db = new DB();
$admin = new Admin($db);
$view = new Views($admin, $_SESSION['utclogin'], $_SESSION['surname'], $_SESSION['firstname']);
$view->printHtmlBegin($admin);
$view->printUser($db->isResp($_SESSION['utclogin']), $db->isAdmin($_SESSION['utclogin']));
$view->apiStudents($db->apiStudents($_SESSION['utclogin'],$_GET['api']));
}
?>
body {
color:#393939;
}
.user .name {
font-weight:bold;
}
.user .login {
font-style:italic;
}
.menu {
margin-top:5pt;
}
.menu a {
text-decoration:none;
color:#1d007a;
font-weight:bold;
}
a {
text-decoration:none;
color:black;
}
hr {
border-top: 1.5px solid black;
}
.goldenrule {
font-weight:bold;
color:#8e3c00;
font-size:150%;
}
.sub {
text-decoration:none;
font-weight:bold;
color:#00612b;
}
.unsub {
text-decoration:none;
font-weight:bold;
color:#8e3c00;
}
.valid {
text-decoration:none;
font-weight:bold;
color:#790600;
}
*
!.gitignore
<?php
session_start();
if (!isset($_SESSION['ticket'])) {
/* If session is already open for current PHP file, user is already logged in, do nothing
If session is not open on current PHP file, check if it is open on CAS server
If it is open on CAS server retrieve session informations
If it is not on open on CAS server, ask for login to CAS server
*/
include $_SERVER['DOCUMENT_ROOT'].'/apisub/lib/cas.php';
$cas = new CAS('https://cas.utc.fr/cas/','http');
$info = $cas->authenticate();
if ($info != -1) {
$_SESSION['ticket'] = $_GET['ticket'];
$_SESSION['utclogin'] = $info['cas:user'];
$_SESSION['mail'] = $info['cas:attributes']['cas:mail'];
$_SESSION['surname'] = strtoupper($info['cas:attributes']['cas:sn']);
$_SESSION['firstname'] = $info['cas:attributes']['cas:givenName'];
}
else {
$cas->login();
}
$_SESSION['localcopy'] = true; //call localcopy once per session
}
include 'lib/cas_connect.php';
include 'lib/db.php';
include 'lib/views.php';
include 'lib/admin.php';
$db = new DB();
if ($_SESSION['localcopy']) {
//if ($_SESSION['localcopy']) {
$db->copyUser($_SESSION['utclogin'], $_SESSION['surname'], $_SESSION['firstname'], $_SESSION['mail']);
$_SESSION['localcopy']=false;
}
//}
$admin = new Admin($db);
$view = new Views($admin, $_SESSION['utclogin'], $_SESSION['surname'], $_SESSION['firstname']);
$view->printHtmlBegin();
$view->printHtmlBegin($admin);
$view->printUser($db->isResp($_SESSION['utclogin']), $db->isAdmin($_SESSION['utclogin']));
$view->printInstructions($db->config());
/** Subscription and unsubscription management **/
if (isset($_GET['api']) && $admin->isActive()) {
if (isset($_GET['action'])) {
if ($_GET['action']=='sub') {
$db->subToApi($_SESSION['utclogin'], $_GET['api']);
if (isset($_GET['mode'])) {
if ($_GET['mode']=='resp') {
if (isset($_GET['action']) && isset($_GET['api']) && isset($_GET['login'])) {
if ($_GET['action']=='validate') {
$db->validate($_SESSION['utclogin'], $_GET['api'], $_GET['login']);
}
}
elseif ($_GET['action']=='unsub') {
$db->unsubToApi($_SESSION['utclogin'], $_GET['api']);
$view->respValidation($db->apiListResp($admin, $_SESSION['utclogin']));
}
if ($_GET['mode']=='admin') {
$view->adminFunction($_SESSION['utclogin']);
}
}
else {
/** Subscription and unsubscription management **/
if (isset($_GET['api']) && $admin->isActive()) {
if (isset($_GET['action'])) {
if ($_GET['action']=='sub') {
$db->subToApi($admin, $_SESSION['utclogin'], $_GET['api']);
}
elseif ($_GET['action']=='unsub') {
$db->unsubToApi($_SESSION['utclogin'], $_GET['api']);
}
}
}
$view->printInstructions($db->config());
$view->printSubList($db->subList($_SESSION['utclogin']));
$view->printApiList($db->apiList($admin, $_SESSION['utclogin']));
}
$view->printSubList($db->subList($_SESSION['utclogin']));
$view->printApiList($db->apiList('E', 2019), $_SESSION['utclogin']);
?>
function download_csv(students) {
var csv = '';
students.forEach(function(row) {
csv += row.join(',');
csv += "\n";
});
console.log(csv);
var a = document.getElementById('csvlink');
a.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
a.target = '_blank';
a.download = 'people.csv';
a.click();
}
<?php
const IS_ACTIVE = true;
class Admin {
......@@ -13,4 +12,12 @@ class Admin {
return $this->db->config()['isactive'];
}
public function activeSemester() {
return 'E';
}
public function activeYear() {
return 2019;
}
}
<?php
session_start();
if (!isset($_SESSION['login'])) {
if (!isset($_SESSION['ticket'])) {
/* If session is already open for current PHP file, user is already logged in, do nothing
If session is not open on current PHP file, check if it is open on CAS server
If it is open on CAS server retrieve session informations
If it is not on open on CAS server, ask for login to CAS server
*/
include $_SERVER['DOCUMENT_ROOT'].'/apisub/lib/cas.php';
$info = CAS::authenticate();
include 'lib/cas.php';
$cas = new CAS('https://cas.utc.fr/cas/','http');
$info = $cas->authenticate();
if ($info != -1) {
$_SESSION['ticket'] = $_GET['ticket'];
$_SESSION['utclogin'] = $info['cas:user'];
......@@ -17,9 +16,9 @@ if (!isset($_SESSION['login'])) {
$_SESSION['surname'] = strtoupper($info['cas:attributes']['cas:sn']);
$_SESSION['firstname'] = $info['cas:attributes']['cas:givenName'];
}
else
CAS::login();
else {
$cas->login();
}
$_SESSION['localcopy'] = true; //call localcopy once per session
}
echo $_SESSION['ticket']." ".$_SESSION['utclogin']
?>
......@@ -16,7 +16,8 @@ class DB {
public function subList($utclogin) {
$sql = 'SELECT *
FROM vsubscription
WHERE utclogin=:utclogin';
WHERE utclogin=:utclogin
AND (validation OR validation IS NULL)';
$st = $this->conn->prepare($sql);
$st->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st->execute();
......@@ -24,31 +25,52 @@ class DB {
return $res;
}
public function apiList($semester, $year) {
$sql = 'SELECT *
public function apiList($admin, $utclogin) {
$sql = 'SELECT *, is_available(:utclogin, week, year) AS is_available
FROM vapi
WHERE semester=:semester AND year=:year';
$st = $this->conn->prepare($sql);
$st->bindValue(':semester',$semester,PDO::PARAM_STR);
$st->bindValue(':year',$year,PDO::PARAM_INT);
$st->bindValue(':semester',$admin->activeSemester(),PDO::PARAM_STR);
$st->bindValue(':year',$admin->activeYear(),PDO::PARAM_INT);
$st->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st->execute();
$res = $st->fetchAll(PDO::FETCH_ASSOC);
return $res;
}
public function subToApi($utclogin, $api) {
$today = date('Ymd');
$sql = 'INSERT INTO subscribe(utclogin, api, subdate) VALUES (:utclogin, :api, :today)';
public function subToApi($admin, $utclogin, $api) {
// Case 1 : Student had not yet subscribe to this Api and no other Api is validated same week, insertion expected to work
// Case 2 : Student had already subscribe to this Api, key constraint will prevent from adding new record, so, if subscription has been unvalidated it will remain so AND is_available test will block inserting before previous rule anyway
// Case 3 : Student had not subscribe to this Api, but another Api has been validated same week, insertion expected to fail (test with is_avaiblable)
$sql = 'SELECT is_available(:utclogin, week, year) AS is_available
FROM vapi
WHERE semester=:semester AND year=:year AND id=:api' ;
$st = $this->conn->prepare($sql);
$st->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st->bindValue(':api',$api,PDO::PARAM_INT);
$st->bindValue(':today',$today,PDO::PARAM_STR);
$res = $st->execute();
return $res;
$st->bindValue(':semester',$admin->activeSemester(),PDO::PARAM_STR);
$st->bindValue(':year',$admin->activeYear(),PDO::PARAM_INT);
$st->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st->execute();
$res = $st->fetch(PDO::FETCH_ASSOC);
if ($res['is_available']) {
$today = date('Ymd');
$sql = 'INSERT INTO subscribe(utclogin, api, subdate) VALUES (:utclogin, :api, :today)';
$st = $this->conn->prepare($sql);
$st->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st->bindValue(':api',$api,PDO::PARAM_INT);
$st->bindValue(':today',$today,PDO::PARAM_STR);
$res = $st->execute();
return $res;
}
else {
return null;
}
}
public function unsubToApi($utclogin, $api) {
$sql = 'DELETE FROM subscribe WHERE utclogin=:utclogin AND api=:api';
#TODO add superpower to unsubscribe if admin
/** Testing validation IS NULL prevent from unsubscribing to validated Api **/
$sql = 'DELETE FROM subscribe WHERE utclogin=:utclogin AND api=:api AND validation IS NULL';
$st = $this->conn->prepare($sql);
$st->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st->bindValue(':api',$api,PDO::PARAM_INT);
......@@ -57,25 +79,29 @@ class DB {
}
public function copyUser($utclogin, $surname, $firstname, $email) {
// Function used to create a local copy of surname and firstname of each user, in order to link to DFP files without utclogin
// Function used to create a local copy of each user, in order to use data directly in database
$sql = 'SELECT utclogin FROM localuser WHERE utclogin=:utclogin';
$st1 = $this->conn->prepare($sql);
$st1->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st1->execute();
if (!$st1->fetch(PDO::FETCH_ASSOC)) {
// If user has never logged in yet, he is added to local copy
$sql = 'INSERT INTO localuser(utclogin, firstname, surname, email) VALUES (:utclogin, :firstname, :surname, :email)';
$sql = 'INSERT INTO localuser(utclogin) VALUES (:utclogin)';
$st2 = $this->conn->prepare($sql);
$st2->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st2->bindValue(':firstname',$firstname,PDO::PARAM_STR);
$st2->bindValue(':surname',$surname,PDO::PARAM_STR);
$st2->bindValue(':email',$email,PDO::PARAM_STR);
$res = $st2->execute();
return $res;
}
else {
return 0;
}
// Update data in any case
$sql = 'UPDATE localuser
SET firstname=:firstname, surname=:surname, email=:email
WHERE utclogin=:utclogin';
$st2 = $this->conn->prepare($sql);
$st2->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st2->bindValue(':firstname',$firstname,PDO::PARAM_STR);
$st2->bindValue(':surname',$surname,PDO::PARAM_STR);
$st2->bindValue(':email',$email,PDO::PARAM_STR);
$res = $st2->execute();
return $res;
}
/** Returns T is subscriptions and unsubscription are allowed **/
......@@ -105,4 +131,98 @@ class DB {
return $res['utclogin'];
}
public function apiListResp($admin, $utclogin) {
$sql = 'SELECT *, indicator(utclogin, week, year) AS indicator
FROM vsubscription
WHERE semester=:semester AND year=:year AND resplogin=:resp' ;
$st = $this->conn->prepare($sql);
$st->bindValue(':semester',$admin->activeSemester(),PDO::PARAM_STR);
$st->bindValue(':year',$admin->activeYear(),PDO::PARAM_INT);
$st->bindValue(':resp',$utclogin,PDO::PARAM_STR);
$st->execute();
$res = $st->fetchAll(PDO::FETCH_ASSOC);
return $res;
}
public function validate($resp, $api, $student) {
$today = date('Ymd');
// Validation that $resp is resp of $api
$sql = 'SELECT COUNT(*) AS c FROM vapi WHERE resplogin=:resp AND id=:api';
$st = $this->conn->prepare($sql);
$st->bindValue(':resp',$resp,PDO::PARAM_STR);
$st->bindValue(':api',$api,PDO::PARAM_STR);
$st->execute();
$res = $st->fetch(PDO::FETCH_ASSOC);
if ($res['c']==1) {
// Year and week calculation for Api
$sql = "SELECT year, week FROM vapi WHERE id=:api";
$st = $this->conn->prepare($sql);
$st->bindValue(':api',$api,PDO::PARAM_STR);
$st->execute();
$res = $st->fetch(PDO::FETCH_ASSOC);
$year = $res['year'];
$week = $res['week'];
// Validate subscription
$st = $this->conn->prepare($sql);
$sql = "BEGIN";
$st = $this->conn->prepare($sql);
$st->execute();
$sql = "UPDATE subscribe
SET validation='TRUE', validationdate=:today
WHERE api=:api AND utclogin=:utclogin";
$st = $this->conn->prepare($sql);
$st->bindValue(':utclogin',$student,PDO::PARAM_STR);
$st->bindValue(':api',$api,PDO::PARAM_STR);
$st->bindValue(':today',$today,PDO::PARAM_STR);
$res = $st->execute();
// Cancel other subscriptions the same week
$sql = "UPDATE subscribe
SET validation='FALSE', validationdate=:today
WHERE api<>:api AND utclogin=:utclogin
AND api IN (SELECT id FROM vapi WHERE week=:week AND year=:year)";
$st = $this->conn->prepare($sql);
$st->bindValue(':utclogin',$student,PDO::PARAM_STR);
$st->bindValue(':api',$api,PDO::PARAM_STR);
$st->bindValue(':today',$today,PDO::PARAM_STR);
$st->bindValue(':year',$year,PDO::PARAM_STR);
$st->bindValue(':week',$week,PDO::PARAM_STR);
$res = $st->execute();
$sql = "COMMIT";
$st = $this->conn->prepare($sql);
$st->execute();
return $res;
}
else {
echo "<p>Erreur : le responsable $resp n'est pas autorisé à valider l'inscription de $student</p>" ;
// ajouter le nom de l'Api
return -1;
}
}
public function apiStudents($utclogin, $api) {
if ($this->isAdmin($utclogin)) {
$sql = 'SELECT *
FROM vsubscription
WHERE id=:api AND resplogin=:utclogin AND validation
ORDER BY surname, firstname' ; //TODO donner accès aux admins même si ne sont pas les resp
}
else {
$sql = 'SELECT *
FROM vsubscription
WHERE id=:api AND resplogin=:utclogin AND validation
ORDER BY surname, firstname';
}
$st = $this->conn->prepare($sql);
$st->bindValue(':api',$api,PDO::PARAM_STR);
$st->bindValue(':utclogin',$utclogin,PDO::PARAM_STR);
$st->execute();
$res = $st->fetchAll(PDO::FETCH_ASSOC);
return $res;
}
}
......@@ -18,7 +18,7 @@ class Views {
return $this->admin->isActive();
}
public function printHtmlBegin() {
public function printHtmlBegin($admin) {
echo '<html>';
echo '<head>';
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>';
......@@ -26,40 +26,74 @@ class Views {
echo '<link href="css/main.css" type="text/css" rel="stylesheet"/>';
echo '</head>';
echo '<body>';
echo '<h1>Inscriptions Api</h1>';
echo '<h1>Foire aux Api '.$admin->activeSemester().$admin->activeYear().'</h1>';
}
public function printInstructions($row) {
echo '<hr/>';
echo '<h2>Catalogue</h2>';
echo '<p>Les Api sont décrites ici : <b><a href="https://apint.utc.fr/cat">https://apint.utc.fr/cat</a></b>. Veillez à avoir bien lu la fiche avant de vous inscrire (pré-requis, dates...).</p>';
echo '<h2>Instructions</h2>';
echo '<p>Les Api sont décrites ici : <b><a href="https://apint.utc.fr/cat">https://apint.utc.fr/cat</a></b></p>';
echo "<p>Veillez à avoir bien lu la fiche avant de vous inscrire (pré-requis, dates...). Vous pouvez vous inscrire et vous désinscrire librement entre le $row[openbegin] et le $row[openend].</p>";
echo '<p>Vous ne <b>pouvez pas</b> suivre deux Api qui se chevauchent (sauf pour le cas particulier de l\'Api <i>Animer une Api</i>). Si vous choisissez deux Api qui se chevauchent, indiquez vos préférences dans la zone de commentaire.</p>';
echo '<ul>';
echo '<li>Les Api sont ajoutées au fil du semestre par les responsables des Api. Dès qu\'une Api est au catalogue, les étudiants peuvent commencer à s\'inscrire.';
echo '<li>Un étudiant peut s\'inscrire à plusieurs Api la même semaine, mais il ne pourra en suivre qu\'une seule. Il peut librement se désinscrire tant que l\'inscription n\'est pas validée.</li>';
echo '<li><span class="goldenrule">Règle d\'or : dès qu\'un responsable d\'Api a validé une inscription, celle-ci est irréversible (ni l\'enseignant ni l\'étudiant ne peuvent l\'annuler). Si un étudiant était inscrit à d\'autres Api la même semaine, ces autres inscriptions sont annulées.</span></li>';
echo '<li><span class="goldenrule">Corrolaire : Si un reponsable d\'Api commence à valider des inscriptions, alors l\'Api sera nécessairement ouverte.</span></li>';
echo '</ul>';
}
public function printUser($isResp, $isAdmin) {
echo "<p><i>$this->firstname $this->surname</i> (<b>$this->utclogin</b>)</p>";
if ($isResp) {
echo '<a href="resp.php">[Gérer ses Api]</a> ';
echo "<div class='user'><span class='name'>$this->firstname $this->surname</span> (<span class='login'>$this->utclogin</span>)</div>";
actuels if ($isResp) {
echo '<a href="index.php?mode=resp">[Gérer ses Api]</a> ';
}
if ($isAdmin) {
echo '<a href="admin.php">[Super-pouvoirs]</a>';
echo '<a href="index.php?mode=admin">[Super-pouvoirs]</a> ';
}
if ($isResp || $isAdmin) {
echo '<a href="index.php">[Inscriptions]</a>';
}
echo "</div>";
}
private function printApi($row) {
return "$row[normcode] - $row[name] (du $row[normdbegin] au $row[normdend]) [Inscriptions : $row[nbsub]/$row[size]]";
return "$row[normcode] - $row[name] (du $row[normdbegin] au $row[normdend]) [Demandes $row[nbask] | Inscriptions $row[nbval]/$row[size]]";
}
private function printWeek($row) {
return "$row[year] Semaine $row[week]";
}
private function printStudent($row) {
if (!$row['surname']) {
return "$row[utclogin] $row[level] <a href='mailto:$row[utclogin]@etu.utc.fr'>[mail]</a> <a href='https://demeter.utc.fr/portal/pls/portal30/portal30.get_photo_utilisateur?username=$row[utclogin]'>[photo]</a>";
}
else {
return "$row[firstname] $row[surname] $row[level] <a href='mailto:$row[email]'>[mail]</a> <a href='https://demeter.utc.fr/portal/pls/portal30/portal30.get_photo_utilisateur?username=$row[utclogin]'>[photo]</a>";
}
}
public function printSubList($list) {
#KNOWN_BUB #TODO Il est possible de ses déinscrire en utilisant directement l'URL
if ($list) {
echo '<hr/>';
echo '<h2>Vos inscriptions</h2>';
$week = '';
foreach ($list as $row) {
if ($row['week'] != $week) {
$week = $row['week'];
echo "<h3>".$this->printWeek($row)."</h3>";
}
echo '<p>';
if ($this->isActive()) {
echo "<a href='index.php?action=unsub&api=$row[id]'>[désinscription]</a> ";
if ($row['validation']) {
echo "<span class='validation'>[validé]</span> ";
}
else {
echo "<a href='index.php?action=unsub&api=$row[id]' class='unsub'>[désinscription]</a> ";
}
}
echo $this->printApi($row);
echo ' ['.$row['semester'].$row['year'].', inscrit le '.$row['subdate'].']';
echo '</p>';
}
}
......@@ -68,28 +102,27 @@ class Views {
}
}
public function printExplanation($comment, $utclogin) {
if ($this->isActive()) {
echo '<h2>Commentaire</h2>';
echo '<form method="get" action="index.php">';
echo '<textarea name="explanation" cols="100" rows="5">'.$comment.'</textarea>';
echo '<br/>';
echo '<input type="submit" value="Enregistrer le commentaire"/>';
echo '</form>';
}
else {
echo '<h2>Commentaire</h2>';
echo '<p>'.$comment.'</p>';
}
}
public function printApiList($list) {
if ($list) {
echo '<hr/>';
echo '<h2>Liste des Api</h2>';
$week = '';
foreach ($list as $row) {
if ($row['week'] != $week) {
$week = $row['week'];
echo "<h3>".$this->printWeek($row)."</h3>";
}
echo '<p>';
if ($this->isActive()) {
echo "<a href='index.php?action=sub&api=$row[id]'>[inscription]</a> ";
if ($row['open'] && $row['is_available']) {
echo "<a href='index.php?action=sub&api=$row[id]' class='sub'>[inscription]</a> ";
}
elseif (! $row['is_available']) {
echo "[indisponible] ";
}
else {
echo '[complet] ';
}
}
echo $this->printApi($row);
echo '</p>';
......@@ -100,4 +133,90 @@ class Views {
}
}
public function respValidation ($listsub) {
// #KNOWN_BUG Si un resp a plusieurs Api, il peut changer un inscrit entre ses deux Api en modifiant l'URL (pas via l'interface)
echo '<h1>Interface Responsable d\'Api</h1>';
echo '<hr/>';
echo '<h2>Rappel</h2>';
echo '<ul>';
echo '<li>La validation d\'une inscription entraîne la confirmation de l\'ouverture de l\'Api.</li>';
echo '<li>Toute inscription validée est irréversible.</li>';
echo '</ul>';
if ($listsub) {
$api = '';
foreach ($listsub as $sub) {
if ($api != $sub['id']) {
$api = $sub['id'];
echo '<hr/>';
echo "<h2><a href='api.php?api=$api'>".$this->printApi($sub).' 📷</a></h2>';
}
if ($sub['utclogin']) {
if ($sub['validation']) {
// Subscription already validated
echo '<p><b>[validé] </b>'.$this->printStudent($sub).'</p>';
}
else if (is_null($sub['validation'])) {
// At least one waiting subscription
echo "<p> <a href='index.php?action=validate&api=$sub[id]&login=$sub[utclogin]&mode=resp' class='valid'>[valider]</a> ".$this->printStudent($sub)." <span>Exclusivité : $sub[indicator]%</span></p>";
}
else {
// validation = FALSE lignes ignored
}
}
else {
// Not yet any subscription for this Api (LEFT JOIN might have add null student line)
echo "<p>Aucune inscription à gérer</p>";
}
}
}
else {
echo "<p>Aucune Api à gérer</p>";
}
}
public function apiStudents($students) {
echo "<hr/>";
if (isset($students[0])) {
// Api Title
echo '<h2>'.$this->printApi($students[0]).'</h2>';
// Api mailing list
$mailinglist='mailto:';
foreach ($students as $s) {
$mailinglist = $mailinglist."$s[email],";
}
// Api CSV data (for JavaScript function)
echo '<script src="js/main.js"></script>';
echo "<script>var csvstudents = [['Nom','Prénom','Niveau','Mail','Login'],";
foreach ($students as $s) {
echo "['$s[surname]','$s[firstname]','$s[level]','$s[email]','$s[utclogin]'],";
}
echo "];</script>";
// Api Menu
echo "<div class='menu'><a href='$mailinglist'>[Mailing list]</a> <a id='csvlink' onclick='download_csv(csvstudents)' href=''>[Fichier CSV]</a></div>";
echo "<hr/>";
}
else {
echo '<h2>Aucun inscrit validé</h2>';
}
foreach ($students as $s) {
echo "<div class='student'>
<img src='https://demeter.utc.fr/portal/pls/portal30/portal30.get_photo_utilisateur?username=$s[utclogin]'
height='100px'
width='100px'/>
<span class='name'>$s[surname] $s[firstname] | $s[level] | <a href='mailto:$s[email]'>$s[email]</a> ($s[utclogin])</span>
</div>";
}
}
public function apiStudentsCsv($students) {
//TODO
foreach ($students as $s) {
echo "$s[surname];$s[firstname];$s[level];$s[email];$s[utclogin]\n";
}
}
public function adminFunction ($utclogin) {
echo "<p>Je dois vérifier que $utclogin a vraiment des super-pouvoirs...</p>";
}
}
......@@ -15,6 +15,10 @@ class Api {
week() : [1..53]
year() : int(4)
semester() : H|E|A|P
nbsub() : int
nbval() : int
isActive() : boolean
isOpen() : boolean
}
note left of Api : (dbeging,code) key\n(dbegin,name) key\nduration in days
......
......@@ -16,7 +16,7 @@ CREATE TABLE config (
openend DATE NOT NULL
);
INSERT INTO config VALUES ('FALSE', TO_DATE('20180101','YYYYMMDD'), TO_DATE('20191231','YYYYMMDD'));
INSERT INTO config VALUES ('FALSE', TO_DATE('20190410','YYYYMMDD'), TO_DATE('20190603','YYYYMMDD'));
CREATE OR REPLACE VIEW vconfig AS
SELECT
......
CREATE TABLE student (
utclogin TEXT PRIMARY KEY,
level TEXT
);
/** Test dataset **/
BEGIN;
DELETE FROM subscribe;
DELETE FROM api;
DELETE FROM localuser;
INSERT INTO localuser (utclogin) VALUES ('crozatst');
INSERT INTO localuser (utclogin) VALUES ('prof1');
INSERT INTO localuser (utclogin) VALUES ('student1');
INSERT INTO localuser (utclogin) VALUES ('student2');
INSERT INTO localuser (utclogin) VALUES ('student3');
INSERT INTO localuser (utclogin) VALUES ('sdesterc');
INSERT INTO localuser (utclogin) VALUES ('dore');
INSERT INTO localuser (utclogin) VALUES ('nsalzman');
INSERT INTO localuser (utclogin) VALUES ('dauzatbr');
INSERT INTO localuser (utclogin) VALUES ('jlaforet');
INSERT INTO localuser (utclogin) VALUES ('icaillea');
INSERT INTO localuser (utclogin) VALUES ('ramond');
INSERT INTO localuser (utclogin) VALUES ('baouchya');
INSERT INTO localuser (utclogin) VALUES ('syrousse');
INSERT INTO localuser (utclogin) VALUES ('amaldona');
INSERT INTO localuser (utclogin) VALUES ('huetremy');
INSERT INTO api VALUES (
'1e06e8dc-2178-11e9-8edb-4bc5e8f8599c',
TO_DATE('20190121','yyyymmdd'),1,'Poésie et ingénierie','Lorem ipsum dolor sit amet',5,24,2,'crozatst'
INSERT INTO api ( id, dbegin, code, name, description, duration, size, ects, resplogin) VALUES (
'1006e8dc-2178-11e9-8edb-4bc5e8f8599c',
TO_DATE('20190701','yyyymmdd'),1,'Concevoir une formation','Concevoir et animer une formation courte',3,4,1,'icaillea'
);
INSERT INTO api ( id, dbegin, code, name, description, duration, size, ects, resplogin) VALUES (
'5e06e8dc-2178-11e9-8edb-4bc5e8f8599c',
TO_DATE('20190701','yyyymmdd'),5,'Poésie et ingénierie','Lorem ipsum dolor sit amet',5,3,2,'crozatst'
);
INSERT INTO api VALUES (
'2afa8472-2178-11e9-b2b0-07511495b3b2',
TO_DATE('20190128','yyyymmdd'),2,'Cloud big data blockchain IA','At vero eos et accusamus',3,12,1,'crozatst'
TO_DATE('20190701','yyyymmdd'),2,'Cloud big data blockchain IA','At vero eos et accusamus',3,12,1,'crozatst'
);
INSERT INTO api VALUES (
'3352b3a0-217d-11e9-aabc-037b6e1a6a33',
TO_DATE('20190708','yyyymmdd'),3,'La TRM et la Ğ1','Duis rhoncus turpis non libero auctor posuere.',5,10,2,'crozatst'
);
INSERT INTO api VALUES (
'4352b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190121','yyyymmdd'),3,'La TRM et la G1','Duis rhoncus turpis non libero auctor posuere.',5,50,2,'prof1'
TO_DATE('20190715','yyyymmdd'),4,'Initiation au Picard','Vivamus porttitor arcu non dui mollis.',1,1,1,'crozatst'
);
INSERT INTO api VALUES (
'1452b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190701','yyyymmdd'),14,'SUSHI','Contribution au projet SUSHI : productions d''outils méthodologiques spécifiques pour le cursus Hutech.',5,6,2,'nsalzman'
);
INSERT INTO api VALUES (
'1142b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190701','yyyymmdd'),114,'SUSHI II','Le retour.',3,3,1,'nsalzman'
);
INSERT INTO api VALUES (
'1652b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190701','yyyymmdd'),16,'La Data Science pour tous','La Data Science pour tous : comprendre et pratiquer.',5,10,2,'syrousse'
);
INSERT INTO api VALUES (
'1052b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190708','yyyymmdd'),10,'Apprentissage automatique','Apprentissage automatique statistique et introduction à la recherche.',5,3,2,'sdesterc'
);
INSERT INTO api VALUES (
'1002b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190701','yyyymmdd'),100,'Baby-foot','Concevoir un baby-foot.',5,4,2,'dore'
);
INSERT INTO api VALUES (
'8882b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190708','yyyymmdd'),8,'Habilitation électrique','Formation préalable à l''habilitation électrique.',5,2,2,'dauzatbr'
);
INSERT INTO api VALUES (
'2052b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190708','yyyymmdd'),20,'Python pour les sciences','Initiation à Python pour les sciences.',5,4,2,'jlaforet'
);
INSERT INTO api VALUES (
'1999b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190708','yyyymmdd'),19,'Dipfablab Eté 2019','Dipfablab 2019 - Prototypage - module débutant.',5,4,2,'ramond'
);
INSERT INTO api VALUES (
'1199b3a0-217d-11e9-aabc-037b6e1a6a16',
TO_DATE('20190708','yyyymmdd'),11,'Challenge Ecoconception','Challenge Ecoconception.',5,4,2,'baouchya'
);
/* Initial Subscriptions */
INSERT INTO subscribe (utclogin,api,subdate) VALUES (
'student1','1e06e8dc-2178-11e9-8edb-4bc5e8f8599c',TO_DATE('20190121','yyyymmdd')
'huetremy','5e06e8dc-2178-11e9-8edb-4bc5e8f8599c',TO_DATE('20190121','yyyymmdd')
);
INSERT INTO subscribe (utclogin,api,subdate) VALUES (
'student1','2afa8472-2178-11e9-b2b0-07511495b3b2',TO_DATE('20190121','yyyymmdd')
'amaldona','5e06e8dc-2178-11e9-8edb-4bc5e8f8599c',TO_DATE('20190121','yyyymmdd')
);
INSERT INTO subscribe (utclogin,api,subdate) VALUES (
'student1','4352b3a0-217d-11e9-aabc-037b6e1a6a16',TO_DATE('20190121','yyyymmdd')
'nsalzman','5e06e8dc-2178-11e9-8edb-4bc5e8f8599c',TO_DATE('20190121','yyyymmdd')
);
INSERT INTO subscribe (utclogin,api,subdate) VALUES (
'student2','1e06e8dc-2178-11e9-8edb-4bc5e8f8599c',TO_DATE('20190121','yyyymmdd')
'dore','2afa8472-2178-11e9-b2b0-07511495b3b2',TO_DATE('20190121','yyyymmdd')
);
INSERT INTO subscribe (utclogin,api,subdate) VALUES (
'dore','4352b3a0-217d-11e9-aabc-037b6e1a6a16',TO_DATE('20190121','yyyymmdd')
);
SELECT id, normcode, name FROM vapi;
SELECT normcode, name, size, nbval, nbask, open, resplogin, semester, year FROM vapi;
SELECT * FROM vlocaluser;
SELECT utclogin, id, normcode FROM vsubscription;
SELECT * FROM vapi_count;
SELECT utclogin, id, normcode, validation FROM vsubscription;
COMMIT;
CREATE OR REPLACE FUNCTION unaccent_string(TEXT)
RETURNS TEXT
AS $$
CREATE OR REPLACE FUNCTION unaccent_string(TEXT) RETURNS TEXT AS $$
SELECT translate(
$1,
'âãäåÁÂÃÄÅèééêëÈÉÉÊËìíîïìÌÍÎÏÌóôõöÒÓÔÕÖùúûüÙÚÛÜ',
......@@ -8,11 +6,77 @@ AS $$
);
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION nb_api(TEXT, TEXT) RETURNS INTEGER AS $$
/* Returns number of api for one week and year */
DECLARE
w ALIAS FOR $1;
y ALIAS FOR $2;
c INTEGER;
BEGIN
SELECT COUNT(*) INTO c
FROM vapi
WHERE week=w AND year=y;
RETURN c;
END;
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION nb_sub(TEXT, TEXT, TEXT) RETURNS INTEGER AS $$
/* Returns number of subsciption for one student for one week and year */
DECLARE
student ALIAS FOR $1;
w ALIAS FOR $2;
y ALIAS FOR $3;
c INTEGER;
BEGIN
SELECT COUNT(*) INTO c
FROM vsubscription
WHERE utclogin=student AND week=w AND year=y;
RETURN c;
END;
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION indicator(TEXT, TEXT, TEXT) RETURNS INTEGER AS $$
/* Returns indicator one student for one week and year */
DECLARE
student ALIAS FOR $1;
w ALIAS FOR $2;
y ALIAS FOR $3;
nb_sub FLOAT;
nb_api FLOAT;
BEGIN
nb_sub = nb_sub(student,w,y);
nb_api = nb_api(w,y);
IF nb_sub = 0 THEN
RETURN -1;
ELSIF nb_sub = 1 THEN
RETURN 100;
ELSE
RETURN ROUND(100 * (1 - (nb_sub / nb_api)));
END IF;
END;
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION is_available(TEXT, TEXT, TEXT) RETURNS BOOLEAN AS $$
/* Returns True if student has no api validated for same week and year */
DECLARE
student ALIAS FOR $1;
w ALIAS FOR $2;
y ALIAS FOR $3;
c INTEGER;
BEGIN
SELECT COUNT(*) INTO c
FROM vsubscription
WHERE utclogin=student AND week=w AND year=y AND validation;
IF c = 0 THEN
RETURN 'TRUE';
ELSE
RETURN 'FALSE';
END IF;
END;
$$ LANGUAGE PLPGSQL;
/** TODO **/
CREATE OR REPLACE FUNCTION
semester(DATE)
RETURNS CHAR(1)
AS $$
CREATE OR REPLACE FUNCTION semester(DATE) RETURNS CHAR(1) AS $$
BEGIN
RETURN 'E';
END;
......
......@@ -3,15 +3,12 @@ BEGIN;
DROP TABLE IF EXISTS subscribe CASCADE;
DROP TABLE IF EXISTS api CASCADE;
DROP TABLE IF EXISTS localuser CASCADE;
DROP TABLE IF EXISTS utcstudent;
CREATE TABLE localuser (
utclogin TEXT PRIMARY KEY,
email TEXT,
surname TEXT,
firstname TEXT,
speciality TEXT,
level TEXT
firstname TEXT
);
CREATE TABLE api (
......@@ -38,18 +35,11 @@ CREATE TABLE subscribe (
utclogin TEXT NOT NULL,
api UUID NOT NULL,
subdate DATE NOT NULL,
confirmed BOOLEAN NOT NULL DEFAULT FALSE,
validation BOOLEAN,
validationdate DATE,
FOREIGN KEY (utclogin) REFERENCES localuser(utclogin),
FOREIGN KEY (api) REFERENCES api(id),
PRIMARY KEY (utclogin,api)
);
/* Table created to retrieve CSV info from DFP (À supprimer) */
CREATE TABLE utcstudent (
surname TEXT NOT NULL,
firstname TEXT NOT NULL,
speciality TEXT NOT NULL,
level TEXT NOT NULL
);
COMMIT;
BEGIN;
CREATE OR REPLACE VIEW vapi_count AS
CREATE OR REPLACE VIEW vapi_subcount AS
SELECT
api AS countid,
COUNT(utclogin) AS nbsub
api AS subcountid,
COUNT(utclogin) AS countsub
FROM subscribe
WHERE validation IS NULL
GROUP BY api;
CREATE OR REPLACE VIEW vapi_valcount AS
SELECT
api AS valcountid,
COUNT(utclogin) AS countval
FROM subscribe
WHERE validation
GROUP BY api;
CREATE OR REPLACE VIEW vapi AS
SELECT
*,
TO_CHAR(dbegin,'TMday FMDD TMmonth') AS normdbegin,
CASE WHEN code<10 THEN '000'||code WHEN code>=10 THEN '00'||code END AS normcode,
LPAD(code::text, 4, '0') AS normcode,
TO_CHAR(dbegin + duration-1,'TMday FMDD TMmonth') AS normdend,
TO_CHAR(dbegin, 'ww') AS week,
TO_CHAR(dbegin, 'IW') AS week,
TO_CHAR(dbegin, 'yyyy') AS year,
semester(dbegin) AS semester
FROM api LEFT JOIN vapi_count ON id=countid
ORDER BY dbegin, code;
semester(dbegin) AS semester,
COALESCE(countsub,0) AS nbask,
COALESCE(countval,0) AS nbval,
CASE WHEN countval >= size THEN 0 ELSE 1 END AS open
FROM api LEFT JOIN vapi_subcount ON id=subcountid LEFT JOIN vapi_valcount ON id=valcountid
ORDER BY year, week, code;
CREATE OR REPLACE VIEW vlocaluser AS
SELECT l.utclogin, u.surname, u.firstname, l.email, MAX(u.speciality) AS speciality, MAX(u.level) AS level,
CASE WHEN COUNT(*)>1 THEN 'duplication' END AS warning
SELECT l.*, s.level
FROM localuser l
LEFT JOIN utcstudent u ON l.surname=u.surname AND l.firstname=unaccent_string(u.firstname)
GROUP BY l.utclogin, u.surname, u.firstname;
LEFT JOIN student s ON l.utclogin=s.utclogin;
CREATE OR REPLACE VIEW vsubscription AS
SELECT
ap.*,
TO_CHAR(su.subdate,'DD/MM/YYYY') AS subdate,
su.utclogin AS sublogin,
lo.*
lo.*,
su.subdate,
su.validation,
su.validationdate
FROM subscribe su
JOIN vapi ap ON ap.id=su.api
RIGHT JOIN vapi ap ON ap.id=su.api
LEFT JOIN vlocaluser lo ON su.utclogin=lo.utclogin
ORDER BY ap.dbegin, ap.code, lo.firstname, lo.surname, lo.utclogin;
ORDER BY ap.year, ap.week, ap.code, su.validation, lo.firstname, lo.surname, lo.utclogin;
CREATE OR REPLACE VIEW vsubscription_anonymous AS
SELECT normcode, name, normdbegin, normdend, size, speciality, level
SELECT normcode, name, normdbegin, normdend, size, level
FROM vsubscription;
COMMIT;
#!/bin/bash
sqlfiles='/media/stc/data/git/apisub/sql'
psql -c "DROP DATABASE apisub"
psql -c "DROP USER apisub"
psql -c "CREATE USER apisub WITH ENCRYPTED PASSWORD 'password'"
SQL=`dirname $0`
psql -c "DROP DATABASE IF EXISTS apisub"
psql -c "DROP USER IF EXISTS apisub"
psql -c "CREATE USER apisub WITH ENCRYPTED PASSWORD '$1'"
psql -c "CREATE DATABASE apisub WITH OWNER apisub"
psql -d apisub -f "$sqlfiles/apisub_functions.sql"
psql -d apisub -f "$sqlfiles/apisub_admin.sql"
psql -d apisub -f "$sqlfiles/apisub_tables.sql"
psql -d apisub -f "$sqlfiles/apisub_views.sql"
psql -d apisub -f "$sqlfiles/apisub_dataset.sql"
psql -d apisub -f "$SQL/apisub_functions.sql"
psql -d apisub -f "$SQL/apisub_admin.sql"
psql -d apisub -f "$SQL/apisub_tables.sql"
psql -d apisub -f "$SQL/apisub_data.sql"
psql -d apisub -c "\copy student (utclogin, level) FROM '$SQL/../data/students.csv' WITH CSV DELIMITER ','"
psql -d apisub -f "$SQL/apisub_views.sql"
psql -d apisub -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO apisub"
psql -d apisub -c 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
# psql -d apisub -f "$SQL/apisub_dataset.sql"
......@@ -10,36 +10,50 @@
<xsl:output method="text"></xsl:output>
<xsl:template match="/sc:item">
<xsl:text>BEGIN;</xsl:text>
<xsl:text>INSERT INTO api (code,name,description,year,semester,dbegin,dend,size,ects,mail) VALUES</xsl:text>
<xsl:apply-templates select="of:webSite/sp:home/of:page/sp:subPage"/>
;
<xsl:variable name="logintitle">Login UTC du responsable UTC</xsl:variable>
<xsl:template match="/sc:item">
<xsl:apply-templates select="of:webSite/sp:home/of:page/sp:subPage" mode="login"/>
<xsl:text>BEGIN;</xsl:text>
<xsl:apply-templates select="of:webSite/sp:home/of:page/sp:subPage"/>
<xsl:text>COMMIT;</xsl:text>
</xsl:template>
<xsl:template match="sp:subPage" mode="login">
<xsl:text>INSERT INTO localuser (utclogin) VALUES ('</xsl:text>
<xsl:value-of select="document(@sc:refUri)/sc:item//sp:info[of:block/of:blockM/sp:title=$logintitle]//sc:para[1]"/>
<xsl:text>');</xsl:text>
</xsl:template>
<xsl:template match="sp:subPage">
<xsl:apply-templates select="document(@sc:refUri)/sc:item" mode="api">
<xsl:with-param name="code">
<xsl:value-of select="substring(@sc:refUri,string-length(@sc:refUri)-11,4)"/>
</xsl:with-param>
</xsl:apply-templates>
<xsl:if test="following::sp:subPage">,</xsl:if>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="sc:item" mode="api">
<xsl:param name="code"/>
<xsl:variable name="id">uuid_generate_v4()</xsl:variable>
<xsl:variable name="begin">
<xsl:value-of select="substring(.//sp:info[of:block/of:blockM/sp:title='Période']//sc:para[1],1,5)"/>
</xsl:variable>
<xsl:variable name="title">
<xsl:value-of select="replace(of:section/of:sectionM/sp:title,'''','''''')"/>
</xsl:variable>
<xsl:variable name="longtitle">
<xsl:value-of select="replace(.//sp:emphasis[1]//sc:para[1],'''','''''')"/>
</xsl:variable>
<xsl:variable name="begin">
<xsl:value-of select="substring(.//sp:info[of:block/of:blockM/sp:title='Période']//sc:para[1],1,5)"/>
</xsl:variable>
<xsl:variable name="end">
<xsl:value-of select="substring(.//sp:info[of:block/of:blockM/sp:title='Période']//sc:para[1],7,11)"/>
<xsl:variable name="duration">
<xsl:value-of select="
number(substring(.//sp:info[of:block/of:blockM/sp:title='Période']//sc:para[1],7,2))
-
number(substring(.//sp:info[of:block/of:blockM/sp:title='Période']//sc:para[1],1,2))
+1
"
/>
</xsl:variable>
<xsl:variable name="size">
<xsl:value-of select="number(.//sp:info[of:block/of:blockM/sp:title='Capacité d''accueil']//sc:para[1])"/>
......@@ -47,24 +61,20 @@
<xsl:variable name="ects">
<xsl:value-of select="number(.//sp:info[of:block/of:blockM/sp:title='ECTS']//sc:para[1])"/>
</xsl:variable>
<xsl:variable name="mail">
<xsl:value-of select=".//sp:info[of:block/of:blockM/sp:title='Mail']//sc:para[1]"/>
</xsl:variable>
(
<xsl:value-of select="$code"/>,
'<xsl:value-of select="$title"></xsl:value-of>',
'<xsl:value-of select="$longtitle"></xsl:value-of>',
2019,
'H',
TO_DATE('<xsl:value-of select="$begin"/>/19','DD/MM/YY'),
TO_DATE('<xsl:value-of select="$end"/>/19','DD/MM/YY'),
<xsl:value-of select="$size"/>,
<xsl:value-of select="$ects"/>,
<xsl:choose>
<xsl:when test="$mail=''">NULL</xsl:when>
<xsl:otherwise>'<xsl:value-of select="$mail"/>'</xsl:otherwise>
</xsl:choose>
)
<xsl:variable name="login">
<xsl:value-of select=".//sp:info[of:block/of:blockM/sp:title=$logintitle]//sc:para[1]"/>
</xsl:variable>
INSERT INTO api (id,dbegin,code,name,description,duration,size,ects,resplogin) VALUES (
<xsl:value-of select="$id"/>,
TO_DATE('<xsl:value-of select="$begin"/>/19','DD/MM/YY'),
<xsl:value-of select="$code"/>,
'<xsl:value-of select="$title"></xsl:value-of>',
'<xsl:value-of select="$longtitle"></xsl:value-of>',
<xsl:value-of select="$duration"/>,
<xsl:value-of select="$size"/>,
<xsl:value-of select="$ects"/>,
'<xsl:value-of select="$login"/>'
<xsl:text>);</xsl:text>
</xsl:template>
......