Files
ms1inscription-v5/superadm/php/inc_fx_doc_admin.php
stephan 63b0a1d4c5 Refactor sidebar navigation and improve documentation management in admin interface
This commit enhances the sidebar navigation by consolidating sections for site management, access management, and documentation. It introduces a new help section for production deployment and streamlines the documentation links for better accessibility. Unused code related to module selection has been removed, improving maintainability. The version code is updated to reflect these changes.
2026-07-01 10:58:23 -04:00

338 lines
13 KiB
PHP

<?php
/**
* Admin documentation (doc_mod / doc_page / doc_anchor) — super admin.
* Lister, creer modules et pages ; edition via /php/doc_edition.php (Trumbowyg).
* Creation reservee dev/preprod (le contenu est ensuite pousse par la base).
*/
function fxDocAdminEsc($str)
{
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
}
function fxDocAdminIsDevPreprod()
{
global $vblnEnvironementDev, $vblnEnvironementPreProd;
return !empty($vblnEnvironementDev) || !empty($vblnEnvironementPreProd);
}
function fxDocAdminSchemaReady()
{
global $objDatabase;
static $blnReady = null;
if ($blnReady !== null) {
return $blnReady;
}
if (!isset($objDatabase)) {
$blnReady = false;
return $blnReady;
}
$qry = $objDatabase->fxQuery("SHOW TABLES LIKE 'doc_page'");
$blnReady = ($qry && mysqli_num_rows($qry) > 0);
return $blnReady;
}
function fxDocAdminEditUrl($modClef, $prg)
{
global $vDomaine;
$prg = ($prg !== '') ? $prg : 'compte.php';
return $vDomaine . '/php/doc_edition.php?' . http_build_query(array(
'mod' => $modClef,
'anchor' => $modClef,
'prg' => $prg,
'bd' => 'client',
'page' => 'compte.php',
));
}
function fxDocAdminListModules()
{
global $objDatabase;
if (!fxDocAdminSchemaReady()) {
return array();
}
$sql = "SELECT m.pk_doc_mod, m.doc_mod_clef, m.doc_mod_prg, m.doc_mod_titre, m.doc_mod_actif,
(SELECT COUNT(DISTINCT p.doc_page_clef)
FROM doc_page p
WHERE p.doc_mod_clef = m.doc_mod_clef) AS nb_pages
FROM doc_mod m
ORDER BY m.doc_mod_tri, m.doc_mod_titre";
$rows = $objDatabase->fxGetResults($sql);
return is_array($rows) ? $rows : array();
}
function fxDocAdminGetModule($modClef)
{
global $objDatabase;
if (!fxDocAdminSchemaReady() || trim($modClef) === '') {
return null;
}
return $objDatabase->fxGetRow(
"SELECT * FROM doc_mod WHERE doc_mod_clef = '" . $objDatabase->fxEscape($modClef) . "' LIMIT 1"
);
}
function fxDocAdminListPages($modClef)
{
global $objDatabase;
if (!fxDocAdminSchemaReady() || trim($modClef) === '') {
return array();
}
$sql = "SELECT * FROM doc_page
WHERE doc_mod_clef = '" . $objDatabase->fxEscape($modClef) . "'
ORDER BY doc_tri, doc_page_clef, doc_langue DESC";
$rows = $objDatabase->fxGetResults($sql);
$grouped = array();
if (is_array($rows)) {
for ($i = 1; $i <= count($rows); $i++) {
$r = $rows[$i];
$clef = $r['doc_page_clef'] ?? '';
if ($clef === '') {
continue;
}
if (!isset($grouped[$clef])) {
$grouped[$clef] = array(
'clef' => $clef,
'tri' => (int)($r['doc_tri'] ?? 0),
'prg' => $r['doc_prg'] ?? 'compte.php',
'fr' => null,
'en' => null,
);
}
$lng = $r['doc_langue'] ?? 'fr';
if ($lng === 'fr' || $lng === 'en') {
$grouped[$clef][$lng] = $r;
}
}
}
return $grouped;
}
function fxDocAdminCreateModule($clef, $titre, $prg)
{
global $objDatabase;
$clef = trim($clef);
$prg = (trim($prg) !== '') ? trim($prg) : 'compte.php';
if ($clef === '') {
return array('state' => 'error', 'message' => 'Clé du module requise.');
}
if (!preg_match('/^[a-z0-9_]+$/i', $clef)) {
return array('state' => 'error', 'message' => 'Clé invalide (lettres, chiffres, underscore seulement).');
}
if (!fxDocAdminSchemaReady()) {
return array('state' => 'error', 'message' => 'Tables de documentation absentes.');
}
$intExists = (int)$objDatabase->fxGetVar(
"SELECT COUNT(*) FROM doc_mod
WHERE doc_mod_clef = '" . $objDatabase->fxEscape($clef) . "'
AND doc_mod_prg = '" . $objDatabase->fxEscape($prg) . "'"
);
if ($intExists > 0) {
return array('state' => 'error', 'message' => 'Ce module existe déjà.');
}
$objDatabase->fxQuery(
"INSERT INTO doc_mod (doc_mod_clef, doc_mod_prg, doc_mod_titre, doc_mod_actif, doc_mod_tri, doc_mod_creation)
VALUES ('" . $objDatabase->fxEscape($clef) . "', '" . $objDatabase->fxEscape($prg) . "', '" . $objDatabase->fxEscape($titre) . "', 1, 0, NOW())"
);
$intAnchor = (int)$objDatabase->fxGetVar(
"SELECT COUNT(*) FROM doc_anchor
WHERE doc_anchor_clef = '" . $objDatabase->fxEscape($clef) . "'
AND doc_prg = '" . $objDatabase->fxEscape($prg) . "'"
);
if ($intAnchor === 0) {
$objDatabase->fxQuery(
"INSERT INTO doc_anchor (doc_anchor_clef, doc_mod_clef, doc_prg, doc_actif, doc_creation)
VALUES ('" . $objDatabase->fxEscape($clef) . "', '" . $objDatabase->fxEscape($clef) . "', '" . $objDatabase->fxEscape($prg) . "', 1, NOW())"
);
}
return array('state' => 'ok', 'mod' => $clef, 'prg' => $prg);
}
function fxDocAdminCreatePage($modClef, $pageClef, $prg)
{
global $objDatabase;
$modClef = trim($modClef);
$pageClef = trim($pageClef);
$prg = (trim($prg) !== '') ? trim($prg) : 'compte.php';
if ($modClef === '' || $pageClef === '') {
return array('state' => 'error', 'message' => 'Clé du module et clé de page requises.');
}
if (!preg_match('/^[a-z0-9_]+$/i', $pageClef)) {
return array('state' => 'error', 'message' => 'Clé de page invalide (lettres, chiffres, underscore seulement).');
}
if (!fxDocAdminSchemaReady()) {
return array('state' => 'error', 'message' => 'Tables de documentation absentes.');
}
$intExists = (int)$objDatabase->fxGetVar(
"SELECT COUNT(*) FROM doc_page
WHERE doc_page_clef = '" . $objDatabase->fxEscape($pageClef) . "'
AND doc_prg = '" . $objDatabase->fxEscape($prg) . "'"
);
if ($intExists > 0) {
return array('state' => 'error', 'message' => 'Cette page existe déjà.');
}
$intTri = (int)$objDatabase->fxGetVar(
"SELECT COALESCE(MAX(doc_tri), 0) + 10 FROM doc_page
WHERE doc_mod_clef = '" . $objDatabase->fxEscape($modClef) . "'"
);
foreach (array('fr', 'en') as $lng) {
$objDatabase->fxQuery(
"INSERT INTO doc_page (doc_mod_clef, doc_page_clef, doc_langue, doc_titre, doc_sous_titre, doc_html, doc_prg, doc_tri, doc_actif, doc_creation)
VALUES ('" . $objDatabase->fxEscape($modClef) . "', '" . $objDatabase->fxEscape($pageClef) . "', '" . $lng . "', '', '', '', '" . $objDatabase->fxEscape($prg) . "', " . $intTri . ", 1, NOW())"
);
}
return array('state' => 'ok', 'mod' => $modClef, 'page' => $pageClef, 'prg' => $prg);
}
/** Liste des modules + formulaire de creation. */
function fxDocAdminRenderModulesList()
{
global $vDomaine;
$arrModules = fxDocAdminListModules();
$blnDev = fxDocAdminIsDevPreprod();
echo '<div class="d-flex align-items-center justify-content-between mb-3">';
echo '<h1 class="h3 mb-0">Documentation &amp; Nouveautés</h1>';
echo '</div>';
echo '<p class="text-muted">Modules de documentation (pages HTML multipage). Le contenu n\'est pas lié au code : édition directe ici, puis poussé par la base.</p>';
if ($blnDev) {
echo '<div class="card mb-4">';
echo '<div class="card-header"><i class="fa fa-plus mr-2" aria-hidden="true"></i>Créer un module</div>';
echo '<div class="card-body">';
echo '<form method="post" action="documentation.php" class="form-row align-items-end">';
echo '<input type="hidden" name="action" value="addmodule">';
echo '<div class="form-group col-md-3"><label>Clé du module</label><input type="text" name="doc_mod_clef" class="form-control" placeholder="ex. promoteur_hub_annonces" required></div>';
echo '<div class="form-group col-md-4"><label>Titre</label><input type="text" name="doc_mod_titre" class="form-control" placeholder="ex. Nouveautés MS1"></div>';
echo '<div class="form-group col-md-3"><label>Programme (doc_prg)</label><input type="text" name="doc_mod_prg" class="form-control" value="compte.php"></div>';
echo '<div class="form-group col-md-2"><button type="submit" class="btn btn-primary btn-block">Créer</button></div>';
echo '</form>';
echo '</div></div>';
} else {
echo '<div class="alert alert-info">La création de modules/pages est réservée aux environnements dev/préprod.</div>';
}
if (empty($arrModules)) {
echo '<div class="alert alert-warning">Aucun module de documentation.</div>';
return;
}
echo '<table class="table table-striped table-hover">';
echo '<thead><tr><th>Titre</th><th>Clé</th><th>Programme</th><th class="text-center">Pages</th><th class="text-right">Actions</th></tr></thead><tbody>';
for ($i = 1; $i <= count($arrModules); $i++) {
$m = $arrModules[$i];
$strClef = $m['doc_mod_clef'] ?? '';
$strPrg = $m['doc_mod_prg'] ?? 'compte.php';
$intNb = (int)($m['nb_pages'] ?? 0);
echo '<tr>';
echo '<td>' . fxDocAdminEsc($m['doc_mod_titre'] ?? '') . '</td>';
echo '<td><code>' . fxDocAdminEsc($strClef) . '</code></td>';
echo '<td>' . fxDocAdminEsc($strPrg) . '</td>';
echo '<td class="text-center">' . $intNb . '</td>';
echo '<td class="text-right">';
echo '<a class="btn btn-sm btn-outline-secondary mr-1" href="documentation.php?p=pages&mod=' . urlencode($strClef) . '"><i class="fa fa-list" aria-hidden="true"></i> Pages</a>';
echo '<a class="btn btn-sm btn-primary" href="' . fxDocAdminEsc(fxDocAdminEditUrl($strClef, $strPrg)) . '" target="_blank"><i class="fa fa-pencil" aria-hidden="true"></i> Éditer</a>';
echo '</td>';
echo '</tr>';
}
echo '</tbody></table>';
}
/** Liste des pages d'un module + formulaire d'ajout de page. */
function fxDocAdminRenderPages($modClef)
{
$modClef = trim($modClef);
$arrMod = fxDocAdminGetModule($modClef);
if ($arrMod === null) {
echo '<div class="alert alert-danger">Module introuvable.</div>';
echo '<a class="btn btn-outline-secondary" href="documentation.php"><i class="fa fa-chevron-left" aria-hidden="true"></i> Retour</a>';
return;
}
$strPrg = $arrMod['doc_mod_prg'] ?? 'compte.php';
$arrPages = fxDocAdminListPages($modClef);
$blnDev = fxDocAdminIsDevPreprod();
echo '<div class="d-flex align-items-center justify-content-between mb-3">';
echo '<div><a class="btn btn-sm btn-outline-secondary mb-2" href="documentation.php"><i class="fa fa-chevron-left" aria-hidden="true"></i> Tous les modules</a>';
echo '<h1 class="h3 mb-0">' . fxDocAdminEsc($arrMod['doc_mod_titre'] ?? $modClef) . '</h1>';
echo '<div class="text-muted"><code>' . fxDocAdminEsc($modClef) . '</code> · ' . fxDocAdminEsc($strPrg) . '</div></div>';
echo '<a class="btn btn-primary" href="' . fxDocAdminEsc(fxDocAdminEditUrl($modClef, $strPrg)) . '" target="_blank"><i class="fa fa-pencil" aria-hidden="true"></i> Éditer le module</a>';
echo '</div>';
if ($blnDev) {
echo '<div class="card mb-4">';
echo '<div class="card-header"><i class="fa fa-plus mr-2" aria-hidden="true"></i>Ajouter une page</div>';
echo '<div class="card-body">';
echo '<form method="post" action="documentation.php" class="form-row align-items-end">';
echo '<input type="hidden" name="action" value="addpage">';
echo '<input type="hidden" name="mod" value="' . fxDocAdminEsc($modClef) . '">';
echo '<input type="hidden" name="doc_prg" value="' . fxDocAdminEsc($strPrg) . '">';
echo '<div class="form-group col-md-6"><label>Clé de la nouvelle page</label><input type="text" name="doc_page_clef" class="form-control" placeholder="ex. annonce_v4_73" required></div>';
echo '<div class="form-group col-md-3"><button type="submit" class="btn btn-primary btn-block">Créer et éditer</button></div>';
echo '</form>';
echo '<small class="text-muted">La page (FR + EN) est créée vide, puis l\'éditeur s\'ouvre.</small>';
echo '</div></div>';
}
if (empty($arrPages)) {
echo '<div class="alert alert-warning">Aucune page dans ce module.</div>';
return;
}
echo '<table class="table table-striped">';
echo '<thead><tr><th class="text-center">Tri</th><th>Clé</th><th>Titre FR</th><th>Titre EN</th></tr></thead><tbody>';
foreach ($arrPages as $page) {
$strTitreFr = isset($page['fr']['doc_titre']) ? $page['fr']['doc_titre'] : '';
$strTitreEn = isset($page['en']['doc_titre']) ? $page['en']['doc_titre'] : '';
echo '<tr>';
echo '<td class="text-center">' . (int)$page['tri'] . '</td>';
echo '<td><code>' . fxDocAdminEsc($page['clef']) . '</code></td>';
echo '<td>' . fxDocAdminEsc($strTitreFr) . '</td>';
echo '<td>' . fxDocAdminEsc($strTitreEn) . '</td>';
echo '</tr>';
}
echo '</tbody></table>';
echo '<p class="text-muted"><i class="fa fa-info-circle" aria-hidden="true"></i> Le bouton « Éditer le module » ouvre toutes les pages dans l\'éditeur visuel.</p>';
}