diff --git a/docs/documentation/helpcenter.md b/docs/documentation/helpcenter.md index 0a9555bc17..6d1e9dc3b6 100644 --- a/docs/documentation/helpcenter.md +++ b/docs/documentation/helpcenter.md @@ -112,6 +112,10 @@ existing help center articles: of the article that again links to any help center documentation mentioned in the text or related to the feature. +If your updates to the existing article will change the name of the +markdown file, then see section below on [redirecting an existing +article](#redirecting-an-existing-article). + Creating robust and informative help center articles with good links will allow users to navigate the help center much more effectively. @@ -148,6 +152,57 @@ with modals, etc. should never go in the help center documentation. In such cases, you may be able to fix the problem by adding text in-app, where the user will see it as they are interacting with the feature. +### Redirecting an existing article + +From time to time, we might want to rename an article in the help +center, or REST API documentation. This change will break incoming +links, including links in published Zulip blog posts, links in other +branches of the repository that haven't been rebased, and more +importantly links from previous versions of Zulip. + +To fix these broken links, you can easily add a URL redirect in: +`zerver/lib/url_redirects.py`. + +For help center documentation, once you've renamed the file in your +branch (e.g., `git mv path/to/foo.md path/to/bar.md`), go to +`url_redirects.py` and add a new `URLRedirect` to the +`HELP_DOCUMENTATION_REDIRECTS` list: + +```python +HELP_DOCUMENTATION_REDIRECTS: List[URLRedirect] = [ + # Add URL redirects for help center documentation here: + URLRedirect("/help/foo", "/help/bar"), + ... +``` + +Note that you will also need to add redirects when you're deleting +a help center article and adding its content to an existing article +as a section. In that case, the new URL will include the new section +header: `URLRedirect("/help/foo", "/help/bar#new-section-header"),`. + +For REST API documentation, you will either need to rename the file +as above, or you will need to update the endpoint's `operationId` in +`zerver/openapi/zulip.yaml`. Then, you would add a new `URLRedirect` +to the `API_DOCUMENTATION_REDIRECTS` list in `url_redirects.py`. + +You should still check for references to the old URL in your branch +and replace those with the new URL (e.g., `git grep "/help/foo"`). +Updating section headers in existing help center articles does not +require adding a URL redirect, but you will need to update any +existing links to that article's section in your branch. + +If you have the Zulip development environment set up, you can manually +test your changes by loading the old URL in your browser (e.g., +`http://localhost:9991/help/foo`), and confirming that it redirects to +the new url (e.g., `http://localhost:9991/help/bar`). + +There is also an automated test in `zerver/tests/test_urls.py` that +checks all the URL redirects, which you can run from the command line: + +```console +./tools/test-backend zerver.tests.test_urls.URLRedirectTest +``` + ## Writing style Below are some general style and writing conventions that should be used diff --git a/zerver/lib/test_helpers.py b/zerver/lib/test_helpers.py index c8c2709435..fc4018296a 100644 --- a/zerver/lib/test_helpers.py +++ b/zerver/lib/test_helpers.py @@ -481,24 +481,7 @@ def write_instrumentation_reports(full_suite: bool, include_webhooks: bool) -> N "confirmation_key/", "node-coverage/(?P.+)", "docs/(?P.+)", - "help/add-custom-emoji", - "help/configure-who-can-add-custom-emoji", - "help/change-the-topic-of-a-message", - "help/configure-missed-message-emails", - "help/community-topic-edits", - "help/about-streams-and-topics", - "help/delete-a-stream", - "help/add-an-alert-word", - "help/change-notification-sound", - "help/configure-message-notification-emails", - "help/disable-new-login-emails", - "help/test-mobile-notifications", - "help/troubleshooting-desktop-notifications", - "help/web-public-streams", "for/working-groups-and-communities/", - "help/only-allow-admins-to-add-emoji", - "help/night-mode", - "api/delete-stream", "casper/(?P.+)", "static/(?P.+)", "flush_caches", diff --git a/zerver/lib/url_redirects.py b/zerver/lib/url_redirects.py new file mode 100644 index 0000000000..f106b3ec62 --- /dev/null +++ b/zerver/lib/url_redirects.py @@ -0,0 +1,56 @@ +from dataclasses import dataclass +from typing import List + + +@dataclass +class URLRedirect: + old_url: str + new_url: str + + +API_DOCUMENTATION_REDIRECTS: List[URLRedirect] = [ + # Add URL redirects for REST API documentation here: + URLRedirect("/api/delete-stream", "/api/archive-stream"), +] + +POLICY_DOCUMENTATION_REDIRECTS: List[URLRedirect] = [ + # Add URL redirects for policy documentation here: + URLRedirect("/privacy/", "/policies/privacy"), + URLRedirect("/terms/", "/policies/terms"), +] + +HELP_DOCUMENTATION_REDIRECTS: List[URLRedirect] = [ + # Add URL redirects for help center documentation here: + URLRedirect("/help/delete-a-stream", "/help/archive-a-stream"), + URLRedirect("/help/change-the-topic-of-a-message", "/help/rename-a-topic"), + URLRedirect("/help/configure-missed-message-emails", "/help/email-notifications"), + URLRedirect("/help/add-an-alert-word", "/help/pm-mention-alert-notifications#alert-words"), + URLRedirect("/help/test-mobile-notifications", "/help/mobile-notifications"), + URLRedirect( + "/help/troubleshooting-desktop-notifications", + "/help/desktop-notifications#troubleshooting-desktop-notifications", + ), + URLRedirect( + "/help/change-notification-sound", "/help/desktop-notifications#change-notification-sound" + ), + URLRedirect("/help/configure-message-notification-emails", "/help/email-notifications"), + URLRedirect("/help/disable-new-login-emails", "/help/email-notifications#new-login-emails"), + # The `help/about-streams-and-topics` redirect is particularly important, + # because the old URL appears in links from Welcome Bot messages. + URLRedirect("/help/about-streams-and-topics", "/help/streams-and-topics"), + URLRedirect("/help/community-topic-edits", "/help/configure-who-can-edit-topics"), + URLRedirect( + "/help/only-allow-admins-to-add-emoji", "/help/custom-emoji#change-who-can-add-custom-emoji" + ), + URLRedirect( + "/help/configure-who-can-add-custom-emoji", + "/help/custom-emoji#change-who-can-add-custom-emoji", + ), + URLRedirect("/help/add-custom-emoji", "/help/custom-emoji"), + URLRedirect("/help/night-mode", "/help/dark-theme"), + URLRedirect("/help/web-public-streams", "/help/public-access-option"), +] + +DOCUMENTATION_REDIRECTS = ( + API_DOCUMENTATION_REDIRECTS + POLICY_DOCUMENTATION_REDIRECTS + HELP_DOCUMENTATION_REDIRECTS +) diff --git a/zerver/tests/test_urls.py b/zerver/tests/test_urls.py index 657c371150..247ed6b6c8 100644 --- a/zerver/tests/test_urls.py +++ b/zerver/tests/test_urls.py @@ -6,6 +6,11 @@ import django.urls.resolvers from django.test import Client from zerver.lib.test_classes import ZulipTestCase +from zerver.lib.url_redirects import ( + API_DOCUMENTATION_REDIRECTS, + HELP_DOCUMENTATION_REDIRECTS, + POLICY_DOCUMENTATION_REDIRECTS, +) from zerver.models import Realm, Stream from zproject import urls @@ -154,3 +159,20 @@ class ErrorPageTest(ZulipTestCase): "/json/users", secure=True, HTTP_REFERER="https://somewhere", HTTP_HOST="$nonsense" ) self.assertEqual(result.status_code, 400) + + +class RedirectURLTest(ZulipTestCase): + def test_api_redirects(self) -> None: + for redirect in API_DOCUMENTATION_REDIRECTS: + result = self.client_get(redirect.old_url, follow=True) + self.assert_in_success_response(["Zulip homepage", "API documentation home"], result) + + def test_help_redirects(self) -> None: + for redirect in HELP_DOCUMENTATION_REDIRECTS: + result = self.client_get(redirect.old_url, follow=True) + self.assert_in_success_response(["Zulip homepage", "Help center home"], result) + + def test_policy_redirects(self) -> None: + for redirect in POLICY_DOCUMENTATION_REDIRECTS: + result = self.client_get(redirect.old_url, follow=True) + self.assert_in_success_response(["Policies", "Archive"], result) diff --git a/zproject/urls.py b/zproject/urls.py index c5ef772ce0..bffb061f92 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -18,6 +18,7 @@ from django.views.generic import RedirectView, TemplateView from zerver.forms import LoggingSetPasswordForm from zerver.lib.integrations import WEBHOOK_INTEGRATIONS from zerver.lib.rest import rest_path +from zerver.lib.url_redirects import DOCUMENTATION_REDIRECTS from zerver.tornado.views import cleanup_event_queue, get_events, get_events_internal, notify from zerver.views.alert_words import add_alert_words, list_alert_words, remove_alert_words from zerver.views.attachments import list_by_user, remove @@ -780,98 +781,19 @@ policy_documentation_view = MarkdownDirectoryView.as_view( template_name="zerver/documentation_main.html", policies_view=True, ) + +# Redirects due to us having moved help center, API or policy documentation pages: +for redirect in DOCUMENTATION_REDIRECTS: + old_url = redirect.old_url.lstrip("/") + urls += [path(old_url, RedirectView.as_view(url=redirect.new_url, permanent=True))] + urls += [ - # Redirects due to us having moved the docs: - path( - "help/delete-a-stream", RedirectView.as_view(url="/help/archive-a-stream", permanent=True) - ), - path("api/delete-stream", RedirectView.as_view(url="/api/archive-stream", permanent=True)), - path( - "help/change-the-topic-of-a-message", - RedirectView.as_view(url="/help/rename-a-topic", permanent=True), - ), - path( - "help/configure-missed-message-emails", - RedirectView.as_view(url="/help/email-notifications", permanent=True), - ), - path( - "help/add-an-alert-word", - RedirectView.as_view( - url="/help/pm-mention-alert-notifications#alert-words", permanent=True - ), - ), - path( - "help/test-mobile-notifications", - RedirectView.as_view(url="/help/mobile-notifications", permanent=True), - ), - path( - "help/troubleshooting-desktop-notifications", - RedirectView.as_view( - url="/help/desktop-notifications#troubleshooting-desktop-notifications", permanent=True - ), - ), - path( - "help/change-notification-sound", - RedirectView.as_view( - url="/help/desktop-notifications#change-notification-sound", permanent=True - ), - ), - path( - "help/configure-message-notification-emails", - RedirectView.as_view(url="/help/email-notifications", permanent=True), - ), - path( - "help/disable-new-login-emails", - RedirectView.as_view(url="/help/email-notifications#new-login-emails", permanent=True), - ), - # This redirect is particularly important, because the old URL - # appears in links from Welcome Bot messages. - path( - "help/about-streams-and-topics", - RedirectView.as_view(url="/help/streams-and-topics", permanent=True), - ), - path( - "help/community-topic-edits", - RedirectView.as_view(url="/help/configure-who-can-edit-topics", permanent=True), - ), - path( - "help/only-allow-admins-to-add-emoji", - RedirectView.as_view( - url="/help/custom-emoji#change-who-can-add-custom-emoji", permanent=True - ), - ), - path( - "help/configure-who-can-add-custom-emoji", - RedirectView.as_view( - url="/help/custom-emoji#change-who-can-add-custom-emoji", permanent=True - ), - ), - path( - "help/add-custom-emoji", - RedirectView.as_view(url="/help/custom-emoji", permanent=True), - ), - path( - "help/night-mode", - RedirectView.as_view(url="/help/dark-theme", permanent=True), - ), - path( - "help/web-public-streams", - RedirectView.as_view(url="/help/public-access-option", permanent=True), - ), path("help/", help_documentation_view), path("help/", help_documentation_view), path("api/", api_documentation_view), path("api/", api_documentation_view), path("policies/", policy_documentation_view), path("policies/", policy_documentation_view), - path( - "privacy/", - RedirectView.as_view(url="/policies/privacy"), - ), - path( - "terms/", - RedirectView.as_view(url="/policies/terms"), - ), ] # Two-factor URLs