From 74207340a1dcf2d7d4e9b3b918988bcc6fe50c29 Mon Sep 17 00:00:00 2001 From: William Jacoby Date: Wed, 7 Oct 2026 09:09:47 -0500 Subject: [PATCH 1/2] Read the build from store/ when the old default path is empty Boards set to the old default, ext/phpbbmodders/documentation/docs-build, keep it when a build was there at upgrade time. If that build is later moved to store/phpbbmodders_documentation without updating the setting, the extension now reads it from there instead of reporting no build. The ACP settings page says when this fallback is in use, and when the build in use is inside the extension's own directory, where the next extension update would delete it. Co-Authored-By: Claude Opus 5.5 --- acp/main_module.php | 3 + adm/style/acp_documentation.html | 12 +++ controller/documentation_helper.php | 86 +++++++++++++++++-- docs-build/.gitkeep | 0 docs-build/.htaccess | 25 ------ language/en/info_acp_documentation.php | 3 + .../controller/documentation_helper_test.php | 76 ++++++++++++++++ 7 files changed, 175 insertions(+), 30 deletions(-) delete mode 100644 docs-build/.gitkeep delete mode 100644 docs-build/.htaccess diff --git a/acp/main_module.php b/acp/main_module.php index de86619..4d3f274 100644 --- a/acp/main_module.php +++ b/acp/main_module.php @@ -166,6 +166,9 @@ public function main($id, $mode) 'ERROR_MSG' => implode('
', $error), 'S_DOCUMENTATION_BUILD_FOUND' => $docs_root_found, + 'S_DOCUMENTATION_STORE_FALLBACK' => $doc_helper->is_using_store_fallback(), + 'S_DOCUMENTATION_BUILD_IN_EXTENSION' => $doc_helper->is_build_inside_extension(), + 'DOCUMENTATION_DEFAULT_DOCS_PATH' => $doc_helper::DEFAULT_DOCS_PATH, 'RESYNC_FEEDBACK' => $resync_feedback, 'DOCUMENTATION_DOCS_PATH' => $cfg_array['phpbbmodders_documentation_docs_path'], diff --git a/adm/style/acp_documentation.html b/adm/style/acp_documentation.html index 7cd203f..a17cd89 100644 --- a/adm/style/acp_documentation.html +++ b/adm/style/acp_documentation.html @@ -15,6 +15,18 @@

{{ lang('WARNING') }}

{% endif %} +{% if S_DOCUMENTATION_STORE_FALLBACK %} +
+

{{ lang('ACP_DOCUMENTATION_STORE_FALLBACK', DOCUMENTATION_DEFAULT_DOCS_PATH)|e }}

+
+{% endif %} + +{% if S_DOCUMENTATION_BUILD_IN_EXTENSION %} +
+

{{ lang('ACP_DOCUMENTATION_BUILD_IN_EXTENSION', DOCUMENTATION_DEFAULT_DOCS_PATH)|e }}

+
+{% endif %} + {% if not S_DOCUMENTATION_BUILD_FOUND %}

{{ lang('ACP_DOCUMENTATION_BUILD_MISSING') }}

diff --git a/controller/documentation_helper.php b/controller/documentation_helper.php index 903e671..f747c7c 100644 --- a/controller/documentation_helper.php +++ b/controller/documentation_helper.php @@ -43,6 +43,18 @@ class documentation_helper /** Page whose wide tables get wrapped in a horizontally scrollable region. */ const EVENTS_LIST_PATH = 'development/extensions/events_list'; + /** Default docs build path, relative to the phpBB root. */ + const DEFAULT_DOCS_PATH = 'store/phpbbmodders_documentation'; + + /** + * Default before the build moved to store/. Boards still set to it use + * DEFAULT_DOCS_PATH when this has no build but that does. + */ + const LEGACY_DOCS_PATH = 'ext/phpbbmodders/documentation/docs-build'; + + /** This extension's own directory, relative to the phpBB root. */ + const EXTENSION_PATH = 'ext/phpbbmodders/documentation'; + /** Character Hugo's breadcrumb puts before its home link. */ const HUGO_HOME_GLYPH = '⌂'; @@ -167,24 +179,88 @@ public function get_docs_root() } /** - * @return string|false The configured docs path, resolved and - * existence-checked, but without requiring it to be non-empty. + * The configured docs path, resolved and existence-checked, but + * without requiring it to be non-empty. A board still set to + * LEGACY_DOCS_PATH with no build there gets DEFAULT_DOCS_PATH instead + * when that has a build, so moving the build to store/ works before + * the setting is updated. + * + * @return string|false */ protected function resolve_configured_root() { $configured = (string) $this->config['phpbbmodders_documentation_docs_path']; + $root = $this->resolve_path($configured); + + if ($this->is_store_fallback($configured, $root)) + { + return $this->resolve_path(self::DEFAULT_DOCS_PATH); + } + + return $root; + } + + /** + * @param string $configured The docs path setting. + * @param string|false $root That setting, resolved. + * @return bool Whether the build is read from DEFAULT_DOCS_PATH instead. + */ + protected function is_store_fallback($configured, $root) + { + if ($configured !== self::LEGACY_DOCS_PATH || ($root !== false && $this->has_any_language_directory($root))) + { + return false; + } + + $store = $this->resolve_path(self::DEFAULT_DOCS_PATH); + + return $store !== false && $this->has_any_language_directory($store); + } - if ($configured === '') + /** + * @param string $path Absolute, or relative to the phpBB root. + * @return string|false The existing directory's real path. + */ + protected function resolve_path($path) + { + if ($path === '') { return false; } - $root = (strpos($configured, '/') === 0) ? $configured : $this->phpbb_root_path . $configured; - $real = realpath($root); + $real = realpath((strpos($path, '/') === 0) ? $path : $this->phpbb_root_path . $path); return ($real !== false && is_dir($real)) ? $real : false; } + /** + * Whether the docs build path setting is still the old default but the + * build is read from DEFAULT_DOCS_PATH, so the setting should be updated. + * + * @return bool + */ + public function is_using_store_fallback() + { + $configured = (string) $this->config['phpbbmodders_documentation_docs_path']; + + return $this->is_store_fallback($configured, $this->resolve_path($configured)); + } + + /** + * Whether the build in use lives inside this extension's own + * directory, which is replaced, build and all, when the extension is + * updated. + * + * @return bool + */ + public function is_build_inside_extension() + { + $root = $this->get_docs_root(); + $extension = $this->resolve_path(self::EXTENSION_PATH); + + return $root !== false && $extension !== false && strpos($root . DIRECTORY_SEPARATOR, $extension . DIRECTORY_SEPARATOR) === 0; + } + /** * @param string $root * @return bool diff --git a/docs-build/.gitkeep b/docs-build/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docs-build/.htaccess b/docs-build/.htaccess deleted file mode 100644 index 92e78ba..0000000 --- a/docs-build/.htaccess +++ /dev/null @@ -1,25 +0,0 @@ -# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from -# module mod_authz_host to a new module called mod_access_compat (which may be -# disabled) and a new "Require" syntax has been introduced to mod_authz_core. -# We could just conditionally provide both versions, but unfortunately Apache -# does not explicitly tell us its version if the module mod_version is not -# available. In this case, we check for the availability of module -# mod_authz_core (which should be on 2.4 or higher only) as a best guess. - - - Order Allow,Deny - Deny from All - - = 2.4> - Require all denied - - - - - Order Allow,Deny - Deny from All - - - Require all denied - - diff --git a/language/en/info_acp_documentation.php b/language/en/info_acp_documentation.php index 78d579e..93d9074 100644 --- a/language/en/info_acp_documentation.php +++ b/language/en/info_acp_documentation.php @@ -23,6 +23,9 @@ 'ACP_DOCUMENTATION_SETTINGS' => 'Documentation settings', 'ACP_DOCUMENTATION_SETTINGS_EXPLAIN' => 'Configure where the built documentation site lives and how it behaves inside the forum.', + 'ACP_DOCUMENTATION_STORE_FALLBACK' => 'The docs build path still points to the old location inside the extension, which has no build, so the documentation is being read from %s instead. Set the docs build path below to that directory.', + 'ACP_DOCUMENTATION_BUILD_IN_EXTENSION' => 'The documentation build is inside the extension’s own directory, which is deleted when the extension is updated. Move the build to %s and set the docs build path below to that directory.', + 'ACP_DOCUMENTATION_BUILD_MISSING' => 'No documentation build was found at the configured path. Documentation will stay hidden from the forum until this is fixed.', 'ACP_DOCUMENTATION_DOCS_PATH' => 'Docs build path', diff --git a/tests/controller/documentation_helper_test.php b/tests/controller/documentation_helper_test.php index 7f16df1..ee6a4fd 100644 --- a/tests/controller/documentation_helper_test.php +++ b/tests/controller/documentation_helper_test.php @@ -790,4 +790,80 @@ public static function search_max_results_provider() 'too high' => array(array('phpbbmodders_documentation_search_max_results' => 5000), 200), ); } + + /** + * A helper for a phpBB root at $board, with the docs build path set to $docs_path. + * + * @param string $board Absolute phpBB root, with a trailing slash. + * @param string $docs_path + * @return documentation_helper + */ + protected function get_board_helper($board, $docs_path) + { + return new documentation_helper( + $this->get_config(array('phpbbmodders_documentation_docs_path' => $docs_path)), + $this->createMock(language::class), + $this->get_request(), + $this->get_user(), + $board, + $this->get_controller_helper() + ); + } + + protected function make_board_build($board, $path) + { + mkdir($board . $path . '/en', 0777, true); + file_put_contents($board . $path . '/en/index.html', 'page'); + } + + public function test_old_default_path_without_a_build_falls_back_to_store() + { + $board = $this->docs_root . '/board/'; + mkdir($board . documentation_helper::LEGACY_DOCS_PATH, 0777, true); + $this->make_board_build($board, documentation_helper::DEFAULT_DOCS_PATH); + + $helper = $this->get_board_helper($board, documentation_helper::LEGACY_DOCS_PATH); + + $this->assertSame(realpath($board . documentation_helper::DEFAULT_DOCS_PATH), $helper->get_docs_root()); + $this->assertSame(array('en'), $helper->get_available_languages()); + $this->assertTrue($helper->is_using_store_fallback()); + $this->assertFalse($helper->is_build_inside_extension()); + } + + public function test_old_default_path_with_a_build_keeps_it_and_warns() + { + $board = $this->docs_root . '/board/'; + $this->make_board_build($board, documentation_helper::LEGACY_DOCS_PATH); + $this->make_board_build($board, documentation_helper::DEFAULT_DOCS_PATH); + + $helper = $this->get_board_helper($board, documentation_helper::LEGACY_DOCS_PATH); + + $this->assertSame(realpath($board . documentation_helper::LEGACY_DOCS_PATH), $helper->get_docs_root()); + $this->assertFalse($helper->is_using_store_fallback()); + $this->assertTrue($helper->is_build_inside_extension()); + } + + public function test_other_missing_paths_do_not_fall_back_to_store() + { + $board = $this->docs_root . '/board/'; + $this->make_board_build($board, documentation_helper::DEFAULT_DOCS_PATH); + + $helper = $this->get_board_helper($board, 'store/somewhere_else'); + + $this->assertFalse($helper->get_docs_root()); + $this->assertFalse($helper->is_using_store_fallback()); + } + + public function test_store_path_is_neither_a_fallback_nor_inside_the_extension() + { + $board = $this->docs_root . '/board/'; + mkdir($board . documentation_helper::EXTENSION_PATH, 0777, true); + $this->make_board_build($board, documentation_helper::DEFAULT_DOCS_PATH); + + $helper = $this->get_board_helper($board, documentation_helper::DEFAULT_DOCS_PATH); + + $this->assertSame(realpath($board . documentation_helper::DEFAULT_DOCS_PATH), $helper->get_docs_root()); + $this->assertFalse($helper->is_using_store_fallback()); + $this->assertFalse($helper->is_build_inside_extension()); + } } From 7ba5861554c5d79ebf405b08fbb78844646cd292 Mon Sep 17 00:00:00 2001 From: William Jacoby Date: Wed, 7 Oct 2026 09:10:00 -0500 Subject: [PATCH 2/2] Describe the old-path warning and store/ fallback in the README Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d48c233..8d61652 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Shows the board's Hugo documentation site inside phpBB, styled with the active b The build's HTML is shown inside the board as-is, so only put a build you trust at the docs build path, in a directory only administrators can write to. -Boards upgraded from an earlier version keep their build at `ext/phpbbmodders/documentation/docs-build/` if one was already there; move it to the new location and update the docs build path to stop the next extension update deleting it. +Boards upgraded from an earlier version keep their build at `ext/phpbbmodders/documentation/docs-build/` if one was already there; move it to the new location and update the docs build path to stop the next extension update deleting it. The settings page warns while the build is inside the extension's directory. If the build is moved but the setting isn't updated, the extension reads it from `store/phpbbmodders_documentation/` and the settings page asks for the setting to be updated. If you add a new top-level section or a new language to the docs build later, use the **Resync permissions** button on the settings page.