help: Add default page to display on /help when help server is off.

We've copied the button and error colors from portico_signin.css. We did
not want the new HTML file to depend on portico_signin.css since they
are unrelated. In addition, having those colors diverge over time might
not be an issue.

We make the raw mode work with /help and /help/ both.

See https://chat.zulip.org/#narrow/channel/19-documentation/topic/edits.20not.20appearing.20with.20vagrant/near/2257442

Co-authored-by: Alya Abbott <alya@zulip.com>
This commit is contained in:
Shubham Padia
2025-09-11 15:19:23 +00:00
committed by Tim Abbott
parent 3b6d8de815
commit c3fbe00eb0
8 changed files with 241 additions and 32 deletions

View File

@@ -48,6 +48,7 @@ class DocPageTest(ZulipTestCase):
"/devtools/",
"/emails/",
"/errors/",
"/help",
"/integrations/",
]:
if url.startswith(prefix):
@@ -70,6 +71,11 @@ class DocPageTest(ZulipTestCase):
if url.startswith("/attribution/"):
allow_robots = False
# When a raw MDX file is being fetched, the meta tag to
# disallow robots will be absent.
if url in ["/help/status-and-availability?raw", "/help/?raw", "/help?raw"]:
allow_robots = True
result = self.get_doc(url, subdomain=subdomain)
self.print_msg_if_error(url, result)
self.assertEqual(result.status_code, 200)
@@ -243,6 +249,49 @@ class DocPageTest(ZulipTestCase):
self._test("/devtools/", ["Useful development URLs"])
self._test("/emails/", ["Manually generate most emails"])
def test_dev_help_default_page_endpoints(self) -> None:
# View on Zulip.com and View source URLs should be visible.
self._test(
"/help/status-and-availability",
[
'href="https://zulip.com/help/status-and-availability"',
'href="/help/status-and-availability?raw"',
],
)
# Raw MDX file should be shown when `?raw` is present.
self._test(
"/help/status-and-availability?raw",
["---", "title: Status and availability", "### Set a status"],
)
self._test(
"/help/nonexistent-page-that-does-not-exist",
["This is not a valid help path and not a valid MDX file"],
)
# `?raw` should have no effect when the page does not exist
self._test(
"/help/nonexistent-page-that-does-not-exist?raw",
["This is not a valid help path and not a valid MDX file"],
)
# Root /help and /help/ is a special case without subpath.
self._test("/help/?raw", ["---", "title: Zulip help center"])
self._test("/help?raw", ["---", "title: Zulip help center"])
with (
mock.patch("builtins.open", side_effect=OSError("File read error")),
self.assertLogs("django.request", level="ERROR") as m,
):
result = self.client_get("/help/status-and-availability?raw")
self.assertEqual(result.status_code, 500)
self.assertIn("Error reading MDX file", result.content.decode())
self.assertEqual(
m.output,
["ERROR:django.request:Internal Server Error: /help/status-and-availability"],
)
def test_error_endpoints(self) -> None:
self._test("/errors/404/", ["Page not found"])
self._test("/errors/5xx/", ["Internal server error"])

View File

@@ -0,0 +1,57 @@
import os
import werkzeug
from django.conf import settings
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
def help_dev_mode_view(request: HttpRequest, subpath: str = "") -> HttpResponse:
"""
Dev only view that displays help information for setting up the
help center dev server in the default `run-dev` mode where the
help center server is not running. Also serves raw MDX content when
`raw` query param is passed is passed.
"""
def read_mdx_file(filename: str) -> HttpResponse:
file_path = os.path.join(
settings.DEPLOY_ROOT, "starlight_help", "src", "content", "docs", f"{filename}.mdx"
)
try:
with open(file_path, encoding="utf-8") as f:
content = f.read()
return HttpResponse(content, content_type="text/plain")
except OSError:
return HttpResponse("Error reading MDX file", status=500)
mdx_file_exists = False
is_requesting_raw_file = request.GET.get("raw") == ""
if subpath:
subpath = werkzeug.utils.secure_filename(subpath)
raw_url = f"/help/{subpath}?raw"
mdx_path = os.path.join(
settings.DEPLOY_ROOT, "starlight_help", "src", "content", "docs", f"{subpath}.mdx"
)
mdx_file_exists = os.path.exists(mdx_path) and "/include/" not in mdx_path
if mdx_file_exists and is_requesting_raw_file:
return read_mdx_file(subpath)
else:
if request.path.endswith("/"):
raw_url = "/help/?raw"
else:
raw_url = "/help?raw"
mdx_file_exists = True
if is_requesting_raw_file:
return read_mdx_file("index")
return render(
request,
"zerver/development/dev_help.html",
{
"subpath": subpath,
"mdx_file_exists": mdx_file_exists,
"raw_url": raw_url,
},
)