Skip to content
Snippets Groups Projects
Commit 9634818e authored by Laurent Lecluse's avatar Laurent Lecluse
Browse files

Système de mise à jour automatique des privilèges

parent 8c08df2f
Branches
Tags
No related merge requests found
...@@ -29,6 +29,7 @@ ne sont plus affichées lorsqu'on clique sur l'utilisateur en haut à droite. ...@@ -29,6 +29,7 @@ ne sont plus affichées lorsqu'on clique sur l'utilisateur en haut à droite.
* Formules de calcul : nouveau système de récupération des paramètres spécifiques directement implanté dans les formules. * Formules de calcul : nouveau système de récupération des paramètres spécifiques directement implanté dans les formules.
Les vues V_FORMULE_LOCAL_I_PARAMS et V_FORMULE_LOCAL_VH_PARAMS ne sont plus nécessaires. Les vues V_FORMULE_LOCAL_I_PARAMS et V_FORMULE_LOCAL_VH_PARAMS ne sont plus nécessaires.
* Renforcement du script de mise à jour (pour les futures mises à jour) : détection de l'accès à la BDD OK ou non avant de démarrer la procédure et avertissement sans blocage si le cache ne peut pas se nettoyer. * Renforcement du script de mise à jour (pour les futures mises à jour) : détection de l'accès à la BDD OK ou non avant de démarrer la procédure et avertissement sans blocage si le cache ne peut pas se nettoyer.
* Système de mise à jour automatique : les privilèges sont maintenus à jour automatiquement
# OSE 8.1.2 # OSE 8.1.2
......
<?php <?php
$oa->majPrivileges();
\ No newline at end of file
...@@ -37,4 +37,11 @@ $schema->setLogger($scl); ...@@ -37,4 +37,11 @@ $schema->setLogger($scl);
$schema->alter($ref, $ddlConfig, true); $schema->alter($ref, $ddlConfig, true);
$c->println('Fin de mise à jour des définitions'); $c->println('Fin de mise à jour des définitions');
$c->println('Mise à jour des privilèges', $c::COLOR_LIGHT_PURPLE);
$oa->majPrivileges();
$c->println('Fin de la mise à jour des privilèges');
$c->println(''); $c->println('');
\ No newline at end of file
...@@ -49,9 +49,6 @@ $c->passthru([ ...@@ -49,9 +49,6 @@ $c->passthru([
"php composer.phar install", "php composer.phar install",
]); ]);
// Néttoyage des caches et mise à jour des proxies, lancement du script de migration éventuel
$oa->run('clear-cache');
// Mise à jour des liens vers les répertoires publics des dépendances // Mise à jour des liens vers les répertoires publics des dépendances
$c->println("\nMise à jour des liens vers les répertoires publics des dépendances", $c::COLOR_LIGHT_CYAN); $c->println("\nMise à jour des liens vers les répertoires publics des dépendances", $c::COLOR_LIGHT_CYAN);
$res = $oa->majUnicaenSymLinks($osedir); $res = $oa->majUnicaenSymLinks($osedir);
...@@ -66,5 +63,8 @@ $oa->migration('pre'); ...@@ -66,5 +63,8 @@ $oa->migration('pre');
$oa->run('update-bdd'); $oa->run('update-bdd');
$oa->migration('post'); $oa->migration('post');
// Néttoyage des caches et mise à jour des proxies
$oa->run('clear-cache');
$c->println("\nFin de la mise à jour. N'oubliez pas de sortir du mode maintenance!"); $c->println("\nFin de la mise à jour. N'oubliez pas de sortir du mode maintenance!");
$c->println(''); $c->println('');
\ No newline at end of file
...@@ -194,6 +194,20 @@ class Bdd ...@@ -194,6 +194,20 @@ class Bdd
/**
* @param string $sequenceName
*
* @return int
*/
public function sequenceNextVal(string $sequenceName): int
{
$r = $this->select("SELECT $sequenceName.NEXTVAL seqval FROM DUAL");
return (int)$r[0]['SEQVAL'];
}
/** /**
* @param string $sql * @param string $sql
* @param array $params * @param array $params
...@@ -287,76 +301,15 @@ class Bdd ...@@ -287,76 +301,15 @@ class Bdd
/** /**
* @param $table * @param string $name
* @param $data
*
* @return bool
*/
public function insert($table, $data, array $params = [])
{
$cols = array_keys($data);
$cols = implode(',', $cols);
$vals = '';
foreach ($data as $col => $val) {
if ($vals != '') $vals .= ',';
$vals .= ":$col";
}
$sql = "INSERT INTO $table ($cols) VALUES ($vals)";
return $this->exec($sql, $data);
}
public function copy(self $source, string $table)
{
}
/**
* @param string $table
* @param array|string|integer $data
* *
* @return bool * @return Table
*/
public function delete(string $table, $data)
{
if (!is_array($data)) {
$data = ['ID' => $data];
}
$sql = "DELETE FROM \"$table\" WHERE ";
$conds = "";
foreach ($data as $col => $val) {
if ($conds != '') {
$conds .= ' AND ';
}
$conds .= "$col = :$col";
}
$sql .= $conds;
return $this->exec($sql, $data);
}
/**
* Vide une table
*
* @param string $table
*
* @return bool
*/ */
public function truncate(string $table) public function getTable(string $name): Table
{ {
$sql = "TRUNCATE TABLE \"$table\""; $table = new Table($this, $name);
return $this->exec($sql); return $table;
} }
......
<?php
namespace BddAdmin\Data;
use BddAdmin\Bdd;
use BddAdmin\BddAwareTrait;
class Updater
{
use BddAwareTrait;
/**
* @inheritDoc
*/
public function __construct(Bdd $bdd)
{
$this->setBdd($bdd);
}
/**
* @param string $table
* @param array $data
* @param string|array $key
* @param array $ignoredCols
*
* @throws \BddAdmin\Exception\BddCompileException
* @throws \BddAdmin\Exception\BddException
* @throws \BddAdmin\Exception\BddIndexExistsException
*/
public function update(string $table, array $data, $key, array $options = [])
{
$ddlObject = new \BddAdmin\Ddl\DdlTable($this->getBdd());
$ddl = $ddlObject->get($table)[$table];
$tableWithId = isset($ddl['columns']['ID']);
$tableWithSequence = !empty($ddl['sequence']);
/* Initialisation */
$records = [];
$newRecord = [
'id' => null,
'bdd' => [],
'data' => [],
];
if ($tableWithId) {
$options['ID']['ignore'] = true;
}
/* Chargement des enregistrements actuels */
$result = $this->getBdd()->select('SELECT * FROM ' . $ddl['name']);
foreach ($result as $record) {
$keyVal = $this->makeValWithKey($record, $key);
if (!isset($records[$keyVal])) {
$records[$keyVal] = $newRecord;
}
if ($tableWithId) {
$records[$keyVal]['id'] = (int)$record['ID'];
}
foreach ($ddl['columns'] as $colName => $colDdl) {
if (!isset($options[$colName]['ignore']) || !$options[$colName]['ignore']) {
$colVal = $record[$colName];
$records[$keyVal]['bdd'][$colName] = $this->sqlToVal($colVal, $colDdl);
}
}
}
/* Chargement des données */
foreach ($data as $d) {
foreach( $d as $k => $v ){
if (isset($options[$k]['transformer'])){
$d[$k] = $this->transform($v, $options[$k]['transformer'], $ddl['columns'][$k]);
}
}
$keyVal = $this->makeValWithKey($d, $key);
if (!isset($records[$keyVal])) {
$records[$keyVal] = $newRecord;
}
foreach ($ddl['columns'] as $colName => $colDdl) {
if (!isset($options[$colName]['ignore']) || !$options[$colName]['ignore']) {
$records[$keyVal]['data'][$colName] = $d[$colName];
}
}
}
/* Mise à jour de la table */
foreach ($records as $index => $record) {
if (empty($record['bdd'])) { // INSERT
if (empty($record['id']) && $tableWithSequence) {
$record['id'] = $this->getBdd()->sequenceNextVal($ddl['sequence']);
}
$new = [];
if ($tableWithId){
$new['ID'] = $record['id'];
}
foreach ($ddl['columns'] as $colName => $colDdl) {
if (!isset($options[$colName]['ignore']) || !$options[$colName]['ignore']) {
$new[$colName] = $record['data'][$colName];
}
}
$this->getBdd()->insert($ddl['name'], $new);
} elseif (empty($record['data'])) { // DELETE
$this->getBdd()->delete($ddl['name'], $record['id']);
} else { // UPDATE ?
$diff = [];
foreach ($ddl['columns'] as $colName => $colDdl) {
if (!isset($options[$colName]['ignore']) || !$options[$colName]['ignore']) {
if ($record['bdd'][$colName] !== $record['data'][$colName]) {
$diff[$colName] = $record['data'][$colName];
}
}
}
if (!empty($diff)) {
$this->getBdd()->update($ddl['name'], $diff, ['ID' => $record['id']]);
}
}
}
}
protected function transform($value, string $transformer, array $ddl)
{
$val = $this->getBdd()->select(sprintf($transformer,':val'), ['val' => $value]);
$result = $this->sqlToVal(current($val[0]), $ddl);
return $result;
}
protected function makeValWithKey( array $data, $key)
{
$result = '';
$key = (array)$key;
foreach( $key as $k ){
if ($result != ''){
$result .= '_&@&@&@&_';
}
$result .= $data[$k];
}
return $result;
}
protected function sqlToVal($value, array $ddl)
{
switch ($ddl['type']) {
case 'NUMBER':
if (1 == $ddl['precision']) {
return $value === '1';
} else {
return (int)$value;
}
case 'FLOAT':
return (float)$value;
case 'VARCHAR2':
case 'CLOB':
return $value;
case 'DATE':
$date = \DateTime::createFromFormat('Y-m-d', $value);
$date->setTime(0, 0, 0, 0);
return $date;
case 'BLOB':
return $value;
default:
throw new \Exception("Type de donnée " . $ddl['type'] . " non géré.");
}
return $value;
}
}
\ No newline at end of file
<?php
namespace BddAdmin;
use BddAdmin\Ddl\DdlTable;
class Table
{
use BddAwareTrait;
/**
* @var string
*/
private $name;
/**
* @var array
*/
private $ddl;
/**
* @var array
*/
private $transformCache = [];
/**
* @inheritDoc
*/
public function __construct(Bdd $bdd, string $name)
{
$this->setBdd($bdd);
$this->name = $name;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @return array
*/
public function getDdl(): array
{
if (empty($this->ddl)) {
$ddlObject = new DdlTable($this->getBdd());
$this->ddl = $ddlObject->get($this->name)[$this->name];
}
return $this->ddl;
}
/**
* @param array|integer|null $where
* @param string|null $orderBy
*
* @return array
* @throws Exception\BddCompileException
* @throws Exception\BddException
* @throws Exception\BddIndexExistsException
*/
public function select($where = null, array $options = []): array
{
/* Initialisation des entrées */
$defaultOptions = [
'orderBy' => '',
'key' => null,
];
$options = array_merge($defaultOptions, $options);
$ddl = $this->getDdl();
/* Construction et exécution de la requête */
$cols = '';
foreach ($ddl['columns'] as $colDdl) {
if ($cols != '') $cols .= ', ';
if ($colDdl['type'] == 'DATE') {
$cols .= 'to_char(' . $colDdl['name'] . ',\'YYYY-mm-dd\') ' . $colDdl['name'];
} else {
$cols .= $colDdl['name'];
}
}
$sql = "SELECT $cols FROM \"$this->name\"";
$params = [];
$sql .= $this->makeWhere($where, $options, $params);
if ($options['orderBy']) {
$sql .= ' ORDER BY ' . $options['orderBy'];
}
$select = $this->getBdd()->select($sql, $params);
/* Mise en forme des résultats */
$data = [];
foreach ($select as $d) {
foreach ($d as $c => $v) {
$d[$c] = $this->sqlToVal($v, $ddl['columns'][$c]);
}
$keyValue = $this->makeKey($d, $options['key']);
$data[$keyValue] = $d;
}
return $data;
}
/**
* @param array $data
* @param array $options
*
* @return bool
* @throws Exception\BddCompileException
* @throws Exception\BddException
* @throws Exception\BddIndexExistsException
*/
public function insert(array $data, array $options = []): bool
{
if (!isset($data['ID']) && $this->hasId() && $this->hasSequence()) {
$data['ID'] = $this->getBdd()->sequenceNextVal($this->ddl['sequence']);
}
$cols = array_keys($data);
$cols = implode(', ', $cols);
$vals = '';
foreach ($data as $col => $val) {
if ($vals != '') $vals .= ',';
$transVal = ':' . $col;
if (isset($options['columns'][$col]['transformer'])) {
$transVal = '(' . sprintf($options['columns'][$col]['transformer'], $transVal) . ')';
}
$vals .= $transVal;
}
$sql = "INSERT INTO \"$this->name\" ($cols) VALUES ($vals)";
return $this->getBdd()->exec($sql, $data);
}
public function update(array $data, $where = null, array $options = []): bool
{
$params = [];
$dataSql = '';
foreach ($data as $col => $val) {
if ($dataSql != '') $dataSql .= ',';
$transVal = ':new_' . $col;
if (isset($options['columns'][$col]['transformer'])) {
$transVal = '(' . sprintf($options['columns'][$col]['transformer'], $transVal) . ')';
}
$dataSql .= $col . '=' . $transVal;
$params['new_' . $col] = $val;
}
$sql = "UPDATE \"$this->name\" SET $dataSql" . $this->makeWhere($where, $options, $params);
return $this->getBdd()->exec($sql, $params);
}
/**
* @param int|string|array|null $where
* @param array $options
*
* @return bool
*/
public function delete($where, array $options = []): bool
{
$params = [];
$sql = "DELETE FROM \"$this->name\"" . $this->makeWhere($where, $options, $params);
return $this->getBdd()->exec($sql, $params);
}
/**
* Vide une table
*
* @param string $table
*
* @return bool
*/
public function truncate(): bool
{
$sql = "TRUNCATE TABLE \"$this->name\"";
return $this->getBdd()->exec($sql);
}
public function merge(array $data, $key, array $options = [])
{
/* Initialisation */
$defaultOptions = [
'where' => null,
'key' => $key,
];
$options = array_merge($defaultOptions, $options);
$ddl = $this->getDdl();
$diff = [];
/* Chargement des données actuelles, à mettre à jour */
$oldData = $this->select($options['where'], $options);
foreach ($oldData as $k => $d) {
if (!isset($diff[$k])) {
$diff[$k] = ['old' => [], 'new' => []];
}
$diff[$k]['old'] = $d;
}
/* Mise en forme des nouvelles données */
foreach ($data as $d) {
foreach ($d as $c => $v) {
if (isset($options['columns'][$c]['transformer'])) {
$d[$c] = $this->transform($v, $options['columns'][$c]['transformer'], $ddl['columns'][$c]);
}
}
$k = $this->makeKey($d, $key);
if (!isset($diff[$k])) {
$diff[$k] = ['old' => [], 'new' => []];
}
$diff[$k]['new'] = $d;
}
/* Traitement */
foreach($diff as $dr){
$old = $dr['old'];
$new = $dr['new'];
if (empty($old)){ // INSERT
$this->insert($new);
}elseif(empty($new)){ // DELETE
$this->delete($this->makeKeyArray($old, $key));
}else{ // UPDATE si différent!!
$toUpdate = [];
foreach($old as $c => $ov){
if ($c != 'ID' && isset($new[$c]) && $new[$c] !== $old[$c]){
$toUpdate[$c] = $new[$c];
}
}
if (!empty($toUpdate)){
$this->update($toUpdate, $this->makeKeyArray($old,$key));
}
}
}
}
private function makeKeyArray(array $data, $key): array
{
if (!$key && $this->hasId()) {
$key = 'ID';
}
$key = (array)$key;
$keyArray = [];
foreach ($key as $kc) {
$keyArray[$kc] = $data[$kc];
}
return $keyArray;
}
private function makeKey(array $data, $key): string
{
$keyArray = $this->makeKeyArray($data, $key);
$keyVal = '';
foreach ($keyArray as $v) {
if ($keyVal != '') $keyVal .= '_';
if ($v instanceof \DateTime) {
$keyVal .= $v->format('Y-m-d');
} else {
$keyVal .= (string)$v;
}
}
return $keyVal;
}
/**
* @param int|string|array|null $where
* @param array $options
*
* @return string
*/
private function makeWhere($where, array $options, array &$params): string
{
if ($where && !is_array($where) && $this->hasId()) {
$where = ['ID' => $where];
}
if ($where) {
$whereSql = '';
foreach ($where as $c => $v) {
if ($whereSql != '') {
$whereSql .= ' AND ';
}
$transVal = ':' . $c;
if (isset($options['columns'][$c]['transformer'])) {
$transVal = '(' . sprintf($options['columns'][$c]['transformer'], $transVal) . ')';
}
$whereSql .= $c . ' = ' . $transVal;
$params[$c] = $v;
}
return ' WHERE ' . $whereSql;
}
return '';
}
/**
* @return bool
*/
protected function hasId(): bool
{
$ddl = $this->getDdl();
return isset($ddl['columns']['ID']);
}
/**
* @return bool
*/
protected function hasSequence(): bool
{
$ddl = $this->getDdl();
return $ddl['sequence'] != null;
}
protected function transform($value, string $transformer, array $ddl)
{
if (!isset($this->transformCache[$transformer][$value])) {
$val = $this->getBdd()->select(sprintf($transformer, ':val'), ['val' => $value]);
$this->transformCache[$transformer][$value] = $this->sqlToVal(current($val[0]), $ddl);
}
return $this->transformCache[$transformer][$value];
}
protected function sqlToVal($value, array $ddl)
{
switch ($ddl['type']) {
case 'NUMBER':
if (1 == $ddl['precision']) {
return $value === '1';
} else {
return (int)$value;
}
case 'FLOAT':
return (float)$value;
case 'VARCHAR2':
case 'CLOB':
return $value;
case 'DATE':
$date = \DateTime::createFromFormat('Y-m-d', $value);
$date->setTime(0, 0, 0, 0);
return $date;
case 'BLOB':
return $value;
default:
throw new \Exception("Type de donnée " . $ddl['type'] . " non géré.");
}
return $value;
}
}
\ No newline at end of file
...@@ -274,6 +274,43 @@ class OseAdmin ...@@ -274,6 +274,43 @@ class OseAdmin
public function majPrivileges()
{
/* Chargement des categories en config */
$data = require $this->getOseDir() . 'data/privileges.php';
$categories = [];
$privileges = [];
foreach ($data as $code => $record) {
$categories[] = [
'CODE' => $code,
'LIBELLE' => $record['libelle'],
'ORDRE' => count($categories) + 1,
];
$io = 0;
foreach ($record['privileges'] as $pcode => $plib) {
$io++;
$privileges[] = [
'CATEGORIE_ID' => $code,
'CODE' => $pcode,
'LIBELLE' => $plib,
'ORDRE' => $io,
];
}
}
/* Mise à jour */
$this->getBdd()->getTable('CATEGORIE_PRIVILEGE')->merge($categories, 'CODE');
$this->getBdd()->getTable('PRIVILEGE')->merge(
$privileges,
['CATEGORIE_ID', 'CODE'],
['columns' => ['CATEGORIE_ID' => ['transformer' => 'SELECT id FROM categorie_privilege WHERE code = %s']]]
);
/* Vidage du fichier de cache */
}
public function exec($args) public function exec($args)
{ {
$this->console->passthru("php " . $this->getOseDir() . "/public/index.php " . $args); $this->console->passthru("php " . $this->getOseDir() . "/public/index.php " . $args);
......
<?php
return [
'odf' => [
'libelle' => 'Gestion de l\'offre de formation',
'privileges' => [
'visualisation' => 'Visualisation',
'export-csv' => 'Export CSV',
'element-visualisation' => 'Enseignements - Visualisation',
'element-edition' => 'Enseignements - Édition',
'etape-visualisation' => 'Formations - Visualisation',
'etape-edition' => 'Formations - Édition',
'centres-cout-edition' => 'Centres de coûts - Édition',
'modulateurs-edition' => 'Modulateurs - Édition',
'taux-mixite-edition' => 'Taux de mixité - Édition',
'element-vh-edition' => 'Enseignements - Volumes horaires - Édition',
'element-vh-visualisation' => 'Enseignements - Volumes horaires - Visualisation',
'grands-types-diplome-visualisation' => 'Grands types de diplômes (visualisation)',
'grands-types-diplome-edition' => 'Grands types de diplômes (édition)',
'types-diplome-visualisation' => 'Types de diplômes (visualisation)',
'types-diplome-edition' => 'Types de diplômes (édition)',
],
],
'discipline' => [
'libelle' => 'Gestion des disciplines',
'privileges' => [
'visualisation' => 'Visualisation',
'edition' => 'Édition',
'gestion' => 'Gestion',
],
],
'intervenant' => [
'libelle' => 'Intervenant',
'privileges' => [
'recherche' => 'Recherche',
'fiche' => 'Visualisation de la fiche',
'calcul-hetd' => 'Calcul HETD',
'edition' => 'Edition',
'suppression' => 'Suppression',
'statut-edition' => 'Statuts (Édition)',
'statut-visualisation' => 'Statuts (Visualisation)',
],
],
'modif-service-du' => [
'libelle' => 'Modification de service dû',
'privileges' => [
'association' => 'Association',
'visualisation' => 'Visualisation',
'edition' => 'Édition',
'export-csv' => 'Export CSV',
'gestion-edition' => 'Gestion (édition)',
'gestion-visualisation' => 'Gestion (visualisation)',
],
],
'dossier' => [
'libelle' => 'Données personnelles',
'privileges' => [
'visualisation' => 'Visualisation',
'edition' => 'Édition',
'validation' => 'Validation',
'suppression' => 'Suppression',
'devalidation' => 'Dévalidation',
'differences' => 'Différences avec Harpège',
'purger-differences' => 'Purger les différences',
],
],
'piece-justificative' => [
'libelle' => 'Pièces justificatives',
'privileges' => [
'visualisation' => 'Visualisation',
'edition' => 'Édition',
'validation' => 'Validation',
'devalidation' => 'Dévalidation',
'gestion-edition' => 'Gestion des pièces justificatives (édition)',
'gestion-visualisation' => 'Gestion des pièces justificatives (visualisation)',
'telechargement' => 'Téléchargement',
],
],
'enseignement' => [
'libelle' => 'Enseignement',
'privileges' => [
'visualisation' => 'Visualisation',
'edition' => 'Édition',
'exterieur' => 'Saisie de service dans une autre autre université',
'validation' => 'Validation',
'devalidation' => 'Dévalidation',
'export-pdf' => 'Export PDF',
'export-csv' => 'Export CSV',
'import-intervenant-previsionnel-agenda' => 'Import service prévisionnel depuis agenda',
'import-intervenant-realise-agenda' => 'Import service réalisé depuis agenda',
],
],
'motif-non-paiement' => [
'libelle' => 'Motifs de non paiement (pour enseignements)',
'privileges' => [
'visualisation' => 'Visualisation',
'edition' => 'Édition',
],
],
'referentiel' => [
'libelle' => 'Référentiel',
'privileges' => [
'visualisation' => 'Visualisation',
'edition' => 'Édition',
'validation' => 'Validation',
'admin-edition' => 'Administration - Édition',
'devalidation' => 'Dévalidation',
'admin-visualisation' => 'Administration - Visualisation',
],
],
'agrement' => [
'libelle' => 'Agréments',
'privileges' => [
'conseil-academique-visualisation' => 'Conseil académique - Visualisation',
'conseil-academique-edition' => 'Conseil académique - Édition',
'conseil-restreint-visualisation' => 'Conseil restreint - Visualisation',
'conseil-restreint-edition' => 'Conseil restreint - Édition',
'conseil-academique-suppression' => 'Conseil académique - Suppression',
'conseil-restreint-suppression' => 'Conseil restreint - Suppression',
'export-csv' => 'Export CSV',
],
],
'contrat' => [
'libelle' => 'Contrats de travail/Avenants',
'privileges' => [
'visualisation' => 'Visualisation',
'creation' => 'Création d\'un projet',
'suppression' => 'Suppression d\'un projet',
'validation' => 'Validation',
'devalidation' => 'Dévalidation',
'depot-retour-signe' => 'Dépôt de contrat signé',
'saisie-date-retour-signe' => 'Saisie de date retour',
'modeles-visualisation' => 'Visualisation des modèles',
'modeles-edition' => 'Édition des modèles',
'projet-generation' => 'Génération de projet de contrat',
'contrat-generation' => 'Génération de contrat',
],
],
'mise-en-paiement' => [
'libelle' => 'Mises en paiement',
'privileges' => [
'visualisation-gestion' => 'Visualisation (Gestion)',
'demande' => 'Demande',
'export-csv' => 'Export CSV',
'export-pdf' => 'Export PDF',
'mise-en-paiement' => 'Mise en paiement',
'export-paie' => 'Export vers le logiciel de paie',
'edition' => 'Annulation de mises en paiement',
'visualisation-intervenant' => 'Visualisation (Intervenant)',
],
],
'indicateur' => [
'libelle' => 'Indicateurs',
'privileges' => [
'visualisation' => 'Visualisation',
'abonnement' => 'Abonnement',
'abonnements-edition' => 'Abonnements - Édition',
'abonnements-visualisation' => 'Abonnements - Visualisation',
'envoi-mail-intervenants' => 'Mail aux intervenants',
],
],
'droit' => [
'libelle' => 'Gestion des droits d\'accès',
'privileges' => [
'role-visualisation' => 'Rôles - Visualisation',
'role-edition' => 'Rôles - Édition',
'privilege-visualisation' => 'Privilèges - Visualisation',
'privilege-edition' => 'Privilèges - Édition',
'affectation-visualisation' => 'Affectations - Visualisation',
'affectation-edition' => 'Affectations - Édition',
],
],
'import' => [
'libelle' => 'Import',
'privileges' => [
'ecarts' => 'Écarts',
'maj' => 'Mise à jour',
'tbl' => 'Tableau de bord',
'vues-procedures' => 'Gestion des vues et procédures',
'sources-edition' => 'Sources (édition)',
'sources-visualisation' => 'Sources (visualisation)',
'tables-edition' => 'Tables (édition)',
'tables-visualisation' => 'Tables (visualisation)',
],
],
'type-intervention' => [
'libelle' => 'Type d\'intervention',
'privileges' => [
'visualisation' => 'Visualisation',
'edition' => 'Édition',
],
],
'unicaen-tbl' => [
'libelle' => 'Tableaux de bord',
'privileges' => [
'admin' => 'Gestion des tableaux de bord',
'update-actuproc' => 'Mise à jour des procédures d\'actualisation',
'actualisation' => 'Actualisation',
],
],
'modulateur' => [
'libelle' => 'Modulateurs',
'privileges' => [
'edition' => 'Édition',
'visualisation' => 'Visualisation',
],
],
'budget' => [
'libelle' => 'Budget',
'privileges' => [
'visualisation' => 'Visualisation',
'edition-engagement-composante' => 'Dotation ressources propres',
'export' => 'Export CSV',
'edition-engagement-etablissement' => 'Dotation paye état',
'type-dotation-edition' => 'Types de dotation - Édition',
'type-dotation-visualisation' => 'Types de dotation - Visualisation',
'cc-activite-visualisation' => 'CC activité - Visualisation',
'cc-activite-edition' => 'CC activité - Édition',
'types-ressources-visualisation' => 'Types de ressources - Visualisation',
'types-ressources-edition' => 'Types de ressources - Édition',
],
],
'pilotage' => [
'libelle' => 'Pilotage',
'privileges' => [
'ecarts-etats' => 'Ecarts d\'heures entre états',
'visualisation' => 'Visualisation',
],
],
'chargens' => [
'libelle' => 'Charges d\'enseignement',
'privileges' => [
'formation-assiduite-edition' => 'Édition des formations (assiduité)',
'formation-effectifs-edition' => 'Édition des formations (effectifs)',
'formation-seuils-edition' => 'Édition des formations (seuils)',
'formation-visualisation' => 'Visualisation des formations',
'scenario-composante-edition' => 'Édition des scénarios (composantes)',
'scenario-etablissement-edition' => 'Édition des scénarios (établissement)',
'scenario-visualisation' => 'Visualisation des scénarios',
'seuil-composante-edition' => 'Édition des seuil (composantes)',
'seuil-composante-visualisation' => 'Visualisation des seuils (composantes)',
'seuil-etablissement-edition' => 'Édition des seuil (établissement)',
'seuil-etablissement-visualisation' => 'Visualisation des seuils (établissement)',
'visualisation' => 'Visualisation',
'scenario-duplication' => 'Duplication de scénario',
'formation-actif-edition' => 'Édition des formations (activation liens)',
'formation-choix-edition' => 'Édition des formations (choix liens)',
'formation-poids-edition' => 'Édition des formations (poids liens)',
'export-csv' => 'Export CSV',
'depassement-csv' => 'Dépassement services/charges (CSV)',
],
],
'etat-sortie' => [
'libelle' => 'États de sortie',
'privileges' => [
'administration-visualisation' => 'Administration (visualisation)',
'administration-edition' => 'Administration (édition)',
],
],
'parametres' => [
'libelle' => 'Paramétrages',
'privileges' => [
'general-edition' => 'Général - Édition',
'general-visualisation' => 'Général - Visualisation',
'campagnes-saisie-edition' => 'Campagnes de saisie - Édition',
'campagnes-saisie-visualisation' => 'Campagnes de saisie - Visualisation',
'annees-edition' => 'Années - Édition',
'annees-visualisation' => 'Années - Visualisation',
],
],
'cloture' => [
'libelle' => 'Clôture des services réalisés',
'privileges' => [
'cloture' => 'Clôture',
'reouverture' => 'Réouverture',
'edition-services' => 'Modification des services après clôture',
'edition-services-avec-mep' => 'Modification des services après clôture et mises en paiement',
],
],
'structures' => [
'libelle' => 'Structures',
'privileges' => [
'administration-visualisation' => 'Administration (visualisation)',
'administration-edition' => 'Administration (édition)',
],
],
'motifs-modification-service-du' => [
'libelle' => 'Motifs de modification de service dû',
'privileges' => [
'visualisation' => 'Administration (visualisation)',
'edition' => 'Administration (édition)',
],
],
'domaines-fonctionnels' => [
'libelle' => 'Domaines fonctionnels',
'privileges' => [
'administration-visualisation' => 'Administration (visualisation)',
'administration-edition' => 'Administration (édition)',
],
],
'centres-couts' => [
'libelle' => 'Paramétrage des centres de coûts',
'privileges' => [
'administration-visualisation' => 'Administration (visualisation)',
'administration-edition' => 'Administration (édition)',
],
],
'workflow' => [
'libelle' => 'Gestion du Workflow',
'privileges' => [
'dependances-visualisation' => 'Dépendances (visualisation)',
'dependances-edition' => 'Dépendances (édition)',
],
],
'plafonds' => [
'libelle' => 'Plafonds',
'privileges' => [
'gestion-visualisation' => 'Gestion (visualisation)',
'gestion-edition' => 'Gestion (édition)',
],
],
'formule' => [
'libelle' => 'Formule de calcul',
'privileges' => [
'tests' => 'Tests',
],
],
];
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment