'admin']; $_SERVER['SCRIPT_NAME'] = '/admin/api.php'; require_once $root . '/admin/lang/i18n.php'; require_once $root . '/includes/ai/raiju-map.php'; function mapAssert(bool $condition, string $message): void { if (!$condition) { fwrite(STDERR, "FAIL: {$message}\n"); exit(1); } } $entries = raijuMapEntries(); $sections = raijuMapSections(); $tabs = raijuMapSettingsTabs(); $languages = raijuMapLanguageCodes(); mapAssert(count($languages) === 9, 'nine admin languages expected, found ' . implode(',', $languages)); // ---- Complete against the dashboard -------------------------------------------------------------------------- $dashboard = (string)file_get_contents($root . '/admin/dashboard.php'); preg_match_all('/data-tab="([a-z-]+)"/', $dashboard, $found); $dashboardAreas = array_values(array_unique($found[1])); foreach ($dashboardAreas as $area) mapAssert(isset($sections[$area]), "dashboard area '{$area}' is missing in raijuMapSections()"); foreach (array_keys($sections) as $area) mapAssert(in_array($area, $dashboardAreas, true), "map area '{$area}' does not exist in the dashboard"); preg_match_all('/data-settings-tab="([a-z-]+)"/', $dashboard, $found); $dashboardTabs = array_values(array_unique($found[1])); foreach ($dashboardTabs as $tab) mapAssert(isset($tabs[$tab]), "settings tab '{$tab}' is missing in raijuMapSettingsTabs()"); foreach (array_keys($tabs) as $tab) mapAssert(in_array($tab, $dashboardTabs, true), "map settings tab '{$tab}' does not exist in the dashboard"); $ids = array_keys($entries); foreach (array_keys($sections) as $area) { mapAssert(count(array_filter($entries, static fn($e) => $e[0] === $area && $e[1] === '' && str_starts_with(array_search($e, $entries), 'area_'))) === 1, "area '{$area}' needs exactly one area_ entry"); } foreach (array_keys($tabs) as $tab) { mapAssert(count(array_filter(array_keys($entries), static fn($id) => str_starts_with($id, 'tab_') && $entries[$id][1] === $tab)) === 1, "settings tab '{$tab}' needs exactly one tab_ entry"); } // The module keys the map uses are the ones the dashboard uses. preg_match("/'news' => true, 'events' => true, 'messages' => true, 'iconManager' => true, 'ai' => true/", $dashboard) or mapAssert(false, 'the dashboard module list changed; update raijuMapSections()'); foreach ($sections as $area => [$label, $role, $module]) { mapAssert(in_array($role, ['admin', 'editor'], true), "area '{$area}' has an unknown role"); mapAssert($module === '' || in_array($module, ['news', 'events', 'messages', 'iconManager'], true), "area '{$area}' has an unknown module"); } // ---- Every name exists in every admin language ----------------------------------------------------------------- $keys = []; foreach ($sections as [$label]) $keys[$label] = true; foreach ($tabs as [$label]) $keys[$label] = true; foreach ($entries as $id => $entry) { mapAssert(isset($sections[$entry[0]]), "{$id}: unknown area {$entry[0]}"); mapAssert($entry[1] === '' || isset($tabs[$entry[1]]), "{$id}: unknown settings tab {$entry[1]}"); mapAssert($entry[1] === '' || $entry[0] === 'settings', "{$id}: a settings tab belongs to the settings area"); mapAssert(is_array($entry[3]) && is_string($entry[4]) && $entry[4] !== '', "{$id}: synonyms and an English hint are needed"); $keys[$entry[2]] = true; } foreach (array_keys($keys) as $key) { foreach ($languages as $language) { $strings = raijuMapLanguageStrings($language); $english = raijuMapLanguageStrings('en'); mapAssert(isset($english[$key]) && trim((string)$english[$key]) !== '', "label key {$key} missing in en.json"); mapAssert(raijuMapLabel($key, $language) !== $key, "label key {$key} cannot be resolved for {$language}"); mapAssert(isset($strings[$key]) || $language === 'en' || isset($english[$key]), "label key {$key} for {$language}"); } } // A synonym belongs to one entry: the same word on two entries makes the answer a coin toss. $owners = []; foreach (array_keys($entries) as $id) { foreach (raijuMapTerms($id) as $term) $owners[$term][] = $id; } foreach ($owners as $term => $list) { if ($term !== 'dashboard') mapAssert(count(array_unique($list)) === 1, "'{$term}' is a name or synonym of several entries: " . implode(', ', array_unique($list))); } // ---- Finding things ---------------------------------------------------------------------------------------------- $first = static function (string $query, bool $admin = true): ?string { $found = raijuMapLookup($query, $admin, 3); return $found[0]['id'] ?? null; }; foreach ([ 'Stell die Systemsprache auf Englisch' => 'set_admin_language', 'Set the system language to German' => 'set_admin_language', 'change the interface language' => 'set_admin_language', 'Wie ändere ich die Sprache des Dashboards?' => 'set_admin_language', 'cambiar el idioma del sistema' => 'set_admin_language', 'Wo kann ich mein Passwort ändern?' => 'set_password', 'where do I switch on dark mode' => 'set_theme', 'Ich möchte einen Benutzer anlegen' => 'tab_users', 'how do I restore a backup' => 'area_backup', 'Wartungsmodus einschalten' => 'set_maintenance', 'where are the form messages' => 'area_messages', 'Logo ändern' => 'set_logo', 'SMTP Server einstellen' => 'set_smtp', ] as $query => $expected) { mapAssert($first($query) === $expected, "'{$query}' should find {$expected}, found " . json_encode($first($query))); } mapAssert($first('Tell me a joke about cats') === null, 'a question with no place finds nothing'); mapAssert($first('') === null, 'an empty question finds nothing'); // The name in each admin language finds its entry. foreach ($languages as $language) { $label = raijuMapLabel('settings.admin_language', $language); mapAssert($first($label) === 'set_admin_language', "the name '{$label}' ({$language}) should find the admin language setting, found " . json_encode($first($label))); } // ---- Links and breadcrumbs ------------------------------------------------------------------------------------------- $place = raijuMapDescribe('set_admin_language', true); mapAssert($place['path'] === 'Settings › Language › Admin Language' && $place['url'] === '/admin/dashboard.php#settings/language' && !$place['restricted'] && $place['available'], 'language setting: ' . json_encode($place)); mapAssert(raijuMapDescribe('area_home', true)['url'] === '/admin/dashboard.php#dashboard', 'the home area uses the public hash'); mapAssert(raijuMapDescribe('area_pages', true)['url'] === '/admin/dashboard.php#pages', 'pages use the public hash'); mapAssert(raijuMapDescribe('area_messages', true)['url'] === '/admin/dashboard.php#messages', 'messages use the public hash'); mapAssert(raijuMapDescribe('area_media', true)['url'] === '/admin/dashboard.php#media', 'media'); mapAssert(raijuMapDescribe('nope') === null, 'unknown id'); $_SERVER['SCRIPT_NAME'] = '/sub/site/admin/api.php'; mapAssert(raijuMapDescribe('tab_users', true)['url'] === '/sub/site/admin/dashboard.php#settings/users', 'the dashboard address follows the folder of the site'); foreach (['//evil.example/admin/api.php', '/x/../../admin/api.php', "/admin/api.php?\">