Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,23 @@ Shows the board's Hugo documentation site inside phpBB, styled with the active b

## Requirements

- phpBB 3.3.19 or later
- phpBB 3.3.19 or a later 3.3 release
- PHP 8.0 or later

## Installation

1. Copy the extension to `/ext/phpbbmodders/documentation`
2. In the Administration Control Panel, go to **Customise → Manage extensions**
3. Enable the **Documentation** extension
4. Point `proteus_hugo.sh`'s build output at the extension's own `docs-build/` directory:
`./proteus_hugo.sh all /path/to/ext/phpbbmodders/documentation/docs-build`
This is also the default **docs build path** in the settings, so no further ACP configuration is needed unless the build lives elsewhere.
4. Build the documentation into phpBB's `store/phpbbmodders_documentation/` directory:
`./phpbbdocs_hugo.sh all /path/to/phpbb/store/phpbbmodders_documentation`
This is the default **docs build path** in the settings, so no further ACP configuration is needed unless the build lives elsewhere. Keeping it outside the extension's own directory means updating the extension doesn't delete it.
5. Documentation is open to everyone, including guests, by default. Restrict it afterwards through the normal Permissions screens if needed.
6. **Block direct web access to `docs-build/`** on anything other than Apache or LiteSpeed. Without it, the raw pages can be read directly, bypassing the extension's permissions. See [docs/securing-docs-build.md](docs/securing-docs-build.md) for Nginx, Caddy, IIS and lighttpd snippets.
6. **Make sure the build can't be read directly from the web.** phpBB's own deny rules for `store/` cover the default location on Apache, LiteSpeed, and servers set up from phpBB's sample configs. Without a deny rule, the raw pages can be read directly, bypassing the extension's permissions. See [docs/securing-docs-build.md](docs/securing-docs-build.md).

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.

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.

Expand Down Expand Up @@ -63,8 +67,8 @@ checks for every file. Index files named by content hash may stay in the
browser's private cache for the ACP's **Search index cache time** (default 60
minutes, 0 turns it off), so a user who loses access to a section can still
search what they already downloaded until it expires. Separate navigation limits search to the current
documentation side. Keep raw access to `docs-build/` blocked, including its
Pagefind bundles, as described in [docs/securing-docs-build.md](docs/securing-docs-build.md).
documentation side. Keep raw access to the build directory blocked, including
its Pagefind bundles, as described in [docs/securing-docs-build.md](docs/securing-docs-build.md).

`styles/all/template/js/documentation-search.js` is a copy of phpbbdocs-hugo's
`site/static/js/documentation-search.js`; keep the two in sync.
Expand Down
4 changes: 4 additions & 0 deletions acp/main_module.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ public function main($id, $mode)
'SECTIONS' => implode(', ', $doc_helper->get_available_sections($lang_code)),
));
}

// Only complete now that every language's sections have been read.
$ignored = $doc_helper->get_ignored_build_names();
$template->assign_var('DOCUMENTATION_IGNORED_NAMES', empty($ignored) ? '' : $language->lang('ACP_DOCUMENTATION_IGNORED_NAMES', implode(', ', $ignored)));
}
}
}
1 change: 0 additions & 1 deletion acp/permission_sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class permission_sync
const DEFAULT_GRANTED_ROLES = array('ROLE_USER_FULL', 'ROLE_USER_STANDARD');
const DEFAULT_GRANTED_GROUPS = array('GUESTS', 'BOTS');


/** @var driver_interface */
protected $db;

Expand Down
12 changes: 9 additions & 3 deletions adm/style/acp_documentation.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ <h3>{{ lang('WARNING') }}</h3>

{% if RESYNC_FEEDBACK %}
<div class="successbox">
<p>{{ RESYNC_FEEDBACK }}</p>
<p>{{ RESYNC_FEEDBACK|e }}</p>
</div>
{% endif %}

Expand Down Expand Up @@ -113,6 +113,12 @@ <h3>{{ lang('WARNING') }}</h3>
{% if S_DOCUMENTATION_BUILD_FOUND %}
<h1>{{ lang('ACP_DOCUMENTATION_DETECTED') }}</h1>

{% if DOCUMENTATION_IGNORED_NAMES %}
<div class="errorbox">
<p>{{ DOCUMENTATION_IGNORED_NAMES|e }}</p>
</div>
{% endif %}

<table cellspacing="1">
<thead>
<tr>
Expand All @@ -123,8 +129,8 @@ <h1>{{ lang('ACP_DOCUMENTATION_DETECTED') }}</h1>
<tbody>
{% for documentation_lang in documentation_lang %}
<tr>
<td>{{ documentation_lang.CODE }}</td>
<td>{{ documentation_lang.SECTIONS }}</td>
<td>{{ documentation_lang.CODE|e }}</td>
<td>{{ documentation_lang.SECTIONS|e }}</td>
</tr>
{% endfor %}
</tbody>
Expand Down
54 changes: 42 additions & 12 deletions adm/style/documentation-tooltips.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
(function () {
"use strict";

// A malformed attribute must not stop the remaining tooltips working.
function parseJson(value) {
try {
return JSON.parse(value || "{}") || {};
} catch (error) {
return {};
}
}

function annotate(node, explanation) {
var term = document.createElement("span");
term.className = "documentation-tooltip-term";
Expand All @@ -11,8 +20,8 @@
}

document.querySelectorAll("[data-doc-abbreviations]").forEach(function (article) {
var definitions = JSON.parse(article.dataset.docAbbreviations);
var headings = JSON.parse(article.dataset.docEventHeadings || "{}");
var definitions = parseJson(article.dataset.docAbbreviations);
var headings = parseJson(article.dataset.docEventHeadings);
var seen = Object.create(null);
var walker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);
var nodes = [];
Expand All @@ -27,7 +36,9 @@
var offset = 0;
var match;
while ((match = pattern.exec(node.textContent))) {
if (seen[match[0]] || !definitions[match[0]]) continue;
if (seen[match[0]] || !definitions[match[0]]) {
continue;
}
seen[match[0]] = true;
fragment.appendChild(document.createTextNode(node.textContent.slice(offset, match.index)));
var text = document.createTextNode(match[0]);
Expand All @@ -50,10 +61,16 @@
});
article.querySelectorAll("img[alt]").forEach(function (image) {
var description = image.getAttribute("alt").trim();
if (!description) return;
if (!description) {
return;
}
var target = image.closest("a") || image;
if (!target.dataset.docTooltip) target.dataset.docTooltip = description;
if (target === image) target.tabIndex = 0;
if (!target.dataset.docTooltip) {
target.dataset.docTooltip = description;
}
if (target === image) {
target.tabIndex = 0;
}
target.classList.add("documentation-tooltip-image");
});
});
Expand All @@ -73,8 +90,11 @@
var ids = (active.getAttribute("aria-describedby") || "").split(/\s+/).filter(function (id) {
return id && id !== popup.id;
});
if (ids.length) active.setAttribute("aria-describedby", ids.join(" "));
else active.removeAttribute("aria-describedby");
if (ids.length) {
active.setAttribute("aria-describedby", ids.join(" "));
} else {
active.removeAttribute("aria-describedby");
}
}
active = null;
popup.hidden = true;
Expand All @@ -90,14 +110,18 @@
var rect = target.getBoundingClientRect();
var left = Math.max(12, Math.min(rect.left, window.innerWidth - popup.offsetWidth - 12));
var top = rect.bottom + 6;
if (top + popup.offsetHeight > window.innerHeight - 12) top = Math.max(12, rect.top - popup.offsetHeight - 6);
if (top + popup.offsetHeight > window.innerHeight - 12) {
top = Math.max(12, rect.top - popup.offsetHeight - 6);
}
popup.style.left = left + "px";
popup.style.top = top + "px";
}

function scheduleHide() {
timer = setTimeout(function () {
if (active !== document.activeElement) hide();
if (active !== document.activeElement) {
hide();
}
}, 150);
}

Expand All @@ -110,9 +134,15 @@
});
popup.addEventListener("mouseenter", function () { clearTimeout(timer); });
popup.addEventListener("mouseleave", scheduleHide);
document.addEventListener("keydown", function (event) { if (event.key === "Escape") hide(); });
document.addEventListener("keydown", function (event) {
if (event.key === "Escape") {
hide();
}
});
document.addEventListener("click", function (event) {
if (!event.target.closest("[data-doc-tooltip], .documentation-tooltip-popup")) hide();
if (!event.target.closest("[data-doc-tooltip], .documentation-tooltip-popup")) {
hide();
}
});
window.addEventListener("resize", hide);
document.addEventListener("scroll", hide, true);
Expand Down
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
],
"require": {
"php": ">=8.0.0",
"phpbb/phpbb": ">=3.3.19",
"composer/installers": "^1.0 || ^2.0"
},
"require-dev": {
Expand All @@ -31,7 +30,7 @@
"extra": {
"display-name": "Documentation",
"soft-require": {
"phpbb/phpbb": ">=3.3.19"
"phpbb/phpbb": ">=3.3.19,<4.0.0@dev"
}
}
}
4 changes: 2 additions & 2 deletions config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ services:
- '@template'
- '@user'
- '@phpbbmodders.documentation.helper'
- '%core.root_path%'
- '%core.php_ext%'
- '@request'
- '@language'

phpbbmodders.documentation.listener:
class: phpbbmodders\documentation\event\listener
Expand All @@ -31,6 +30,7 @@ services:
- '@phpbbmodders.documentation.helper'
- '@template'
- '@phpbbmodders.documentation.permission_sync'
- '@language'
tags:
- { name: event.listener }

Expand Down
18 changes: 10 additions & 8 deletions contrib/caddy-docs-build-deny.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
# run when a request goes through phpBB's own /documentation/... route,
# not a direct hit on this directory.
#
# Add these two lines inside your existing site block (the one serving
# phpBB), above any php_fastcgi/file_server directives. Caddy's default
# directive ordering runs `respond` before those regardless of where in
# the block it's written, so this reliably wins even placed at the top.
# If phpBB isn't installed at your site root, adjust the path below to
# match (e.g. under a /forum/ path, this becomes
# /forum/ext/phpbbmodders/documentation/docs-build/*).
# phpBB ships no Caddy sample config, so nothing denies store/ by default.
# The matcher covers the default build path (store/phpbbmodders_documentation/)
# and the old default inside the extension. Add these two lines inside your
# existing site block (the one serving phpBB), above any
# php_fastcgi/file_server directives. Caddy's default directive ordering
# runs `respond` before those regardless of where in the block it's
# written, so this reliably wins even placed at the top.
# If phpBB isn't installed at your site root, adjust the paths below to
# match (e.g. under a /forum/ path, /store/... becomes /forum/store/...).

@phpbbmodders_documentation_docs_build path /ext/phpbbmodders/documentation/docs-build/*
@phpbbmodders_documentation_docs_build path /store/phpbbmodders_documentation/* /ext/phpbbmodders/documentation/docs-build/*
respond @phpbbmodders_documentation_docs_build 403
5 changes: 5 additions & 0 deletions contrib/iis-docs-build-deny.web.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
at their real filesystem path, bypassing the extension's
per-section/per-language ACL checks entirely.

Not needed for the default build path (store/phpbbmodders_documentation/)
when phpBB's own root web.config is in use, since it already hides the
"store" segment. This block covers the old default inside the
extension; for any other location, hide its segment the same way.

Merge this <location> block into your site's existing web.config
(inside the top-level <configuration> element, alongside phpBB's own
<location path="ext"> and <location path="images/avatars"> blocks —
Expand Down
8 changes: 6 additions & 2 deletions contrib/lighttpd-docs-build-deny.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
# checks entirely — those only run when a request goes through phpBB's
# own /documentation/... route, not a direct hit on this directory.
#
# Not needed for the default build path (store/phpbbmodders_documentation/)
# if your config includes the store rule from phpBB's sample. This covers
# both that path and the old default inside the extension.
#
# Add this inside the same $HTTP["host"] block as phpBB's own "Deny
# access to internal phpbb files" rule (see docs/lighttpd.sample.conf in
# the phpBB package). If phpBB isn't installed at your web root, adjust
# the path below to match.
# the paths below to match.

$HTTP["url"] =~ "^/ext/phpbbmodders/documentation/docs-build/" {
$HTTP["url"] =~ "^/(store/phpbbmodders_documentation|ext/phpbbmodders/documentation/docs-build)/" {
url.access-deny = ( "" )
}
22 changes: 15 additions & 7 deletions contrib/nginx-docs-build-deny.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@
# only run when a request goes through phpBB's own /documentation/...
# route, not a direct hit on this directory.
#
# Nginx doesn't read .htaccess (unlike Apache, where docs-build/.htaccess
# already covers this), so this needs to be added explicitly to your
# site's server block. Place it alongside phpBB's own "Deny access to
# Not needed for the default build path (store/phpbbmodders_documentation/)
# if your server block includes the store rule from phpBB's
# nginx.sample.conf. These blocks cover both that path and the old default
# inside the extension.
#
# Nginx doesn't read .htaccess, so this needs to be added explicitly to
# your site's server block. Place it alongside phpBB's own "Deny access to
# internal phpbb files" location block, inside the same `server { ... }`
# — see docs/nginx.sample.conf in the phpBB package for that block's
# exact location if you're not sure where.
#
# If phpBB isn't installed at your web root, adjust the path below to
# match (e.g. if phpBB lives at /forum/, this becomes
# /forum/ext/phpbbmodders/documentation/docs-build/).
# If phpBB isn't installed at your web root, adjust the paths below to
# match (e.g. if phpBB lives at /forum/, /store/... becomes /forum/store/...).

location ^~ /ext/phpbbmodders/documentation/docs-build/ {
location ^~ /store/phpbbmodders_documentation/ {
deny all;
# deny was ignored before nginx 0.8.40 for connections over IPv6.
# Use internal directive to prohibit access on older versions.
internal;
}

location ^~ /ext/phpbbmodders/documentation/docs-build/ {
deny all;
internal;
}
Loading
Loading