integrations: Change URL scheme for categories and /doc/ page.

We redirect existing URLs to the new URLs. We want to use
`/integrations/category/{category_slug}` for categories and
`/integrations/{integration_name}` instead of
`/integrations/doc/{integration_name}` for individual integrations page.
This commit is contained in:
Shubham Padia
2025-10-09 08:45:13 +00:00
committed by Tim Abbott
parent a9c0cc1162
commit 40dedace08
44 changed files with 198 additions and 117 deletions

View File

@@ -9,10 +9,10 @@ Zulip:
or cases where the third-party tool wants to control the formatting
of the messages in Zulip.
* Use one of our supported [integration
frameworks](/integrations/meta-integration), such as the
[Slack-compatible incoming webhook](/integrations/doc/slack_incoming),
[Zapier integration](/integrations/doc/zapier), or
[IFTTT integration](/integrations/doc/ifttt).
frameworks](/integrations/category/meta-integration), such as the
[Slack-compatible incoming webhook](/integrations/slack_incoming),
[Zapier integration](/integrations/zapier), or
[IFTTT integration](/integrations/ifttt).
* Implementing an incoming webhook integration (detailed on this page),
where all the logic for formatting the Zulip messages lives in the
Zulip server. This is how most of [Zulip's official
@@ -36,7 +36,7 @@ process.
* Set up the
[Zulip development environment](https://zulip.readthedocs.io/en/latest/development/overview.html).
* Use [Zulip's JSON integration](/integrations/doc/json),
* Use [Zulip's JSON integration](/integrations/json),
<https://webhook.site/>, or a similar site to capture an example
webhook payload from the third-party service. Create a
`zerver/webhooks/<mywebhook>/fixtures/` directory, and add the

View File

@@ -13,7 +13,7 @@ integration.
The first step in creating an incoming webhook is to examine the data that the
service you want to integrate will be sending to Zulip.
* Use [Zulip's JSON integration](/integrations/doc/json),
* Use [Zulip's JSON integration](/integrations/json),
<https://webhook.site/>, or a similar tool to capture webhook
payload(s) from the service you are integrating. Examining this data
allows you to do two things:
@@ -289,7 +289,7 @@ from zerver.lib.webhooks.common import PresetUrlOption, WebhookUrlOption
Currently configured preset URL options:
- **`BRANCHES`**: This preset is intended to be used for [version control
integrations](/integrations/version-control), and adds UI for the user to
integrations](/integrations/category/version-control), and adds UI for the user to
configure which branches of a project's repository will trigger Zulip
notification messages. When the user specifies which branches to receive
notifications from, the `branches` parameter will be added to the [generated
@@ -298,14 +298,14 @@ Currently configured preset URL options:
`&branches=main%2Cdev` would be appended to the generated integration URL.
- **`IGNORE_PRIVATE_REPOSITORIES`**: This preset is intended to be used for
[version control integrations](/integrations/version-control), and adds UI
[version control integrations](/integrations/category/version-control), and adds UI
for the user exclude private repositories from triggering Zulip
notification messages. When the user selects this option, the
`ignore_private_repositories` boolean parameter will be added to the
[generated integration URL](/help/generate-integration-url).
- **`MAPPING`**: This preset is intended to be used for [chat-app
integrations](/integrations/communication) (like Slack), and adds a
integrations](/integrations/category/communication) (like Slack), and adds a
special option, **Matching Zulip channel**, to the UI for where to send
Zulip notification messages. This special option maps the notification
messages to Zulip channels that match the messages' original channel

View File

@@ -7,8 +7,8 @@ guide should help you find the API you need:
[already has a native integration](/integrations/).
* Next, check if [Zapier](https://zapier.com/apps) or
[IFTTT](https://ifttt.com/search) has an integration.
[Zulip's Zapier integration](/integrations/doc/zapier) and
[Zulip's IFTTT integration](/integrations/doc/ifttt) often allow
[Zulip's Zapier integration](/integrations/zapier) and
[Zulip's IFTTT integration](/integrations/ifttt) often allow
integrating a new service with Zulip without writing any code.
* If you'd like to send content into Zulip, you can
[write a native incoming webhook integration](/api/incoming-webhooks-overview)

View File

@@ -9,7 +9,7 @@ advantage of Zulip's [topics](/help/introduction-to-topics) to organize
notification messages. Additionally, thousands of integrations are available
through [Zapier](https://zapier.com/apps) and [IFTTT](https://ifttt.com/search).
You can also [connect any webhook designed to work with
Slack](/integrations/doc/slack_incoming) to Zulip.
Slack](/integrations/slack_incoming) to Zulip.
If you don't find an integration you need, you can:
@@ -46,8 +46,8 @@ additional integrations through [Zapier](https://zapier.com/apps) and
1. Search [Zapier](https://zapier.com/apps) or [IFTTT](https://ifttt.com/search)
for the product you'd like to connect to Zulip.
1. Follow the integration instructions for [Zapier](/integrations/doc/zapier) or
[IFTTT](/integrations/doc/ifttt).
1. Follow the integration instructions for [Zapier](/integrations/zapier) or
[IFTTT](/integrations/ifttt).
{end_tabs}

View File

@@ -154,15 +154,15 @@ Here are a few common macros used to document Zulip's integrations:
```
For an example rendering, see
[Zulip's Beanstalk integration](https://zulip.com/integrations/doc/beanstalk).
[Zulip's Beanstalk integration](https://zulip.com/integrations/beanstalk).
[github-integration]: https://zulip.com/integrations/doc/github
[zendesk]: https://zulip.com/integrations/doc/zendesk
[matrix]: https://zulip.com/integrations/doc/matrix#configure-the-bridge
[codebase]: https://zulip.com/integrations/doc/codebase
[beanstalk]: https://zulip.com/integrations/doc/beanstalk
[front]: https://zulip.com/integrations/doc/front
[gitlab]: https://zulip.com/integrations/doc/gitlab
[github-integration]: https://zulip.com/integrations/github
[zendesk]: https://zulip.com/integrations/zendesk
[matrix]: https://zulip.com/integrations/matrix#configure-the-bridge
[codebase]: https://zulip.com/integrations/codebase
[beanstalk]: https://zulip.com/integrations/beanstalk
[front]: https://zulip.com/integrations/front
[gitlab]: https://zulip.com/integrations/gitlab
[integrations-file]: https://github.com/zulip/zulip/blob/main/zerver/lib/integrations.py
## Writing guidelines
@@ -170,7 +170,7 @@ Here are a few common macros used to document Zulip's integrations:
For the vast majority of integrations, you should just copy the docs for a
similar integration and edit it. [Basecamp][basecamp] is a good one to copy.
[basecamp]: https://zulip.com/integrations/doc/basecamp
[basecamp]: https://zulip.com/integrations/basecamp
### General writing guidelines

View File

@@ -881,7 +881,7 @@ _Released 2024-11-22_
- Fixed emoji appearing huge when viewing email notifications in
Microsoft Outlook.
- Fixed the [slack-compatible incoming
webhook](https://zulip.com/integrations/doc/slack_incoming) to
webhook](https://zulip.com/integrations/slack_incoming) to
return success/failure HTTP responses in the correct format.
- Fixed several bugs with the data import tools, primarily around
thumbnailing of images and input validation.
@@ -1269,7 +1269,7 @@ _Released 2024-05-09_
- The default' topic visibility icon is no longer displayed in the inbox view,
for a cleaner look.
- Fixed confusing wording in the [Alertmanager
integration](https://zulip.com/integrations/doc/alertmanager).
integration](https://zulip.com/integrations/alertmanager).
- Started allowing DMs to bots and to oneself, regardless if [DMs are in general
restricted](https://zulip.com/help/restrict-direct-messages).
- Notices indicating that “push notifications are not working” are now
@@ -1659,7 +1659,7 @@ _Released 2023-08-25_
reverse order.
- Upgraded Python requirements.
- Updated puppet dependencies.
- Improved the [Sentry integration](https://zulip.com/integrations/doc/sentry),
- Improved the [Sentry integration](https://zulip.com/integrations/sentry),
including making the “Test plugin” button in Sentry work properly.
- Reduced memory usage by replacing a custom error reporting handler with the
default Django implementation. This will result in a slight change in the
@@ -1684,7 +1684,7 @@ _Released 2023-08-25_
[host multiple Zulip](../production/multiple-organizations.md)
organizations on one server.
- Fixed missing images in documentation for the
[“XKCD” bot](https://zulip.com/integrations/doc/xkcd).
[“XKCD” bot](https://zulip.com/integrations/xkcd).
- Fixed “Back to login page” button alignment in the desktop app.
- Added a reference to
[PostgreSQL upgrades](../production/upgrade.md#upgrading-postgresql)

View File

@@ -9,7 +9,7 @@ because it enables:
into Zulip.
- Integrating third-party services that can send email notifications
into Zulip. See the [integration
documentation](https://zulip.com/integrations/doc/email) for
documentation](https://zulip.com/integrations/email) for
details.
Once this integration is configured, each channel will have a special

View File

@@ -5,10 +5,10 @@ call](https://zulip.com/help/start-a-call) with the click of a button, using the
call provider of your choice. The call providers
supported by Zulip are:
- [Jitsi Meet](https://zulip.com/integrations/doc/jitsi), a fully-encrypted,
- [Jitsi Meet](https://zulip.com/integrations/jitsi), a fully-encrypted,
100% open source video conferencing solution.
- [Zoom](https://zulip.com/integrations/doc/zoom)
- [BigBlueButton](https://zulip.com/integrations/doc/big-blue-button)
- [Zoom](https://zulip.com/integrations/zoom)
- [BigBlueButton](https://zulip.com/integrations/big-blue-button)
By default, Zulip uses the [cloud version of Jitsi Meet](https://meet.jit.si/)
as its call provider. This page documents the configurations required to support

View File

@@ -6,7 +6,7 @@ guide to [sending outgoing email](../production/email.md). If you're trying to
configure an email integration to receive incoming email (e.g., so that users
can reply to message notification emails via email), you might be interested in
our instructions for
[setting up an email integration](https://zulip.com/integrations/doc/email).
[setting up an email integration](https://zulip.com/integrations/email).
On to the documentation. Zulip's email system is fairly straightforward,
with only a few things you need to know to get started.

View File

@@ -16,9 +16,9 @@ source video conferencing solution. Organization administrators can also
change the organization's call provider. The call providers
supported by Zulip are:
* [Jitsi Meet](/integrations/doc/jitsi)
* [Zoom integration](/integrations/doc/zoom)
* [BigBlueButton integration](/integrations/doc/big-blue-button)
* [Jitsi Meet](/integrations/jitsi)
* [Zoom integration](/integrations/zoom)
* [BigBlueButton integration](/integrations/big-blue-button)
<ZulipTip>
You can disable the video and voice call buttons for your organization
@@ -55,6 +55,6 @@ instance of Jitsi Meet.
## Related articles
* [Start a call](/help/start-a-call)
* [Jitsi Meet integration](/integrations/doc/jitsi)
* [Zoom integration](/integrations/doc/zoom)
* [BigBlueButton integration](/integrations/doc/big-blue-button)
* [Jitsi Meet integration](/integrations/jitsi)
* [Zoom integration](/integrations/zoom)
* [BigBlueButton integration](/integrations/big-blue-button)

View File

@@ -14,8 +14,8 @@ import UserCogIcon from "~icons/zulip-icon/user-cog";
Many [Zulip integrations](/integrations/) are webhooks. An incoming webhook
integration allows a third-party service, such as an [issue
tracker](/integrations/doc/github) or an [alerting
tool](/integrations/doc/pagerduty), to post updates to Zulip. To configure
tracker](/integrations/github) or an [alerting
tool](/integrations/pagerduty), to post updates to Zulip. To configure
where these updates will be posted, you need to generate a special Zulip
integration URL.

View File

@@ -197,5 +197,5 @@ moving from Slack](/help/moving-from-slack).
* [Choosing between Zulip Cloud and self-hosting](/help/zulip-cloud-or-self-hosting)
* [Moving from Slack](/help/moving-from-slack)
* [Slack-compatible incoming webhook](/integrations/doc/slack_incoming)
* [Slack-compatible incoming webhook](/integrations/slack_incoming)
* [Getting started with Zulip](/help/getting-started-with-zulip)

View File

@@ -15,7 +15,7 @@ advantage of Zulip's [topics](/help/introduction-to-topics) to organize
notification messages. Additionally, thousands of integrations are available
through [Zapier](https://zapier.com/apps) and [IFTTT](https://ifttt.com/search).
You can also [connect any webhook designed to work with
Slack](/integrations/doc/slack_incoming) to Zulip.
Slack](/integrations/slack_incoming) to Zulip.
If you don't find an integration you need, you can:
@@ -47,8 +47,8 @@ additional integrations through [Zapier](https://zapier.com/apps) and
<Steps>
1. Search [Zapier](https://zapier.com/apps) or [IFTTT](https://ifttt.com/search)
for the product you'd like to connect to Zulip.
1. Follow the integration instructions for [Zapier](/integrations/doc/zapier) or
[IFTTT](/integrations/doc/ifttt).
1. Follow the integration instructions for [Zapier](/integrations/zapier) or
[IFTTT](/integrations/ifttt).
</Steps>
### Integrate via Slack-compatible webhook API

View File

@@ -9,7 +9,7 @@ dedicated guide to get started.
* [Moving from **Slack**](/help/moving-from-slack). You can [import your Slack
workspace](/help/import-from-slack). Zulip's [Slack-compatible incoming
webhook](https://zulip.com/integrations/doc/slack_incoming) also makes it easy
webhook](https://zulip.com/integrations/slack_incoming) also makes it easy
to migrate any integrations.
* [Moving from **Discord**](/help/moving-from-discord).
* [Moving from **Microsoft Teams**](/help/moving-from-teams).

View File

@@ -89,7 +89,7 @@ made the decision to move to Zulip.
conversation its own space, so one channel per team should be enough to get
you started.
1. Move your integrations using Zulip's [Slack-compatible incoming
webhook](/integrations/doc/slack_incoming). You can transition to
webhook](/integrations/slack_incoming). You can transition to
Zulip-native [integrations](/integrations) over time.
</FlattenedSteps>
@@ -137,7 +137,7 @@ team.
## Related articles
* [Import from Slack](/help/import-from-slack)
* [Slack-compatible incoming webhook](/integrations/doc/slack_incoming)
* [Slack-compatible incoming webhook](/integrations/slack_incoming)
* [Trying out Zulip](/help/trying-out-zulip)
* [Zulip Cloud or self-hosting?](/help/zulip-cloud-or-self-hosting)
* [Moving to Zulip](/help/moving-to-zulip)

View File

@@ -5,7 +5,7 @@ title: Request an integration
Zulip comes with over 100 native integrations. Hundreds more are
available through
[Zapier](https://zapier.com/home), [IFTTT](https://ifttt.com/), and
the [Slack compatible webhook](/integrations/doc/slack_incoming).
the [Slack compatible webhook](/integrations/slack_incoming).
However, sometimes there is no integration for a tool you use, or an
existing integration doesn't do what you need. If that's the case for

View File

@@ -290,10 +290,10 @@ user groups:
## Set up integrations
Zulip integrates directly with dozens of products, and with hundreds
more through [Zapier](/integrations/doc/zapier) and
[IFTTT](/integrations/doc/ifttt). Popular Zulip integrations include
[GitHub](/integrations/doc/github) and
[Twitter](/integrations/doc/twitter). The [integrations
more through [Zapier](/integrations/zapier) and
[IFTTT](/integrations/ifttt). Popular Zulip integrations include
[GitHub](/integrations/github) and
[Twitter](/integrations/twitter). The [integrations
page](/integrations/) has instructions for integrating with each
product.

View File

@@ -92,7 +92,7 @@ you can unlink it.
## Related articles
* [Configure call provider](/help/configure-call-provider)
* [Jitsi Meet integration](/integrations/doc/jitsi)
* [Zoom integration](/integrations/doc/zoom)
* [BigBlueButton integration](/integrations/doc/big-blue-button)
* [Jitsi Meet integration](/integrations/jitsi)
* [Zoom integration](/integrations/zoom)
* [BigBlueButton integration](/integrations/big-blue-button)
* [Insert a link](/help/insert-a-link)

View File

@@ -85,7 +85,7 @@ every message is important.
the Immersive & Geospatial division, joined End Point the day before the move to
Zulip. Zulip has always been a core tool for his work at End Point, and he has
built his workflows on Zulips [integrations](/integrations/). “With the
[Jenkins CI integration](/integrations/doc/jenkins), I can see when a job has
[Jenkins CI integration](/integrations/jenkins), I can see when a job has
finished building and is ready to deploy,” Alejandro says. “I use this 100s of
times per week.”

View File

@@ -50,7 +50,7 @@ prior conversations.”
Chat integrations for operational systems and alerts are a crucial part of the
workflow at iDrift AS. Zulip offers a [Slack-compatible
interface](/integrations/doc/slack_incoming), so many integrations could be
interface](/integrations/slack_incoming), so many integrations could be
simply moved over. “For a handful of integrations where Zulip didnt meet our
needs, it was easy to [create our own
integration](/api/integrations-overview#write-your-own-integration) or improve

View File

@@ -566,8 +566,8 @@
</tr>
<tr>
<td class="comparison-table-feature">
1000s of integrations though <a href="/integrations/doc/zapier">Zapier</a> and
<a href="/integrations/doc/ifttt">IFTTT</a>
1000s of integrations though <a href="/integrations/zapier">Zapier</a> and
<a href="/integrations/ifttt">IFTTT</a>
</td>
<td class="comparison-value-positive cloud-cell"><i class="icon icon-check"></i></td>
<td class="comparison-value-positive cloud-cell"><i class="icon icon-check"></i></td>

View File

@@ -266,7 +266,7 @@
using <a href="https://zapier.com/apps/zulip/integrations">Zapier</a>.
Integrations written for Slack can post
into Zulip via
the <a href="https://zulip.com/integrations/doc/slack_incoming">Slack
the <a href="https://zulip.com/integrations/slack_incoming">Slack
compatible webhook</a>.
</div>
</li>

View File

@@ -304,9 +304,9 @@
<li>
<div class="list-content">
Zulip supports mirroring channels with
<a href="/integrations/doc/irc">IRC</a>,
<a href="/integrations/doc/slack">Slack</a>, and
<a href="/integrations/doc/matrix">Matrix</a>, and
<a href="/integrations/irc">IRC</a>,
<a href="/integrations/slack">Slack</a>, and
<a href="/integrations/matrix">Matrix</a>, and
you can connect to other modern chat protocols using
<a href="https://github.com/42wim/matterbridge">Matterbridge</a>.
</div>
@@ -505,7 +505,7 @@
using <a href="https://zapier.com/apps/zulip/integrations">Zapier</a>.
Integrations written for Slack can post
into Zulip via
the <a href="/integrations/doc/slack_incoming">Slack
the <a href="/integrations/slack_incoming">Slack
compatible webhook</a>.
</div>
</li>

View File

@@ -148,7 +148,7 @@
<a href="https://zulip.readthedocs.io/en/stable/production/upgrade.html">upgrade</a>
your self-hosted Zulip installation. Migrate your
<a href="/help/migrating-from-other-chat-tools">data</a>
and <a href="/integrations/doc/slack_incoming">integrations</a>
and <a href="/integrations/slack_incoming">integrations</a>
from other chat tools for a smooth transition.
</p>
<p>

View File

@@ -44,6 +44,6 @@ as your call provider instead.
### Related documentation
- [How to start a call](/help/start-a-call)
- [Jitsi Meet integration](/integrations/doc/jitsi)
- [Zoom integration](/integrations/doc/zoom)
- [Jitsi Meet integration](/integrations/jitsi)
- [Zoom integration](/integrations/zoom)
* [BigBlueButton server configuration](https://docs.bigbluebutton.org/administration/customize/#other-configuration-changes)

View File

@@ -26,9 +26,9 @@
<h2 class="portico-page-subheading">
{% trans %}
And hundreds more through
<a href="/integrations/doc/zapier">Zapier</a>
<a href="/integrations/zapier">Zapier</a>
and
<a href="/integrations/doc/ifttt">IFTTT</a>.
<a href="/integrations/ifttt">IFTTT</a>.
{% endtrans %}
</h2>
</div>
@@ -56,7 +56,7 @@
<h4 class="integration-category {% if selected_category_slug == 'all' %}selected{% endif %}" data-category="all">All</h4>
</a>
{% for category in categories_dict.keys() %}
<a href="/integrations/{{ category }}">
<a href="/integrations/category/{{ category }}">
<h4 class="integration-category {% if selected_category_slug == category %}selected{% endif %}" data-category="{{ category }}">
{{ categories_dict[category] }}
</h4>
@@ -82,7 +82,7 @@
<h4 data-category="all" class="integration-category {% if selected_category_slug == 'all' %}selected{% endif %}">{% trans %}All{% endtrans %}</h4>
</a>
{% for category in categories_dict.keys() %}
<a href="/integrations/{{ category }}">
<a href="/integrations/category/{{ category }}">
<h4 data-category="{{ category }}" class="integration-category {% if selected_category_slug == category %}selected{% endif %}">
{{ categories_dict[category] }}
</h4>
@@ -103,7 +103,7 @@
<div class="integration-lozenges">
{% for integration in visible_integrations %}
<a href="/integrations/doc/{{ integration.name }}{% if selected_category_slug != 'all' %}?category={{ selected_category_slug }}{% endif %}">
<a href="/integrations/{{ integration.name }}{% if selected_category_slug != 'all' %}?category={{ selected_category_slug }}{% endif %}">
{{ integration_macros.render_integration_lozenge(integration) }}
</a>
{% endfor %}

View File

@@ -22,7 +22,7 @@
{% if integration_categories %}
<div class="categories">
{% for slug, display_name in integration_categories %}
<a href="/integrations/{{ slug }}">
<a href="/integrations/category/{{ slug }}">
<h3 class="integration-category" data-category="{{ slug }}">
{{ display_name }}
</h3>
@@ -31,7 +31,7 @@
</div>
{% endif %}
{{ integration_macros.render_integration_lozenge(selected_integration, is_doc_view=true) }}
<a href="/integrations/{% if return_category_slug != 'all' %}{{ return_category_slug }}{% endif %}" id="integration-list-link" class="no-underline">
<a href="/integrations/{% if return_category_slug != 'all' %}category/{{ return_category_slug }}{% endif %}" id="integration-list-link" class="no-underline">
<i class="fa fa-arrow-circle-left" aria-hidden="true"></i><span class="integrations-back-to-list-label">Back to list</span>
</a>
</div>

View File

@@ -5,7 +5,7 @@ It's easy to send Zulip messages from GitHub Actions! This is useful:
Instructions are available [here](https://github.com/zulip/github-actions-zulip#readme).
See also the [GitHub integration](/integrations/doc/github).
See also the [GitHub integration](/integrations/github).
{!congrats.md!}

View File

@@ -51,14 +51,14 @@ result like this:
* [GitHub repository for Zulip Hubot adapter][hubot-zulip]
* Zulip Integrations using Hubot: [Assembla](/integrations/doc/assembla) |
[Bonusly](/integrations/doc/bonusly) |
[Chartbeat](/integrations/doc/chartbeat) |
[Dark Sky](/integrations/doc/darksky) |
[Instagram](/integrations/doc/instagram) |
[Google Translate](/integrations/doc/google-translate) |
[MailChimp](/integrations/doc/mailchimp) |
[YouTube](/integrations/doc/youtube)
* Zulip Integrations using Hubot: [Assembla](/integrations/assembla) |
[Bonusly](/integrations/bonusly) |
[Chartbeat](/integrations/chartbeat) |
[Dark Sky](/integrations/darksky) |
[Instagram](/integrations/instagram) |
[Google Translate](/integrations/google-translate) |
[MailChimp](/integrations/mailchimp) |
[YouTube](/integrations/youtube)
* [Other Hubot adapters][other-adapters]

View File

@@ -30,5 +30,5 @@ instance of Jitsi Meet.
## Related documentation
- [How to start a call](/help/start-a-call)
- [Zoom integration](/integrations/doc/zoom)
- [BigBlueButton integration](/integrations/doc/big-blue-button)
- [Zoom integration](/integrations/zoom)
- [BigBlueButton integration](/integrations/big-blue-button)

View File

@@ -37,5 +37,5 @@ in order to use this integration.
## Related documentation
- [How to start a call](/help/start-a-call)
- [Jitsi Meet integration](/integrations/doc/jitsi)
- [BigBlueButton integration](/integrations/doc/big-blue-button)
- [Jitsi Meet integration](/integrations/jitsi)
- [BigBlueButton integration](/integrations/big-blue-button)

View File

@@ -107,7 +107,11 @@ function integration_events(): void {
// init
$(() => {
const is_doc_view = window.location.pathname.startsWith("/integrations/doc/");
const path = window.location.pathname;
const is_doc_view =
path !== "/integrations/" &&
!path.startsWith("/integrations/category/") &&
path.startsWith("/integrations/");
if (!is_doc_view) {
integration_events();

View File

@@ -28,3 +28,34 @@ LANDING_PAGE_REDIRECTS = [
]
DOCUMENTATION_REDIRECTS = API_DOCUMENTATION_REDIRECTS + POLICY_DOCUMENTATION_REDIRECTS
# List of category slugs at the time of changing the URL scheme to have
# `/category` be appended before the category slug. This list does not
# need to change with changing categories.
INTEGRATION_CATEGORY_SLUGS = [
"bots",
"communication",
"continuous-integration",
"customer-support",
"deployment",
"entertainment",
"financial",
"hr",
"marketing",
"meta-integration",
"misc",
"monitoring",
"productivity",
"project-management",
"version-control",
]
def get_integration_category_redirects() -> list[URLRedirect]:
return [
URLRedirect(
f"/integrations/{slug}",
f"/integrations/category/{slug}",
)
for slug in INTEGRATION_CATEGORY_SLUGS
]

View File

@@ -25546,7 +25546,7 @@ paths:
summary: Create BigBlueButton video call
description: |
Create a video call URL for a BigBlueButton video call.
Requires [BigBlueButton 2.4+](/integrations/doc/big-blue-button)
Requires [BigBlueButton 2.4+](/integrations/big-blue-button)
to be configured on the Zulip server.
The acting user will be given the moderator role on the call.

View File

@@ -16,6 +16,7 @@ from zerver.context_processors import get_apps_page_url
from zerver.lib.integrations import CATEGORIES, INTEGRATIONS, META_CATEGORY
from zerver.lib.test_classes import ZulipTestCase
from zerver.lib.test_helpers import HostRequestMock
from zerver.lib.url_redirects import INTEGRATION_CATEGORY_SLUGS
from zerver.models import Realm
from zerver.models.realms import get_realm
from zerver.views.documentation import add_api_url_context
@@ -136,8 +137,8 @@ class DocPageTest(ZulipTestCase):
"/errors/404/",
"/errors/5xx/",
"/integrations/",
"/integrations/bots",
"/integrations/doc/github",
"/integrations/category/bots",
"/integrations/github",
"/team/",
]
@@ -391,47 +392,66 @@ class DocPageTest(ZulipTestCase):
images_in_docs.add(image)
result = self.client_get(
"/integrations/nonexistent_category",
"/integrations/category/nonexistent_category",
follow=True,
)
self.assertEqual(result.status_code, 404)
for category_name in INTEGRATION_CATEGORY_SLUGS:
legacy_category_response = self.client_get(
f"/integrations/{category_name}",
follow=False,
)
self.assertEqual(legacy_category_response.status_code, 301)
self.assertEqual(
legacy_category_response["Location"], f"/integrations/category/{category_name}"
)
legacy_doc_response = self.client_get(
"/integrations/doc/asana?category=project-management",
follow=False,
)
self.assertEqual(legacy_doc_response.status_code, 301)
self.assertEqual(
legacy_doc_response["Location"], "/integrations/asana?category=project-management"
)
result = self.client_get(
"/integrations/doc/nonexistent_integration",
"/integrations/nonexistent_integration",
follow=True,
)
self.assertEqual(result.status_code, 404)
result = self._test(
"/integrations/doc/asana?category=project-management",
"/integrations/asana?category=project-management",
expected_strings=[
'<a href="/integrations/project-management" id="integration-list-link" class="no-underline">'
'<a href="/integrations/category/project-management" id="integration-list-link" class="no-underline">'
],
)
result = self.client_get(
"/integrations/doc/asana?category=nonexistent_category",
"/integrations/asana?category=nonexistent_category",
)
self.assert_not_in_success_response(
[
'<a href="/integrations/project-management" id="integration-list-link" class="no-underline">'
'<a href="/integrations/category/project-management" id="integration-list-link" class="no-underline">'
],
response,
)
# Mis-matched category should also return back to all.
result = self.client_get(
"/integrations/doc/asana?category=communication",
"/integrations/asana?category=communication",
)
self.assert_not_in_success_response(
[
'<a href="/integrations/project-management" id="integration-list-link" class="no-underline">'
'<a href="/integrations/category/project-management" id="integration-list-link" class="no-underline">'
],
response,
)
for integration in INTEGRATIONS:
url = f"/integrations/doc/{integration}"
url = f"/integrations/{integration}"
response = self._test(url, expected_strings=[])
doc = response.content.decode("utf-8")
for image in re.findall(r"/static/images/integrations/(.*)\"", doc):
@@ -475,14 +495,14 @@ class DocPageTest(ZulipTestCase):
og_description = '<meta property="og:description" content="Zulip comes with over'
# Test a particular integration page
url = "/integrations/doc/github"
url = "/integrations/github"
title = '<meta property="og:title" content="GitHub | Zulip integrations" />'
description = '<meta property="og:description" content="Zulip comes with over'
self._test(url, [title, description, get_canonical_url(url)])
# Test category pages
for category in CATEGORIES:
url = f"/integrations/{category}"
url = f"/integrations/category/{category}"
if category in META_CATEGORY:
title = f"<title>{CATEGORIES[category]} | Zulip integrations</title>"
og_title = f'<meta property="og:title" content="{CATEGORIES[category]} | Zulip integrations" />'
@@ -500,19 +520,19 @@ class DocPageTest(ZulipTestCase):
# We don't need to test all the pages for 404
for integration in list(INTEGRATIONS.keys())[5]:
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
url = f"/en/integrations/doc/{integration}"
url = f"/en/integrations/{integration}"
result = self.client_get(url, subdomain="", follow=True)
self.assertEqual(result.status_code, 404)
result = self.client_get(url, subdomain="zephyr", follow=True)
self.assertEqual(result.status_code, 404)
url = f"/en/integrations/doc/{integration}"
url = f"/en/integrations/{integration}"
result = self.client_get(url, subdomain="", follow=True)
self.assertEqual(result.status_code, 404)
result = self.client_get(url, subdomain="zephyr", follow=True)
self.assertEqual(result.status_code, 404)
result = self.client_get("/integrations/doc/nonexistent_integration", follow=True)
result = self.client_get("/integrations/nonexistent_integration", follow=True)
self.assertEqual(result.status_code, 404)
def test_electron_detection(self) -> None:

View File

@@ -4,7 +4,7 @@ See your Thinkst Canarytoken alerts in Zulip!
This integration works with Canarytokens from
[canarytokens.org][canarytokens], not Thinkst's paid product. See the
[Zulip Thinkst integration](/integrations/doc/thinkst) for those!
[Zulip Thinkst integration](/integrations/thinkst) for those!
{start_tabs}

View File

@@ -30,7 +30,7 @@ Get GitHub notifications in Zulip!
- [GitHub's webhook events documentation][github-webhook-events]
- [Zulip GitHub Actions integration](/integrations/doc/github-actions)
- [Zulip GitHub Actions integration](/integrations/github-actions)
{!webhooks-url-specification.md!}

View File

@@ -27,7 +27,7 @@ Get GitHub Sponsors notifications in Zulip!
- [GitHub's webhook events documentation][github-webhook-events]
- [Zulip GitHub integration](/integrations/doc/github).
- [Zulip GitHub integration](/integrations/github).
{!webhooks-url-specification.md!}

View File

@@ -345,7 +345,7 @@ class NewRelicHookTests(WebhookTestCase):
expected_message = """
:danger: A New Relic [incident](https://one.newrelic.com/alerts-ai) updated
**Warning**: Unable to use the default notification format because at least one expected field was missing from the incident payload. See [New Relic integration documentation](/integrations/doc/newrelic).
**Warning**: Unable to use the default notification format because at least one expected field was missing from the incident payload. See [New Relic integration documentation](/integrations/newrelic).
**Missing fields**: `issueUrl`, `title`, `priority`, `totalIncidents`, `state`, `createdAt`, `updatedAt`, `alertPolicyNames`, `alertConditionNames`
""".strip()

View File

@@ -22,7 +22,7 @@ from zerver.models import UserProfile
MISSING_FIELDS_NOTIFICATION = """
:danger: A New Relic [incident]({url}) updated
**Warning**: Unable to use the default notification format because at least one expected field was missing from the incident payload. See [New Relic integration documentation](/integrations/doc/newrelic).
**Warning**: Unable to use the default notification format because at least one expected field was missing from the incident payload. See [New Relic integration documentation](/integrations/newrelic).
**Missing fields**: {formatted_missing_fields}
"""

View File

@@ -112,7 +112,7 @@ If you are looking to quickly move your Slack integrations to Zulip, check out
{!webhooks-url-specification.md!}
[1]: /integrations/doc/slack_incoming
[1]: /integrations/slack_incoming
[2]: /help/create-a-channel
[3]: https://api.slack.com/apis/events-api
[4]: https://api.slack.com/apps

View File

@@ -27,7 +27,7 @@ integrations when migrating your organization from Slack to Zulip.
- [Moving from Slack to Zulip](/help/moving-from-slack)
- [Forward Slack messages into Zulip](/integrations/doc/slack)
- [Forward Slack messages into Zulip](/integrations/slack)
- [Forward messages Slack <-> Zulip][2] (both directions)

View File

@@ -4,7 +4,7 @@ Get your Thinkst Canary and Canarytoken alerts in Zulip!
This integration works with Canarytokens from Thinkst's paid product.
For [canarytokens.org][canarytokens], see the
[Canarytokens](/integrations/doc/canarytoken) integration!
[Canarytokens](/integrations/canarytoken) integration!
{start_tabs}

View File

@@ -17,7 +17,7 @@ from django.views.generic import RedirectView
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.lib.url_redirects import DOCUMENTATION_REDIRECTS, get_integration_category_redirects
from zerver.tornado.views import (
cleanup_event_queue,
get_events,
@@ -279,6 +279,14 @@ if settings.TWO_FACTOR_AUTHENTICATION_ENABLED: # nocoverage
from two_factor.gateways.twilio.urls import urlpatterns as tf_twilio_urls
from two_factor.urls import urlpatterns as tf_urls
INTEGRATION_CATEGORY_REDIRECT_PATHS = [
path(
redirect.old_url.lstrip("/"),
RedirectView.as_view(url=redirect.new_url, permanent=True, query_string=True),
)
for redirect in get_integration_category_redirects()
]
# NB: There are several other pieces of code which route requests by URL:
#
# - runtornado.py has its own URL list for Tornado views. See the
@@ -717,9 +725,27 @@ i18n_urls = [
# Used to join a BigBlueButton video call
path("calls/bigbluebutton/join", join_bigbluebutton),
# Integrations documentation
path("integrations/doc/<str:integration_name>", integrations_doc),
path("integrations/", integrations_catalog, {"category_slug": "all"}),
path("integrations/<str:category_slug>", integrations_catalog),
path(
"integrations/",
integrations_catalog,
{"category_slug": "all"},
name="integrations_home",
),
path(
"integrations/category/<str:category_slug>",
integrations_catalog,
name="integrations_category",
),
*INTEGRATION_CATEGORY_REDIRECT_PATHS,
path(
"integrations/doc/<str:integration_name>",
RedirectView.as_view(pattern_name="integration_doc", permanent=True, query_string=True),
),
path(
"integrations/<str:integration_name>",
integrations_doc,
name="integration_doc",
),
]
# Make a copy of i18n_urls so that they appear without prefix for english