This commit is contained in:
2025-07-27 16:22:54 +02:00
parent 4378f06c05
commit 8127d6e830
12 changed files with 1116 additions and 46 deletions

View File

@ -30,7 +30,7 @@ security:
access_control:
- { path: ^/login, roles: PUBLIC_ACCESS }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/, roles: ROLE_USER }
- { path: ^/, roles: ROLE_ADMIN }
when@test:
security:

View File

@ -29,12 +29,27 @@ global:
source: env/.env
type: text
required: false
NINEAPACHE_LETSENCRYPT:
id: NINEAPACHE_LETSENCRYPT
label: Activer certificat Letsencrypt
source: env/.env
type: bool
required: false
authentification:
id: authentification
label: Authentification
style: col-md-12
style: col-md-6
vars:
MASTERIDENTITY:
id: MASTERIDENTITY
label: Maitre Identité
source: env/.env
type: choice
choices: "SQL,SSO"
required: true
master: masteridentity
MODE_AUTH:
id: MODE_AUTH
label: Mode d'Authentification
@ -57,26 +72,124 @@ authentification:
source: env/.env
type: string
required: true
slave: modeauth=CAS
slave: modeauth=CAS&&keycloakactive=0
CAS_PORT:
id: CAS_PORT
label: Port du serveur CAS
source: env/.env
type: string
required: true
slave: modeauth=CAS
slave: modeauth=CAS&&keycloakactive=0
CAS_PATH:
id: CAS_PATH
label: Path du serveur CAS
source: env/.env
type: string
required: true
slave: modeauth=CAS
slave: modeauth=CAS&&keycloakactive=0
CAS_URL:
id: CAS_URL
label: Url du serveur CAS
source: env/.env
type: string
required: true
slave: modeauth=CAS&&keycloakactive=0
CAS_USERNAME:
id: CAS_USERNAME
label: Attribut SSO Username
source: env/.env
type: string
required: true
slave: modeauth=CAS&&keycloakactive=0
CAS_MAIL:
id: CAS_MAIL
label: Attribut SSO Email
source: env/.env
type: string
required: true
slave: modeauth=CAS&&keycloakactive=0
CAS_LASTNAME:
id: CAS_LASTNAME
label: Attribut SSO Lastname
source: env/.env
type: string
required: true
slave: modeauth=CAS&&keycloakactive=0
CAS_FIRSTNAME:
id: CAS_FIRSTNAME
label: Attribut SSO Firstname
source: env/.env
type: string
required: true
slave: modeauth=CAS&&keycloakactive=0
mariadb:
id: mariadb
label: MariaDB
style: col-md-6
vars:
MARIADB_LOCAL:
id: MARIADB_LOCAL
label: MariaDB Local
source: env/.env
type: bool
required: true
master: mariadblocal
expert: true
MARIADB_HOST:
id: MARIADB_HOST
label: Host MariaDB
source: env/.env
type: string
required: true
slave: mariadblocal=0
MARIADB_PORT:
id: MARIADB_PORT
label: Port MariaDB
source: env/.env
type: string
required: true
slave: mariadblocal=0
MARIADB_USER:
id: MARIADB_USER
label: User MariaDB
source: env/.env
type: string
required: true
slave: mariadblocal=0
redis:
id: redis
label: Redis
style: col-md-6
vars:
REDIS_LOCAL:
id: REDIS_LOCAL
label: Redis Local
source: env/.env
type: bool
required: true
master: redislocal
expert: true
REDIS_HOST:
id: REDIS_HOST
label: Host Redis
source: env/.env
type: string
required: true
slave: redislocal=0
REDIS_PORT:
id: REDIS_PORT
label: Port Redis
source: env/.env
type: string
required: true
slave: redislocal=0
admin:
id: admin
label: Compte Administrateur
style: col-md-12
label: Comptes Administrateur
style: col-md-6
vars:
ADMIN_USER:
id: ADMIN_USER
@ -98,14 +211,421 @@ admin:
type: text
required: true
# password:
# CAS_PASSWORD=${ADMIN_PASSWORD}-keycloak
password:
id: password
label: Passwords
style: col-md-6
vars:
ADMIN_PASSWORD:
id: ADMIN_PASSWORD
label: Password du compte administrateur
source: env/.env
type: text
required: true
KEYCLOAK_PASSWORD:
id: KEYCLOAK_PASSWORD
label: Keycloak Password administrateur
source: env/.env
type: text
required: true
expert: true
slave: keycloakactive=1
MARIADB_ROOT_PASSWORD:
id: MARIADB_ROOT_PASSWORD
label: Root BDD Password
source: env/.env
type: text
required: true
expert: true
MARIADB_PASSWORD:
id: MARIADB_PASSWORD
label: User BDD Password
source: env/.env
type: text
required: true
expert: true
LDAP_PASSWORD:
id: LDAP_PASSWORD
label: LDAP Writter User Password
source: env/.env
type: text
required: true
slave: openldaplocal=0
expert: true
# Email
email:
id: email
label: Email
style: col-md-6
vars:
MAILER_DSN:
id: MAILER_DSN
label: Mailer DSN
source: env/.env
type: text
required: true
FAKESMTP_ACTIVATE:
id: FAKESMTP_ACTIVATE
label: activer FakeSMTP
source: env/.env
type: bool
required: true
master: fakesmtpactivate
expert: true
FAKESMTP_LOCAL:
id: FAKESMTP_LOCAL
label: FakeSMTP local
source: env/.env
type: bool
required: true
slave: fakesmtpactivate=1
master: fakesmtplocal
expert: true
FAKESMTP_URL:
id: FAKESMTP_URL
label: Url du fakeSMTP distant
source: env/.env
type: text
required: true
slave: fakesmtplocal=0
expert: true
annuaire:
id: annuaire
label: Annuaire
style: col-md-12
vars:
OPENLDAP_ACTIVATE:
id: OPENLDAP_ACTIVATE
label: Activer OpenLDAP
source: env/.env
type: bool
required: true
master: openldapactivate
OPENLDAP_LOCAL:
id: OPENLDAP_LOCAL
label: OpenLDAP local
source: env/.env
type: bool
required: true
slave: openldapactivate=1
master: openldaplocal
expert: true
LDAP_BASEDN:
id: LDAP_BASEDN
label: Base DN
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_ADMIN_USERNAME:
id: LDAP_ADMIN_USERNAME
label: LDAP Writter User
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_USER:
id: LDAP_USER
label: LDAP DN Writter User
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_OUORGANISATION:
id: LDAP_OUORGANISATION
label: LDAP OU Organisation
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_OUNIVEAU01:
id: LDAP_OUNIVEAU01
label: LDAP OU Niveau 01
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_OUNIVEAU02:
id: LDAP_OUNIVEAU02
label: LDAP OU Niveau 02
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_OUNIVEAU03:
id: LDAP_OUNIVEAU03
label: LDAP OU Niveau 03
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_OUNIVEAU04:
id: LDAP_OUNIVEAU04
label: LDAP OU Niveau 04
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_OUGROUP:
id: LDAP_OUGROUP
label: LDAP OU Groupe
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_BASEORGANISATION:
id: LDAP_BASEORGANISATION
label: LDAP Base Organisation
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_BASENIVEAU01:
id: LDAP_BASENIVEAU01
label: LDAP Base Niveau 01
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_BASENIVEAU02:
id: LDAP_BASENIVEAU02
label: LDAP Base Niveau 02
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_BASENIVEAU03:
id: LDAP_BASENIVEAU03
label: LDAP Base Niveau 03
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_BASENIVEAU04:
id: LDAP_BASENIVEAU04
label: LDAP Base Niveau 04
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_BASEUSER:
id: LDAP_BASEUSER
label: LDAP Base User
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_BASEGROUP:
id: LDAP_BASEGROUP
label: LDAP Base Group
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_USERNAME:
id: LDAP_USERNAME
label: Attribut username
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_FIRSTNAME:
id: LDAP_FIRSTNAME
label: Attribut firstname
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_LASTNAME:
id: LDAP_LASTNAME
label: Attribut lastname
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_DISPLAYNAME:
id: LDAP_DISPLAYNAME
label: Attribut displayname
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_EMAIL:
id: LDAP_EMAIL
label: Attribut email
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_MEMBEROF:
id: LDAP_MEMBEROF
label: Attribut memberof
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_GROUP_GID:
id: LDAP_GROUP_GID
label: Attribut gidnumber
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_GROUP_NAME:
id: LDAP_GROUP_NAME
label: Attribut cn
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_GROUP_MEMBER:
id: LDAP_GROUP_MEMBER
label: Attribut memberUid
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_GROUP_MEMBERISDN:
id: LDAP_GROUP_MEMBERISDN
label: Attribut member is a DN
source: env/.env
type: bool
required: true
slave: openldaplocal=0
LDAP_LOGIN_FILTER:
id: LDAP_LOGIN_FILTER
label: Filtre login
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_USER_FILTER:
id: LDAP_USER_FILTER
label: Filtre utilisateur
source: env/.env
type: text
required: true
slave: openldaplocal=0
LDAP_GROUP_FILTER:
id: LDAP_GROUP_FILTER
label: Filtre groupe
source: env/.env
type: text
required: true
slave: openldaplocal=0
portail:
id: portail
label: Portail Ninegate
style: col-md-12
vars:
NINEGATE_ACTIVATE:
id: NINEGATE_ACTIVATE
label: Activer Portail Ninegate
source: env/.env
type: bool
required: true
master: ninegateactivate
NINEGATE_LOCAL:
id: NINEGATE_LOCAL
label: Ninegate local
source: env/.env
type: bool
required: true
slave: ninegateactivate=1
master: ninegatelocal
expert: true
MODEREGISTRATION:
id: MODEREGISTRATION
label: Mode de Registration
source: env/.env
type: choice
choices: "none,byadmin,byuser"
required: true
slave: ninegatelocal=1&&masteridentity=SQL
NINEGATE_URL:
id: NINEGATE_URL
label: Url du Ninegate distant
source: env/.env
type: text
required: true
slave: ninegatelocal=0
expert: true
LDAP_SYNC:
id: LDAP_SYNC
label: Activer la synchronisation Annuaire
source: env/.env
type: bool
required: true
master: ldapsync
slave: openldapactivate=1
LDAP_TEMPLATE:
id: LDAP_TEMPLATE
label: Modele Annuaire
source: env/.env
type: choice
choices: "open,scribe"
required: true
master: ldaptemplate
slave: ldapsync=1&&openldaplocal=0
SCRIBE_GROUP:
id: SCRIBE_GROUP
label: Synchroniser les groupes SCRIBE
source: env/.env
type: bool
required: true
slave: LDAP_TEMPLATE=scribe
SCRIBE_MASTER:
id: SCRIBE_MASTER
label: Synchroniser les professeurs SCRIBE comme Master
source: env/.env
type: bool
required: true
slave: ldaptemplate=scribe
OPENLDAPREQNIVEAU01:
id: OPENLDAPREQNIVEAU01
label: Requete LDAP des Niveau 01
source: env/.env
type: text
required: true
slave: ldaptemplate=open
OPENLDAPSYNCHROGROUP:
id: OPENLDAPSYNCHROGROUP
label: Synchroniser les groupes
source: env/.env
type: bool
required: true
master: openldapsynchrogroup
slave: ldaptemplate=open
OPENLDAPREQGROUP:
id: OPENLDAPREQGROUP
label: Requete LDAP des Groupes
source: env/.env
type: text
required: true
slave: openldapsynchrogroup=1
applications:
id: applications
label: Applications
style: col-md-12
vars:
DOKUWIKI_ACTIVATE:
id: DOKUWIKI_ACTIVATE
label: Activer Dokuwiki
source: env/.env
type: bool
required: true
master: dokuwikiactivate
KEEWEB_ACTIVATE:
id: KEEWEB_ACTIVATE
label: Activer Keeweb
source: env/.env
type: bool
required: true
master: keewebactivate
KOMGA_ACTIVATE:
id: KOMGA_ACTIVATE
label: Activer Komga
@ -113,6 +633,13 @@ applications:
type: bool
required: true
master: komgaactivate
NEXTCLOUD_ACTIVATE:
id: NEXTCLOUD_ACTIVATE
label: Activer Nextcloud
source: env/.env
type: bool
required: true
master: nextcloudactivate
NINEBOARD_ACTIVATE:
id: NINEBOARD_ACTIVATE
label: Activer Nineboard
@ -134,6 +661,97 @@ applications:
type: bool
required: true
master: ninefolioactivate
NINESCHOOL_ACTIVATE:
id: NINESCHOOL_ACTIVATE
label: Activer Nineschool
source: env/.env
type: bool
required: true
master: nineschoolactivate
PIWIGO_ACTIVATE:
id: PIWIGO_ACTIVATE
label: Activer Piwigo
source: env/.env
type: bool
required: true
master: piwigoactivate
WORDPRESS_ACTIVATE:
id: WORDPRESS_ACTIVATE
label: Activer Wordpress
source: env/.env
type: bool
required: true
master: wordpressactivate
applicationadmins:
id: applicationadmins
label: Applications Administrateur
style: col-md-12
vars:
NINECONFIG_ACTIVATE:
id: NINECONFIG_ACTIVATE
label: Activer Nineconfig
source: env/.env
type: bool
required: true
ADMINER_ACTIVATE:
id: ADMINER_ACTIVATE
label: Activer Adminer
source: env/.env
type: bool
required: true
master: admineractivate
PHPLDAPADMIN_ACTIVATE:
id: PHPLDAPADMIN_ACTIVATE
label: Activer PhpLDAPAdmin
source: env/.env
type: bool
required: true
master: phpldapadminactivate
dokuwiki:
id: dokuwiki
label: Dokuwiki
style: col-md-6
vars:
DOKUWIKI_LOCAL:
id: DOKUWIKI_LOCAL
label: Dokuwiki local
source: env/.env
type: bool
required: true
slave: dokuwikiactivate=1
master: dokuwikilocal
expert: true
DOKUWIKI_URL:
id: DOKUWIKI_URL
label: Url du Dokuwiki distant
source: env/.env
type: text
required: true
slave: dokuwikilocal=0
keeweb:
id: keeweb
label: Keeweb
style: col-md-6
vars:
KEEWEB_LOCAL:
id: KEEWEB_LOCAL
label: Keeweb local
source: env/.env
type: bool
required: true
slave: keewebactivate=1
master: keeweblocal
expert: true
KEEWEB_URL:
id: KEEWEB_URL
label: Url du Keeweb distant
source: env/.env
type: text
required: true
slave: keeweblocal=0
komga:
id: komga
@ -148,6 +766,7 @@ komga:
required: true
slave: komgaactivate=1
master: komgalocal
expert: true
KOMGA_URL:
id: KOMGA_URL
label: Url du Komga distant
@ -156,6 +775,28 @@ komga:
required: true
slave: komgalocal=0
nextcloud:
id: nextcloud
label: Nextcloud
style: col-md-6
vars:
NEXTCLOUD_LOCAL:
id: NEXTCLOUD_LOCAL
label: Nextcloud local
source: env/.env
type: bool
required: true
slave: nextcloudactivate=1
master: nextcloudlocal
expert: true
NEXTCLOUD_URL:
id: NEXTCLOUD_URL
label: Url du Nextcloud distant
source: env/.env
type: text
required: true
slave: nextcloudlocal=0
nineboard:
id: nineboard
label: Nineboard
@ -169,6 +810,7 @@ nineboard:
required: true
slave: nineboardactivate=1
master: nineboardlocal
expert: true
NINEBOARD_URL:
id: NINEBOARD_URL
label: Url du Nineboard distant
@ -190,6 +832,7 @@ ninecompta:
required: true
slave: ninecomptaactivate=1
master: ninecomptalocal
expert: true
NINECOMPTA_URL:
id: NINECOMPTA_URL
label: Url du Ninecompta distant
@ -211,6 +854,7 @@ ninefolio:
required: true
slave: ninefolioactivate=1
master: ninefoliolocal
expert: true
NINEFOLIO_URL:
id: NINEFOLIO_URL
label: Url du Ninefolio distant
@ -218,3 +862,113 @@ ninefolio:
type: text
required: true
slave: ninefoliolocal=0
nineschool:
id: nineschool
label: Nineschool
style: col-md-6
vars:
NINESCHOOL_LOCAL:
id: NINESCHOOL_LOCAL
label: Nineschool local
source: env/.env
type: bool
required: true
slave: nineschoolactivate=1
master: nineschoollocal
expert: true
NINESCHOOL_URL:
id: NINESCHOOL_URL
label: Url du Nineschool distant
source: env/.env
type: text
required: true
slave: nineschoollocal=0
piwigo:
id: piwigo
label: Piwigo
style: col-md-6
vars:
PIWIGO_LOCAL:
id: PIWIGO_LOCAL
label: Piwigo local
source: env/.env
type: bool
required: true
slave: piwigoactivate=1
master: piwigolocal
expert: true
PIWIGO_URL:
id: PIWIGO_URL
label: Url du Piwigo distant
source: env/.env
type: text
required: true
slave: piwigolocal=0
wordpress:
id: wordpress
label: Wordpress
style: col-md-6
vars:
WORDPRESS_LOCAL:
id: WORDPRESS_LOCAL
label: Wordpress local
source: env/.env
type: bool
required: true
slave: wordpressactivate=1
master: wordpresslocal
expert: true
WORDPRESS_URL:
id: WORDPRESS_URL
label: Url du Wordpress distant
source: env/.env
type: text
required: true
slave: wordpresslocal=0
adminer:
id: adminer
label: Adminer
style: col-md-6
vars:
ADMINER_LOCAL:
id: ADMINER_LOCAL
label: Adminer local
source: env/.env
type: bool
required: true
slave: admineractivate=1
master: adminerlocal
expert: true
ADMINER_URL:
id: ADMINER_URL
label: Url du Adminer distant
source: env/.env
type: text
required: true
slave: adminerlocal=0
phpldapadmin:
id: phpldapadmin
label: phpLDAPAdmin
style: col-md-6
vars:
PHPLDAPADMIN_LOCAL:
id: PHPLDAPADMIN_LOCAL
label: phpLDAPAdmin local
source: env/.env
type: bool
required: true
slave: phpldapadminactivate=1
master: phpldapadminlocal
expert: true
PHPLDAPADMIN_URL:
id: PHPLDAPADMIN_URL
label: Url du phpLDAPAdmin distant
source: env/.env
type: text
required: true
slave: phpldapadminlocal=0

View File

@ -0,0 +1,6 @@
docker:
id: docker
source: misc/docker
misc:
id: misc
source: misc

23
misc/sample/env/.env vendored
View File

@ -22,7 +22,7 @@ ADMIN_PASSWORD=changeme
ADMIN_EMAIL=admin@noreply.fr
# MASTERIDENTITY
# SQL or SSO or (to do LDAP)
# SQL or SSO or LDAP
MASTERIDENTITY=SQL
# AUTHENTIFICATION
@ -46,8 +46,9 @@ NINEAPACHE_LETSENCRYPT=0
# FAKESMTP
# fake-smtp server
FAKESMTP_SERVICE_NAME=fakesmtp
FAKESMTP_ACTIVATE=0
FAKESMTP_LOCAL=0
FAKESMTP_ACTIVATE=1
FAKESMTP_URL=${PROTOCOLE}://${WEB_URL}/fakesmtp
# MTA
# passerelle courriel
@ -171,6 +172,12 @@ DOKUWIKI_ACTIVATE=0
DOKUWIKI_LOCAL=1
DOKUWIKI_URL=${PROTOCOLE}://${WEB_URL}/dokuwiki
# KEEWEB
KEEWEB_SERVICE_NAME=keeweb
KEEWEB_ACTIVATE=0
KEEWEB_LOCAL=1
KEEWEB_URL=${PROTOCOLE}://${WEB_URL}/keeweb
# KOMGA
KOMGA_SERVICE_NAME=komga
KOMGA_ACTIVATE=0
@ -214,12 +221,6 @@ NINESCHOOL_ACTIVATE=1
NINESCHOOL_LOCAL=1
NINESCHOOL_URL=${PROTOCOLE}://${WEB_URL}/nineschool
# NINESKELETOR
NINESKELETOR_SERVICE_NAME=nineskeletor
NINESKELETOR_ACTIVATE=0
NINESKELETOR_LOCAL=1
NINESKELETOR_URL=${PROTOCOLE}://${WEB_URL}/nineskeletor
# PIWIGO
PIWIGO_SERVICE_NAME=piwigo
PIWIGO_ACTIVATE=0
@ -232,6 +233,12 @@ WORDPRESS_ACTIVATE=1
WORDPRESS_LOCAL=1
WORDPRESS_URL=${PROTOCOLE}://${WEB_URL}/wordpress
# NINECONFIG
NINECONFIG_SERVICE_NAME=nineconfig
NINECONFIG_ACTIVATE=1
NINECONFIG_LOCAL=1
NINECONFIG_URL="${PROTOCOLE}://${WEB_URL}/nineconfig"
# ADMINER
ADMINER_SERVICE_NAME=adminer
ADMINER_ACTIVATE=1

View File

@ -1,4 +1,3 @@
APP_ENV=DEV
KOMGA_ACTIVATE=1
NINECOMPTA_ACTIVATE=1
NINEFOLIO_ACTIVATE=1

View File

@ -0,0 +1,43 @@
<?php
namespace App\Command;
use App\Service\DicosService;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: 'app:unusedvars',
description: 'Liste les variables .env/.local non référencées dans le dico',
)]
class UnusedEnvVarsCommand extends Command
{
private DicosService $dicosService;
public function __construct(DicosService $dicosService)
{
parent::__construct();
$this->dicosService = $dicosService;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$unusedKeys = $this->dicosService->findUnusedEnvKeys();
if (empty($unusedKeys)) {
$io->success('✅ Toutes les variables .env/.local sont bien référencées dans le dico.');
} else {
$io->title('🔍 Variables .env/.local non référencées dans le dico :');
foreach ($unusedKeys as $key) {
$io->writeln(" - <fg=yellow>$key</>");
}
}
return Command::SUCCESS;
}
}

View File

@ -4,18 +4,22 @@ namespace App\Controller;
use App\Form\DicosType;
use App\Service\DicosService;
use App\Service\VolumeService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class HomeController extends AbstractController
{
private DicosService $dicosService;
private VolumeService $volumeService;
public function __construct(DicosService $dicosService)
public function __construct(DicosService $dicosService, VolumeService $volumeService)
{
$this->dicosService = $dicosService;
$this->volumeService = $volumeService;
}
#[Route('/', name: 'app_home')]
@ -38,6 +42,33 @@ class HomeController extends AbstractController
]);
}
#[Route('/volume', name: 'app_volume')]
public function volume(Request $request)
{
// Récupération de la liste des volumes possibles
$volumes = $this->volumeService->load();
// Query
$volume = $request->query->get('volume');
$folder = $request->query->get('folder');
// Controler que le volume est autorisé
if ($volume && !array_key_exists($volume, $volumes)) {
throw new AccessDeniedException('Accès non autorisé.');
} elseif ($volume) {
$ls = $this->volumeService->ls($volumes[$volume]['source'], $folder);
}
return $this->render('home/volume.html.twig', [
'usemenu' => true,
'usesidebar' => false,
'maxwidth' => 1500,
'volumes' => $volumes,
'volume' => $volume,
'folder' => $folder,
]);
}
#[Route('/admin', name: 'app_admin')]
public function admin(): Response
{

View File

@ -16,7 +16,7 @@ class DicosType extends AbstractType
{
$builder
->add('submit', SubmitType::class, [
'label' => 'Valider',
'label' => 'Enregistrer',
'attr' => ['class' => 'btn btn-success no-print'],
]);
@ -67,6 +67,15 @@ class DicosType extends AbstractType
$options['attr']['class'] .= 'slave ';
}
if (array_key_exists('expert', $var)) {
$options['attr']['data-expert'] = $var['expert'];
$options['attr']['class'] .= 'expert ';
}
if (array_key_exists('default', $var)) {
$options['attr']['data-default'] = $var['default'];
}
$builder->add($var['id'], $type, $options);
}
}

View File

@ -96,7 +96,6 @@ class DicosService
foreach ($data['dicos'] as $section) {
foreach ($section['vars'] as $var) {
if ($var['default'] != $values[$var['id']]) {
dump($values[$var['id']]);
file_put_contents($this->routeSources.'/'.$var['source'].'.local', $var['id'].'='.$this->formatEnvValue($values[$var['id']]).PHP_EOL, FILE_APPEND);
}
}
@ -142,4 +141,44 @@ class DicosService
return $value;
}
public function findUnusedEnvKeys(): array
{
$allDeclaredKeys = [];
// Récupère toutes les clés de ton dico
$dicos = Yaml::parseFile($this->routeDicos.'/dicos.yml');
foreach ($dicos as $section) {
foreach ($section['vars'] as $var) {
$allDeclaredKeys[] = $var['id'];
}
}
// On récupère toutes les sources mentionnées
$sources = [];
foreach ($dicos as $section) {
foreach ($section['vars'] as $var) {
if (!in_array($var['source'], $sources)) {
$sources[] = $var['source'];
}
}
}
// Charger toutes les variables depuis les sources (.env et .env.local)
$allEnvKeys = [];
foreach ($sources as $source) {
$env = $this->parseDotEnvFile($this->routeSources.'/'.$source);
$envLocal = $this->parseDotEnvFile($this->routeSources.'/'.$source.'.local');
$allEnvKeys = array_merge($allEnvKeys, array_keys($env), array_keys($envLocal));
}
// Supprime les doublons
$allEnvKeys = array_unique($allEnvKeys);
// Différence entre variables trouvées et déclarées
$unused = array_diff($allEnvKeys, $allDeclaredKeys);
return array_values($unused);
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace App\Service;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Yaml\Yaml;
class VolumeService
{
private string $routeDicos;
private string $routeProject;
public function __construct(ParameterBagInterface $params)
{
$this->routeDicos = $params->get('routeDicos');
$this->routeProject = $params->get('kernel.project_dir');
}
public function load(): array
{
$path = $this->routeDicos.'/volumes.yml';
// On s'assure de disposer du dicos
if (!file_exists($path)) {
throw new \RuntimeException("Le fichier $path n'existe pas.");
}
// Parser le dicos
$data = Yaml::parseFile($path);
return $data ?? [];
}
public function ls(string $volume, ?string $folder): array
{
$finder = new Finder();
$finder->depth('== 0')->in($this->routeProject.'/'.$volume.($folder ? '/'.$folder : ''));
$ls = [];
foreach ($finder as $file) {
array_push($ls, [
'basename' => $file->getBasename(),
'realpath' => $file->getRealPath(),
'type' => $file->getType(),
]);
}
dump($ls);
exit;
}
}

View File

@ -4,6 +4,7 @@
<style>
.card-body div {
display:flex;
align-items: center;
}
.card-body div label {
@ -16,7 +17,15 @@
{{ form_start(form) }}
{{ form_widget(form.submit) }}
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
{{ form_widget(form.submit) }}
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="expertSwitch">
<label class="form-check-label ms-2" for="expertSwitch">Mode Expert</label>
</div>
</div>
<div class="row">
{% for section in dicos %}
@ -39,12 +48,19 @@
{% block localscript %}
<script>
let isExpert=false;
function toggleExpertMode(isExpertMode) {
localStorage.setItem('expertMode', isExpertMode ? '1' : '0');
isExpert=isExpertMode;
refreshHideShow();
}
function moveToSection() {
$('[data-section]').each(function() {
inputLabel = $(this).parent();
section = $(this).data('section');
inputLabel.appendTo('#'+section);
console.log('Section trouvée:', section);
});
$('label.required').each(function () {
@ -55,6 +71,69 @@
});
}
function addResetButtons() {
$('input, select, textarea').each(function () {
const $input = $(this);
const defaultValue = $input.data('default');
// Créer le bouton seulement si une valeur par défaut existe
if (typeof defaultValue !== 'undefined') {
const $wrapper = $input.closest('div');
// Évite les doublons
if ($wrapper.find('.reset-btn').length === 0) {
const $resetBtn = $(`
<button type="button" class="btn btn-sm btn-secondary ms-2 reset-btn" title="Réinitialiser">
<i class="fas fa-rotate-left"></i>
</button>
`);
$resetBtn.on('click', function () {
if ($input.is(':checkbox')) {
$input.prop('checked', defaultValue == 1 || defaultValue === 'true');
} else {
$input.val(defaultValue).trigger('change');
}
updateResetButtonStyle($input, $resetBtn); // maj couleur après reset
});
$wrapper.append($resetBtn);
}
// Appliquer couleur initiale
const $resetBtn = $wrapper.find('.reset-btn');
updateResetButtonStyle($input, $resetBtn);
}
});
}
function updateResetButtonStyle($input, $btn) {
const currentVal = $input.is(':checkbox') ? $input.is(':checked') : $input.val();
const defaultVal = $input.data('default');
let isChanged = false;
if ($input.is(':checkbox')) {
isChanged = (defaultVal == '1' || defaultVal === true || defaultVal === 'true') !== $input.is(':checked');
} else {
isChanged = currentVal != defaultVal;
}
if (isChanged) {
$btn.removeClass('btn-secondary').addClass('btn-success');
} else {
$btn.removeClass('btn-success').addClass('btn-secondary');
}
}
function watchInputsForResetState() {
$('input[data-default], select[data-default], textarea[data-default]').on('input change', function () {
console.log("here");
const $input = $(this);
const $btn = $input.closest('div').find('.reset-btn');
updateResetButtonStyle($input, $btn);
});
}
function cardHideShow() {
$('.card-body').each(function () {
const $cardBody = $(this);
@ -68,49 +147,78 @@
});
}
function refreshHideShow() {
$('.slave').each(function() {
slave = $(this);
slaveId = slave.attr('id');
const isExpert = localStorage.getItem('expertMode') === '1';
// Déterminer si le champs est required
isrequired = $('label[for="' + slaveId + '"]').hasClass('required');
console.log(slaveId);
console.log(isrequired);
// Afficher / Masquer les slaves
$('.slave').each(function () {
const $slave = $(this);
const slaveConditions = $slave.data('slave'); // ex: "foo=1&&bar=SQL"
const isExpertField = $slave.data('expert');
const $wrapper = $slave.closest('div');
let toShow = true;
// Rechercher son maitre
masterArray = slave.data('slave').split("=");
master = $('[data-master="'+masterArray[0]+'"]')
// 1. Évaluer les conditions de dépendance
if (slaveConditions) {
const conditions = slaveConditions.split('&&');
// Déterminer si le slave doit etre afficher
toshow=false;
if(master.is(':visible')&&master.val()===masterArray[1]) {
toshow=true;
for (const cond of conditions) {
const [masterKey, expectedValue] = cond.split('=');
const $master = $('[data-master="' + masterKey + '"]');
if (!($master.length && $master.is(':visible') && $master.val() == expectedValue)) {
toShow = false;
break;
}
}
}
if(toshow) {
slave.parent().show();
}
else {
slave.parent().hide();
// 2. Appliquer l'affichage
if (toShow) {
$wrapper.show();
} else {
$wrapper.hide();
}
});
cardHideShow();
// Afficher / Masquer Mode expert
$('[data-expert]').each(function () {
const $el = $(this);
const isExpertField = $el.data('expert');
const $wrapper = $el.closest('div');
if (isExpertField && !isExpert) {
$wrapper.hide();
} else {
$wrapper.show();
}
});
cardHideShow();
}
$(document).ready(function() {
isExpert = localStorage.getItem('expertMode') === '1';
$('#expertSwitch').prop('checked', isExpert);
toggleExpertMode(isExpert);
$('#expertSwitch').on('change', function() {
toggleExpertMode(this.checked);
});
$('.master').on('change', function () {
console.log($(this).val());
refreshHideShow();
});
moveToSection();
moveToSection();
addResetButtons();
watchInputsForResetState();
refreshHideShow();
});
</script>
{% endblock %}

View File

@ -0,0 +1,22 @@
{% extends 'base.html.twig' %}
{% block localstyle%}
{% endblock %}
{% block body %}
<div style="display:flex; flex-direction: column">
{% if volume is empty %}
{% for volume in volumes %}
<div>
<a href="{{path("app_volume",{volume:volume.id})}}">{{ volume.id }}</a>
</div>
{% endfor %}
{% else %}
{% endif %}
</div>
{% endblock %}
{% block localscript %}
{% endblock %}