up wiki land
This commit is contained in:
parent
391a212034
commit
e533c273b2
10 changed files with 1116 additions and 182 deletions
|
@ -8,6 +8,112 @@ use Symfony\Component\Routing\Annotation\Route;
|
|||
|
||||
class WikiController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* Detects incorrect heading hierarchies in a list of sections
|
||||
* For example, h4 directly under h2 without h3 in between
|
||||
*
|
||||
* @param array $sections List of sections with 'level' and 'title' keys
|
||||
* @return array List of section indices with hierarchy errors
|
||||
*/
|
||||
private function detectHeadingHierarchyErrors(array $sections): array
|
||||
{
|
||||
$errors = [];
|
||||
$lastLevel = 0;
|
||||
|
||||
foreach ($sections as $index => $section) {
|
||||
$currentLevel = isset($section['level']) ? (int)$section['level'] : 0;
|
||||
|
||||
// Skip if level is not set or is 0
|
||||
if ($currentLevel === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is the first section, just record its level
|
||||
if ($lastLevel === 0) {
|
||||
$lastLevel = $currentLevel;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the level jump is more than 1
|
||||
// For example, h2 -> h4 (skipping h3)
|
||||
if ($currentLevel > $lastLevel + 1) {
|
||||
$errors[] = $index;
|
||||
}
|
||||
|
||||
$lastLevel = $currentLevel;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
#[Route('/wiki/recent-changes', name: 'app_admin_wiki_recent_changes')]
|
||||
public function recentChanges(): Response
|
||||
{
|
||||
$recentChangesFile = $this->getParameter('kernel.project_dir') . '/wiki_compare/recent_changes.json';
|
||||
|
||||
// Initialize arrays
|
||||
$recentChanges = [];
|
||||
$lastUpdated = null;
|
||||
|
||||
// Check if the recent changes file exists and load it
|
||||
if (file_exists($recentChangesFile)) {
|
||||
$recentChangesData = json_decode(file_get_contents($recentChangesFile), true);
|
||||
|
||||
if (isset($recentChangesData['recent_changes']) && is_array($recentChangesData['recent_changes'])) {
|
||||
$recentChanges = $recentChangesData['recent_changes'];
|
||||
$lastUpdated = isset($recentChangesData['last_updated']) ? $recentChangesData['last_updated'] : null;
|
||||
}
|
||||
|
||||
// Check if the data is older than 1 hour
|
||||
if ($lastUpdated) {
|
||||
$lastUpdatedTime = new \DateTime($lastUpdated);
|
||||
$now = new \DateTime();
|
||||
$diff = $now->diff($lastUpdatedTime);
|
||||
|
||||
// If older than 1 hour, refresh the data
|
||||
if ($diff->h >= 1 || $diff->days > 0) {
|
||||
$this->refreshRecentChangesData();
|
||||
return $this->redirectToRoute('app_admin_wiki_recent_changes');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the file doesn't exist, try to create it by running the script
|
||||
$this->refreshRecentChangesData();
|
||||
|
||||
// Check if the file was created
|
||||
if (file_exists($recentChangesFile)) {
|
||||
return $this->redirectToRoute('app_admin_wiki_recent_changes');
|
||||
} else {
|
||||
$this->addFlash('error', 'Impossible de générer le fichier des changements récents.');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('admin/wiki_recent_changes.html.twig', [
|
||||
'recent_changes' => $recentChanges,
|
||||
'last_updated' => $lastUpdated
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the recent changes data by running the fetch_recent_changes.py script
|
||||
*/
|
||||
private function refreshRecentChangesData(): void
|
||||
{
|
||||
try {
|
||||
$scriptPath = $this->getParameter('kernel.project_dir') . '/wiki_compare/fetch_recent_changes.py';
|
||||
if (file_exists($scriptPath)) {
|
||||
exec('python3 ' . $scriptPath . ' --force 2>&1', $output, $returnCode);
|
||||
|
||||
if ($returnCode !== 0) {
|
||||
$this->addFlash('warning', 'Impossible de mettre à jour les changements récents. Erreur: ' . implode("\n", $output));
|
||||
}
|
||||
} else {
|
||||
$this->addFlash('error', 'Le script fetch_recent_changes.py n\'existe pas.');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', 'Erreur lors de l\'exécution du script: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/wiki/missing-translations', name: 'app_admin_wiki_missing_translations')]
|
||||
public function missingTranslations(): Response
|
||||
{
|
||||
|
@ -664,11 +770,149 @@ class WikiController extends AbstractController
|
|||
$mediaComparison['fr_only_count'] = count($frOnlyImages);
|
||||
}
|
||||
|
||||
// Get link comparison data
|
||||
$linkComparison = $page['link_comparison'] ?? null;
|
||||
|
||||
// Sort links alphabetically by URL if link comparison exists
|
||||
if ($linkComparison) {
|
||||
// Sort English-only links
|
||||
if (isset($linkComparison['en_only']) && is_array($linkComparison['en_only'])) {
|
||||
usort($linkComparison['en_only'], function($a, $b) {
|
||||
return strcmp($a['href'], $b['href']);
|
||||
});
|
||||
}
|
||||
|
||||
// Sort French-only links
|
||||
if (isset($linkComparison['fr_only']) && is_array($linkComparison['fr_only'])) {
|
||||
usort($linkComparison['fr_only'], function($a, $b) {
|
||||
return strcmp($a['href'], $b['href']);
|
||||
});
|
||||
}
|
||||
|
||||
// Sort common links
|
||||
if (isset($linkComparison['common']) && is_array($linkComparison['common'])) {
|
||||
usort($linkComparison['common'], function($a, $b) {
|
||||
return strcmp($a['en']['href'], $b['en']['href']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Get section comparison data and filter out "Contents" sections
|
||||
$sectionComparison = $page['section_comparison'] ?? null;
|
||||
|
||||
// Filter out "Contents" sections if section comparison exists
|
||||
if ($sectionComparison) {
|
||||
// Filter common sections
|
||||
if (isset($sectionComparison['common']) && is_array($sectionComparison['common'])) {
|
||||
$sectionComparison['common'] = array_filter($sectionComparison['common'], function($section) {
|
||||
// Skip if either English or French title is "Contents"
|
||||
return !($section['en']['title'] === 'Contents' || $section['fr']['title'] === 'Sommaire');
|
||||
});
|
||||
// Re-index array
|
||||
$sectionComparison['common'] = array_values($sectionComparison['common']);
|
||||
}
|
||||
|
||||
// Filter English-only sections
|
||||
if (isset($sectionComparison['en_only']) && is_array($sectionComparison['en_only'])) {
|
||||
$sectionComparison['en_only'] = array_filter($sectionComparison['en_only'], function($section) {
|
||||
return $section['title'] !== 'Contents';
|
||||
});
|
||||
// Re-index array
|
||||
$sectionComparison['en_only'] = array_values($sectionComparison['en_only']);
|
||||
}
|
||||
|
||||
// Filter French-only sections
|
||||
if (isset($sectionComparison['fr_only']) && is_array($sectionComparison['fr_only'])) {
|
||||
$sectionComparison['fr_only'] = array_filter($sectionComparison['fr_only'], function($section) {
|
||||
return $section['title'] !== 'Sommaire';
|
||||
});
|
||||
// Re-index array
|
||||
$sectionComparison['fr_only'] = array_values($sectionComparison['fr_only']);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate adjusted section counts (excluding "Contents" sections)
|
||||
$enSectionCount = $enPage['sections'];
|
||||
$frSectionCount = $frPage['sections'];
|
||||
|
||||
// Adjust section counts if we have section comparison data
|
||||
if ($sectionComparison) {
|
||||
// Count how many "Contents" sections were filtered out
|
||||
$contentsFilteredCount = 0;
|
||||
|
||||
// Check common sections that were filtered
|
||||
if (isset($page['section_comparison']['common']) && is_array($page['section_comparison']['common'])) {
|
||||
foreach ($page['section_comparison']['common'] as $section) {
|
||||
if ($section['en']['title'] === 'Contents' || $section['fr']['title'] === 'Sommaire') {
|
||||
$contentsFilteredCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check English-only sections that were filtered
|
||||
if (isset($page['section_comparison']['en_only']) && is_array($page['section_comparison']['en_only'])) {
|
||||
foreach ($page['section_comparison']['en_only'] as $section) {
|
||||
if ($section['title'] === 'Contents') {
|
||||
$contentsFilteredCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check French-only sections that were filtered
|
||||
if (isset($page['section_comparison']['fr_only']) && is_array($page['section_comparison']['fr_only'])) {
|
||||
foreach ($page['section_comparison']['fr_only'] as $section) {
|
||||
if ($section['title'] === 'Sommaire') {
|
||||
$contentsFilteredCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust section counts
|
||||
$enSectionCount -= $contentsFilteredCount;
|
||||
$frSectionCount -= $contentsFilteredCount;
|
||||
}
|
||||
|
||||
// Check for incorrect heading hierarchies
|
||||
$enHierarchyErrors = [];
|
||||
$frHierarchyErrors = [];
|
||||
|
||||
// Check English sections
|
||||
if (isset($sectionComparison['en_only']) && is_array($sectionComparison['en_only'])) {
|
||||
$enHierarchyErrors = $this->detectHeadingHierarchyErrors($sectionComparison['en_only']);
|
||||
}
|
||||
|
||||
// Also check common sections (English side)
|
||||
if (isset($sectionComparison['common']) && is_array($sectionComparison['common'])) {
|
||||
$commonEnSections = array_map(function($section) {
|
||||
return $section['en'];
|
||||
}, $sectionComparison['common']);
|
||||
|
||||
$enHierarchyErrors = array_merge($enHierarchyErrors, $this->detectHeadingHierarchyErrors($commonEnSections));
|
||||
}
|
||||
|
||||
// Check French sections
|
||||
if (isset($sectionComparison['fr_only']) && is_array($sectionComparison['fr_only'])) {
|
||||
$frHierarchyErrors = $this->detectHeadingHierarchyErrors($sectionComparison['fr_only']);
|
||||
}
|
||||
|
||||
// Also check common sections (French side)
|
||||
if (isset($sectionComparison['common']) && is_array($sectionComparison['common'])) {
|
||||
$commonFrSections = array_map(function($section) {
|
||||
return $section['fr'];
|
||||
}, $sectionComparison['common']);
|
||||
|
||||
$frHierarchyErrors = array_merge($frHierarchyErrors, $this->detectHeadingHierarchyErrors($commonFrSections));
|
||||
}
|
||||
|
||||
$detailedComparison = [
|
||||
'section_comparison' => $page['section_comparison'] ?? null,
|
||||
'link_comparison' => $page['link_comparison'] ?? null,
|
||||
'section_comparison' => $sectionComparison,
|
||||
'link_comparison' => $linkComparison,
|
||||
'media_comparison' => $mediaComparison,
|
||||
'category_comparison' => $page['category_comparison'] ?? null
|
||||
'category_comparison' => $page['category_comparison'] ?? null,
|
||||
'adjusted_en_section_count' => $enSectionCount,
|
||||
'adjusted_fr_section_count' => $frSectionCount,
|
||||
'en_hierarchy_errors' => $enHierarchyErrors,
|
||||
'fr_hierarchy_errors' => $frHierarchyErrors
|
||||
];
|
||||
|
||||
$mediaDiff = $page['media_diff'] ?? 0;
|
||||
|
@ -841,6 +1085,15 @@ class WikiController extends AbstractController
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure page URLs are strings to prevent array to string conversion errors
|
||||
if ($frPage && isset($frPage['url']) && is_array($frPage['url'])) {
|
||||
$frPage['url'] = json_encode($frPage['url']);
|
||||
}
|
||||
|
||||
if ($enPage && isset($enPage['url']) && is_array($enPage['url'])) {
|
||||
$enPage['url'] = json_encode($enPage['url']);
|
||||
}
|
||||
|
||||
return $this->render('admin/wiki_compare.html.twig', [
|
||||
'key' => $key,
|
||||
'en_page' => $enPage,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue