diff --git a/.env.example b/.env.example index 75db2a2..55820d9 100644 --- a/.env.example +++ b/.env.example @@ -39,3 +39,7 @@ SMTP_FROM_NAME= # Formulaire de contact CONTACT_EMAIL= CONTACT_FROM_EMAIL= + +# Logs Apache (onglet Recherches dans /admin) +# Nom du fichier de log d'accès du vhost dans /var/log/apache2/ +APACHE_ACCESS_LOG=lan.acegrp.varlog-access.log diff --git a/public/index.php b/public/index.php index b9f361f..386f6c8 100644 --- a/public/index.php +++ b/public/index.php @@ -23,8 +23,10 @@ require_once BASE_PATH . '/src/helpers.php'; require_once BASE_PATH . '/src/auth.php'; require_once BASE_PATH . '/src/SiteSettings.php'; require_once BASE_PATH . '/src/ArticleManager.php'; +require_once BASE_PATH . '/src/BookManager.php'; $articles = new ArticleManager(BASE_PATH . '/data'); +$books = new BookManager(BASE_PATH . '/data/books'); // ─── Mode maintenance ────────────────────────────────────────────────────── if (file_exists(BASE_PATH . '/data/.maintenance')) { @@ -41,7 +43,7 @@ $action = $_GET['action'] ?? 'list'; $uuid = $_GET['uuid'] ?? ''; $slug = $_GET['slug'] ?? ''; -$_noindexActions = ['create', 'edit', 'admin', 'categories', 'diff', 'add_files', 'import_image', 'import_image_step2', 'sources', 'profile', 'delete_file', 'delete_external_link', 'rename_category', 'delete_category', 'toggle_private_category', 'admin_save_site', 'not_found', 'add_feed', 'delete_feed', 'add_link', 'delete_link', 'reorder_links', 'react', 'comment', 'verify_comment', 'comment_moderate', 'comment_delete', 'comment_resend', 'create_tag_type', 'delete_tag_type', 'edit_tags']; +$_noindexActions = ['create', 'edit', 'admin', 'categories', 'diff', 'add_files', 'import_image', 'import_image_step2', 'sources', 'profile', 'delete_file', 'delete_external_link', 'rename_category', 'delete_category', 'toggle_private_category', 'admin_save_site', 'not_found', 'add_feed', 'delete_feed', 'add_link', 'delete_link', 'reorder_links', 'react', 'comment', 'verify_comment', 'comment_moderate', 'comment_delete', 'comment_resend', 'create_tag_type', 'delete_tag_type', 'edit_tags', 'book_save', 'book_delete']; $metaRobots = in_array($action, $_noindexActions, true) ? 'noindex, nofollow' : null; unset($_noindexActions); @@ -825,6 +827,13 @@ switch ($action) { $comments = $commentMgr->forArticle($article['uuid']); } + // Contexte livre (navigation précédent/suivant si l'article fait partie d'un livre) + $bookContext = $books->findForArticle($article['slug'] ?? ''); + if ($bookContext !== null) { + $bookContext['prev_article'] = $bookContext['prev'] !== null ? $articles->getBySlug($bookContext['prev']) : null; + $bookContext['next_article'] = $bookContext['next'] !== null ? $articles->getBySlug($bookContext['next']) : null; + } + include BASE_PATH . '/templates/post_view.php'; break; @@ -2528,7 +2537,7 @@ switch ($action) { exit; } require_once BASE_PATH . '/src/SearchLogParser.php'; - $parser = new SearchLogParser(); + $parser = new SearchLogParser('/var/log/apache2', apacheAccessLog()); $adminData['search_terms'] = $parser->topTerms(100); $adminData['search_log_readable'] = $parser->isReadable(); } @@ -2539,6 +2548,21 @@ switch ($action) { $adminData['tagTypes'] = $articles->getTagTypes(); } + if ($tab === 'books') { + if (!isAdmin()) { + http_response_code(403); + exit; + } + $adminData['books'] = $books->getAll(); + $adminData['edit_book'] = null; + $adminData['all_articles'] = $articles->getAll(); + usort($adminData['all_articles'], static fn ($a, $b) => strcmp($a['title'] ?? '', $b['title'] ?? '')); + $editBookSlug = trim($_GET['edit'] ?? ''); + if ($editBookSlug !== '') { + $adminData['edit_book'] = $books->getBySlug($editBookSlug); + } + } + include BASE_PATH . '/templates/admin.php'; break; @@ -3120,6 +3144,69 @@ switch ($action) { include BASE_PATH . '/templates/search.php'; break; + case 'book': + $bookSlug = trim($_GET['book_slug'] ?? ''); + $book = $books->getBySlug($bookSlug); + if (!$book) { + http_response_code(404); + ob_start(); + ?> +
+ getBySlug($aSlug); + if (!$a) { + continue; + } + if (!$a['published'] && !canDoOnArticle('view_drafts', $a)) { + continue; + } + $bookArticles[] = $a; + } + $allCats = $articles->getCategories(); + include BASE_PATH . '/templates/book.php'; + break; + + case 'book_save': + requireAuth(); + if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(403); + exit; + } + $bSlug = trim($_POST['slug'] ?? ''); + $bTitle = trim($_POST['title'] ?? ''); + $bDesc = trim($_POST['description'] ?? ''); + $bArts = array_values(array_filter(array_map('trim', preg_split('/[\r\n]+/', $_POST['articles'] ?? '')))); + if ($bSlug !== '' && $bTitle !== '') { + $books->save(['slug' => $bSlug, 'title' => $bTitle, 'description' => $bDesc, 'articles' => $bArts]); + } + header('Location: /admin/books?saved=1&edit=' . rawurlencode($bSlug)); + exit; + + case 'book_delete': + requireAuth(); + if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(403); + exit; + } + $bSlug = trim($_POST['slug'] ?? ''); + if ($bSlug !== '') { + $books->delete($bSlug); + } + header('Location: /admin/books?deleted=1'); + exit; + case 'not_found': $notFoundPath = trim( (string)(parse_url($_SERVER['REDIRECT_URL'] ?? $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH) ?? ''), diff --git a/src/SiteSettings.php b/src/SiteSettings.php index c0570cd..1d9d08f 100644 --- a/src/SiteSettings.php +++ b/src/SiteSettings.php @@ -59,10 +59,19 @@ function siteLicenseUrl(): string return siteSettings()['site_license_url'] ?? 'https://creativecommons.org/licenses/by/4.0/'; } +function apacheAccessLog(): string +{ + $fromSettings = siteSettings()['apache_access_log'] ?? ''; + if ($fromSettings !== '') { + return $fromSettings; + } + return (string)($_ENV['APACHE_ACCESS_LOG'] ?? getenv('APACHE_ACCESS_LOG') ?: 'lan.acegrp.varlog-access.log'); +} + function saveSiteSettings(array $data): bool { $current = siteSettings(); - $stringKeys = ['site_title', 'site_claim', 'site_lang', 'site_license_label', 'site_license_url']; + $stringKeys = ['site_title', 'site_claim', 'site_lang', 'site_license_label', 'site_license_url', 'apache_access_log']; foreach ($stringKeys as $key) { if (array_key_exists($key, $data)) { $val = trim((string)$data[$key]); diff --git a/templates/admin.php b/templates/admin.php index a2b850f..88ce490 100644 --- a/templates/admin.php +++ b/templates/admin.php @@ -65,6 +65,10 @@ function adminStatusBadge(array $a, int $now): string Recherches +/var/log/apache2/, utilisé par l'onglet Recherches.Aucun livre pour l'instant.
+ + + ++ + Sélectionnez un livre à gauche pour le modifier, ou créez-en un nouveau. + + Cliquez sur + Nouveau pour créer votre premier livre. + +
+ +