The download URL for a realm export tarball previously contained
only a random suffix, making it easy to download the wrong file
when multiple exports were available in the admin UI -- or when
an admin manages exports across multiple organizations.
Embed both the realm's string_id (when non-empty) and the UTC
timestamp of the export in the tempdir prefix, producing tarballs
named like zulip-export-<string_id>-2026-05-25-09-30-45-<rand>.tar.gz
(or zulip-export-2026-05-25-09-30-45-<rand>.tar.gz for the root
realm, whose string_id is empty). The timestamp format matches
the convention used by `./manage.py backup`; the random suffix is
retained to disambiguate same-second exports.
The prefix is built by a new `export_tarball_prefix()` helper in
`zerver/lib/export.py`, shared by the `export` and
`export_single_user` management commands and the deferred-work
queue worker that handles admin-UI export requests.
Fixes https://chat.zulip.org/#narrow/channel/9-issues/topic/discrepancies.20in.20data.20export/with/2467409
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Most of what makes a Zulip migration tricky to write follows from
how Zulip Cloud deploys: staging and production share a database,
staging deploys first and runs the migration against the shared
DB, production deploys some time later, and Django processes
restart in a rolling fashion. Together these mean migrations must
be safe for the previous release's code to keep running against,
and that staging-time problems are also live production problems.
The previous version of this page didn't describe any of that,
and as a result didn't motivate most of the rules contributors
need to follow. Rework the page around the deploy model so each
rule traces back to a property of how migrations actually run on
Cloud.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously, the `require_e2ee_push_notifications` setting would
send legacy push notifications with redacted content.
Now, legacy push notifications are skipped entirely when this
setting is enabled, so only clients supporting E2EE will receive
push notifications.
Signed-off-by: Prakhar Pratyush <prakhar@zulip.com>
The 2024 left-sidebar rename (commit 1594011b67) replaced "All
messages" with "Combined feed" in this glossary entry's English
half but left the Polish translation as "wszystkie wiadomości"
(literally "all messages"). The actual Polish translation in
locale/pl/translations.json is "Strumień mieszany"; update the
glossary entry and example to match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switch the topic summarization integration from the litellm wrapper
library to the OpenAI Python SDK directly. The SDK can be pointed at
any OpenAI-compatible endpoint via a new TOPIC_SUMMARIZATION_API_BASE
setting, so provider/model strings like "groq/llama-3.3-70b-versatile"
become a plain model name plus a base URL.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Anders Kaseorg <anders@zulip.com>
Fedora 44 ships Postgres 17 in PGDG and shares Fedora 43's package
list, so support is just a matter of accepting the new version in
the provision check.
The Docker subproject references specific sections of these pages —
the Backups model, the WAL-g archiving setup, and the S3 backend —
from several places, but without explicit anchors those references
land at page top.
Most pages under docs/production/ describe Zulip's standard install
in terms of files (`/etc/zulip/settings.py`,
`/etc/zulip/zulip.conf`), commands (`zulip-puppet-apply`,
`supervisorctl`, `/home/zulip/deployments/current/manage.py …`),
and Puppet-managed services. None of those are how a Docker
deployment is configured: settings come from environment variables
on the container, secrets from Docker secrets, certificates from
`CERTIFICATES`, and so on. The Docker docs already cross-reference
these pages from the other side, but the standard-install pages had
no pointer back, so a Docker user looking up how to configure
something would land on instructions that don't apply.
Use the same `important` admonition shape on every affected page
or section, so the divergence pattern is recognizable as readers
move between pages.
The Backups section currently presents `manage.py backup` as the
single tool to use, with no awareness that Docker deployments use
a different unit of backup. A Docker user following the existing
text would produce a tarball that omits certificates, post-setup
scripts, and the configuration mirror under `/data/etc-zulip/` —
state that lives in the `/data` volume but not in the standard
backup tarball.
Add an admonition redirecting Docker readers to the volume-snapshot
recipes, and a paragraph describing the Docker inclusion list. The
admonition redirects rather than warns off: `manage.py backup`
remains the right tool for migrating between Docker and a standard
installation in either direction, capturing whichever side is the
source of the migration.
The official Docker image's documentation is published as a Read the
Docs subproject and is searchable from the parent project, but it
has no entry in the main docs sidebar — so a user navigating
zulip.readthedocs.io has no path to discover it short of a search
query.
Add a thin shim page in the production toctree, and redirect
existing in-prose `docker:index` references to it so the sidebar
entry becomes the canonical Docker navigation anchor.
Zulip production suite / ${{ matrix.name }} (zulip/ci:bookworm, --test-custom-db, Debian 12 production install with custom db name and user, bookworm) (push) Has been cancelled
Zulip production suite / ${{ matrix.name }} (zulip/ci:jammy, , Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga, jammy) (push) Has been cancelled
The production suite CI job covers the risks that manual testing of
this form might catch well, and as far as I know, we last did this
class of additional extensive manual testing for a release years ago.
(We do such manual testing when authoring/merging a change to the
installer experience, but not at release time).
Closes#35196.
In #34850 we implemented this for the ldap authentication codepath.
This PR makes it support also during the sync_ldap_user_data job.
What this means practically is that if this functionality is enabled and
correctly configured, sync_ldap_user_data is able to find the associated
user in the ldap directory even if the email value in the directory has
changed. The UserProfile's delivery_email will be updated to sync this
change, in addition to the regular syncing for other attributes.
Email changes used to break the association between UserProfile and the
ldap user entry.
The primary challenge making this implementation fairly complex is the
fact that django-auth-ldap is designed with authentication in mind, so
it doesn't make arbitrary LDAP searches easy - and the regular direction
is:
user ldap credentials -> LDAP user data -> Django user object.
However, the sync job searches in the opposite direction. We begin with
a Django UserProfile - we need to find the ExternalAuthID entry (if it
exists), and then based on the configuration of this feature, do an
appropriate LDAP search to find the LDAP user entry with the matching
value in the attribute configured as the `unique_account_id`.
The README badge, post-install "follow us" link, release-
checklist announcement step, and support-Zulip help page all
linked to twitter.com/zulip or x.com/zulip. Point them at
bsky.app/profile/zulip.bsky.social, since that is where Zulip
now posts updates.
Customer testimonials in templates/corporate/for/ that quote
dated tweets are intentionally left alone, as their text uses
Twitter @-mention syntax and the link sources the quote.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fedora 38 reached end of life upstream; replace it with Fedora 43,
which ships dnf5 and a recent enough groonga to skip the source
build. Concretely, to make `tools/provision` run cleanly on
Fedora 43:
* dnf5 (Fedora 41+) dropped the `groupinstall` alias and no longer
resolves the "Development Tools" display name, so switch the
Fedora branch of `setup-yum-repo` to
`dnf group install development-tools` (by group ID). Move the
existing CentOS/RHEL `groupinstall` calls into their own branches
so they keep working on yum/dnf4.
* Map Fedora 43 to PostgreSQL 17, and add `groonga-devel`,
`xxhash-devel`, `meson`, and `redhat-rpm-config` to the Fedora
package list. PGroonga 4.0.6 switched its build system to meson;
on Fedora, PostgreSQL's `pg_config` exports CFLAGS containing
`-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1` and
`-specs=.../redhat-annobin-cc1`, and without `redhat-rpm-config`
the PGroonga build fails with "cannot read spec file".
`xxhash-devel` is required because `xxhash-libs` is often pulled
in transitively (by blosc2, pyarrow, etc.) without its headers,
in which case meson detects libxxhash via pkg-config and skips
the vendored fallback that would otherwise build it from source.
* Use the packaged groonga from Fedora's main repo (15.0.4 on
Fedora 43, satisfying PGroonga 4.0.6's >= 14.1.0 requirement)
instead of compiling groonga from source. This removes the only
remaining caller of `scripts/lib/build-groonga` and the
BUILD_GROONGA_FROM_SOURCE plumbing in provision.py, which the
prior Fedora 38 path was the only user of.
Verified end-to-end on a Fedora 43 host and in a fresh fedora:43
podman container: setup-yum-repo, the package install, and the
PGroonga source build against the system groonga all complete
cleanly.
4c3aa4c007 migrated the GET
/users/{user_id_or_email}/presence endpoint to return only the modern
format (active_timestamp and idle_timestamp). The assumption that the
endpoint had no significant consumers turned out to be wrong: the
Zulip web app itself was a consumer (in user_card_popover, where it
caused a "Failed to parse presence API response" error for any
currently active user), and there are likely third-party integrations
relying on the legacy format as well.
Restore the legacy website and aggregated dictionaries alongside the
new modern fields, so existing clients keep working. Clients should
migrate to the modern fields, which is now phrased as a recommendation
rather than a breaking change in the API and self-hosted upgrade
notes.
Additionally, add a top-level server_timestamp field to the response,
matching the behavior of other presence endpoints. This lets clients
compute presence-status age against the server's clock rather than
guessing with the local clock.
Refactor the view to query UserPresence once and format both the
modern and legacy presence dicts from the same row, rather than
issuing two queries that fetch the same data.
Relatively simple change, adding full_name support to our upon-login
user data sync mechanism.
Addresses the user problem noted in
https://github.com/zulip/zulip/issues/38583#issuecomment-4138042890Fixes#34071 partially, which was about OIDC specifically.
This commit adds the necessary underlying mechanism, but it remains only
available via SAML for now. We still have to enable
`SOCIAL_AUTH_SYNC_ATTRS_DICT` support for the OIDC backend.
The web app doesn't use state["streams"] from /register — it relies
on "subscription" data instead (see comment in
zerver/lib/events.py). On initial page load, home.py already skips
this via include_streams=False.
Use the existing fetch_event_types parameter to achieve the same
optimization for client-triggered reloads, avoiding a redundant
do_get_streams() call.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the recently added 'hashtag-thin.svg' icon in the folder popover
View channels menu item with the existing 'zulip-icon-hash'. The hash
icon is already used in the gear menu for channel settings.
Remove 'hashtag-thin.svg' and its THIRDPARTY entry, as it is no longer
needed.
And convert its type from `Callable` to `str`.
It's type was previously set to a string in the frontend, and validator
functions in the backend, which were never called.