mirror of https://github.com/zulip/zulip.git
docs: Rewrap to avoid line breaks in inline code spans.
This works around https://github.com/prettier/prettier/issues/11372. Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
a6e01b35fc
commit
6145fdf678
|
@ -168,8 +168,8 @@ cause time-related bugs that are hard to catch with a test suite, or bugs
|
|||
that only show up during daylight savings time.
|
||||
|
||||
Good ways to make timezone-aware datetimes are below. We import timezone
|
||||
libraries as `from datetime import datetime, timezone` and `from
|
||||
django.utils.timezone import now as timezone_now`.
|
||||
libraries as `from datetime import datetime, timezone` and
|
||||
`from django.utils.timezone import now as timezone_now`.
|
||||
|
||||
Use:
|
||||
* `timezone_now()` to get a datetime when Django is available, such as
|
||||
|
@ -241,10 +241,8 @@ generally use modern
|
|||
[ECMAScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Language_Resources)
|
||||
primitives such as [`for … of`
|
||||
loops](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of),
|
||||
[`Array.prototype.{entries, every, filter, find, indexOf, map,
|
||||
some}`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array),
|
||||
[`Object.{assign, entries, keys,
|
||||
values}`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object),
|
||||
[`Array.prototype.{entries, every, filter, find, indexOf, map, some}`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array),
|
||||
[`Object.{assign, entries, keys, values}`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object),
|
||||
[spread
|
||||
syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax),
|
||||
and so on. Our Babel configuration automatically transpiles and
|
||||
|
@ -266,8 +264,8 @@ code a lot uglier, in which case it's fine to go up to 120 or so.
|
|||
|
||||
Our JavaScript and TypeScript code is formatted with
|
||||
[Prettier](https://prettier.io/). You can ask Prettier to reformat
|
||||
all code via our [linter tool](../testing/linters.md) with `tools/lint
|
||||
--only=prettier --fix`. You can also [integrate it with your
|
||||
all code via our [linter tool](../testing/linters.md) with
|
||||
`tools/lint --only=prettier --fix`. You can also [integrate it with your
|
||||
editor](https://prettier.io/docs/en/editors.html).
|
||||
|
||||
Combine adjacent on-ready functions, if they are logically related.
|
||||
|
@ -328,8 +326,9 @@ type changes in the future.
|
|||
[Black](https://github.com/psf/black) and
|
||||
[isort](https://pycqa.github.io/isort/). The [linter
|
||||
tool](../testing/linters.md) enforces this by running Black and
|
||||
isort in check mode, or in write mode with `tools/lint
|
||||
--only=black,isort --fix`. You may find it helpful to [integrate
|
||||
isort in check mode, or in write mode with
|
||||
`tools/lint --only=black,isort --fix`. You may find it helpful to
|
||||
[integrate
|
||||
Black](https://black.readthedocs.io/en/stable/editor_integration.html)
|
||||
and
|
||||
[isort](https://pycqa.github.io/isort/#installing-isorts-for-your-preferred-text-editor)
|
||||
|
|
|
@ -36,11 +36,12 @@ details worth understanding:
|
|||
which shows all emails that the Zulip server has "sent" (emails are
|
||||
not actually sent by the development environment), to make it
|
||||
convenient to click through the UI of signup, password reset, etc.
|
||||
* There's a management command, `manage.py print_initial_password
|
||||
username@example.com`, that prints out **default** passwords for the
|
||||
development environment users. Note that if you change a user's
|
||||
password in the development environment, those passwords will no longer
|
||||
work. It also prints out the user's **current** API key.
|
||||
* There's a management command,
|
||||
`manage.py print_initial_password username@example.com`, that prints
|
||||
out **default** passwords for the development environment users.
|
||||
Note that if you change a user's password in the development
|
||||
environment, those passwords will no longer work. It also prints
|
||||
out the user's **current** API key.
|
||||
|
||||
### Google
|
||||
|
||||
|
|
|
@ -37,14 +37,14 @@ to the next section.
|
|||
|
||||
You can create a new user with sudo privileges by running the
|
||||
following commands as root:
|
||||
* You can create a `zulipdev` user by running the command `adduser
|
||||
zulipdev`. Run through the prompts to assign a password and user
|
||||
information. (You can pick any username you like for this user
|
||||
* You can create a `zulipdev` user by running the command
|
||||
`adduser zulipdev`. Run through the prompts to assign a password and
|
||||
user information. (You can pick any username you like for this user
|
||||
account.)
|
||||
* You can add the user to the sudo group by running the command
|
||||
`usermod -aG sudo zulipdev`.
|
||||
* Finally, you can switch to the user by running the command `su -
|
||||
zulipdev` (or just log in to that user using `ssh`).
|
||||
* Finally, you can switch to the user by running the command
|
||||
`su - zulipdev` (or just log in to that user using `ssh`).
|
||||
|
||||
## Setting up the development environment
|
||||
|
||||
|
@ -311,9 +311,9 @@ different.
|
|||
service nginx reload # Actually enabled your nginx configuration
|
||||
```
|
||||
|
||||
1. Edit `zproject/dev_settings.py` to set `EXTERNAL_URI_SCHEME =
|
||||
"https://"`, so that URLs served by the development environment
|
||||
will be HTTPS.
|
||||
1. Edit `zproject/dev_settings.py` to set
|
||||
`EXTERNAL_URI_SCHEME = "https://"`, so that URLs served by the
|
||||
development environment will be HTTPS.
|
||||
|
||||
1. Start the Zulip development environment with the following command:
|
||||
```bash
|
||||
|
|
|
@ -251,10 +251,10 @@ expected.
|
|||
1. If you get the error `Hyper-V could not initialize memory`, this is
|
||||
likely because your system has insufficient free memory to start
|
||||
the virtual machine. You can generally work around this error by
|
||||
closing all other running programs and running `vagrant up
|
||||
--provider=hyperv` again. You can reopen the other programs after
|
||||
the provisioning is completed. If it still isn't enough, try
|
||||
restarting your system and running the command again.
|
||||
closing all other running programs and running
|
||||
`vagrant up --provider=hyperv` again. You can reopen the other
|
||||
programs after the provisioning is completed. If it still isn't
|
||||
enough, try restarting your system and running the command again.
|
||||
|
||||
2. Be patient the first time you run `./tools/run-dev.py`.
|
||||
|
||||
|
@ -295,13 +295,14 @@ you can sign up [here](https://aws.amazon.com/cloud9/).
|
|||
* Resize the workspace to be 1GB of memory and 4GB of disk
|
||||
space. (This is under free limit for both the old Cloud9 and the AWS
|
||||
Free Tier).
|
||||
* Clone the zulip repo: `git clone --config pull.rebase
|
||||
https://github.com/<your-username>/zulip.git`
|
||||
* Restart rabbitmq-server since its broken on Cloud9: `sudo service
|
||||
rabbitmq-server restart`.
|
||||
* Clone the zulip repo:
|
||||
`git clone --config pull.rebase https://github.com/<your-username>/zulip.git`
|
||||
* Restart rabbitmq-server since its broken on Cloud9:
|
||||
`sudo service rabbitmq-server restart`.
|
||||
* And run provision `cd zulip && ./tools/provision`, once this is done.
|
||||
* Activate the Zulip virtual environment by `source
|
||||
/srv/zulip-py3-venv/bin/activate` or by opening a new terminal.
|
||||
* Activate the Zulip virtual environment by
|
||||
`source /srv/zulip-py3-venv/bin/activate` or by opening a new
|
||||
terminal.
|
||||
|
||||
#### Install zulip-cloud9
|
||||
|
||||
|
|
|
@ -321,8 +321,9 @@ section. If that doesn't help, please visit
|
|||
in the [Zulip development community server](https://zulip.com/developer-community/) for
|
||||
real-time help.
|
||||
|
||||
On Windows, you will see the message `The system cannot find the path
|
||||
specified.` several times. This is normal and is not a problem.
|
||||
On Windows, you will see the message
|
||||
`The system cannot find the path specified.` several times. This is
|
||||
normal and is not a problem.
|
||||
|
||||
Once `vagrant up` has completed, connect to the development
|
||||
environment with `vagrant ssh`:
|
||||
|
@ -804,11 +805,11 @@ The `vagrant up` command basically does the following:
|
|||
|
||||
To debug such errors, you can log in to the Vagrant guest machine by
|
||||
running `vagrant ssh`, which should present you with a standard shell
|
||||
prompt. You can debug interactively by using e.g. `cd zulip &&
|
||||
./tools/provision`, and then running the individual subcommands
|
||||
that failed. Once you've resolved the problem, you can rerun
|
||||
`tools/provision` to proceed; the provisioning system is designed
|
||||
to recover well from failures.
|
||||
prompt. You can debug interactively by using e.g.
|
||||
`cd zulip && ./tools/provision`, and then running the individual
|
||||
subcommands that failed. Once you've resolved the problem, you can
|
||||
rerun `tools/provision` to proceed; the provisioning system is
|
||||
designed to recover well from failures.
|
||||
|
||||
The Zulip provisioning system is generally highly reliable; the most common
|
||||
cause of issues here is a poor network connection (or one where you need a
|
||||
|
@ -883,9 +884,10 @@ enabled in your BIOS.
|
|||
|
||||
If the error persists, you may have run into an incompatibility
|
||||
between VirtualBox and Hyper-V on Windows. To disable Hyper-V, open
|
||||
command prompt as administrator, run `bcdedit /set
|
||||
hypervisorlaunchtype off`, and reboot. If you need to enable it
|
||||
later, run `bcdedit /deletevalue hypervisorlaunchtype`, and reboot.
|
||||
command prompt as administrator, run
|
||||
`bcdedit /set hypervisorlaunchtype off`, and reboot. If you need to
|
||||
enable it later, run `bcdedit /deletevalue hypervisorlaunchtype`, and
|
||||
reboot.
|
||||
|
||||
#### OSError: [Errno 26] Text file busy
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@ the development environment][authentication-dev-server].
|
|||
## Common
|
||||
|
||||
* Zulip's `main` branch moves quickly, and you should rebase
|
||||
constantly with e.g. `git fetch upstream; git rebase
|
||||
upstream/main` to avoid developing on an old version of the Zulip
|
||||
codebase (leading to unnecessary merge conflicts).
|
||||
constantly with e.g.
|
||||
`git fetch upstream; git rebase upstream/main` to avoid developing
|
||||
on an old version of the Zulip codebase (leading to unnecessary
|
||||
merge conflicts).
|
||||
* Remember to run `tools/provision` to update your development
|
||||
environment after switching branches; it will run in under a second
|
||||
if no changes are required.
|
||||
|
@ -55,8 +56,8 @@ the development environment][authentication-dev-server].
|
|||
console output, which will show tracebacks for any 500 errors your
|
||||
Zulip development server encounters (which are probably caused by
|
||||
bugs in your code).
|
||||
* To manually query Zulip's database interactively, use `./manage.py
|
||||
shell` or `manage.py dbshell`.
|
||||
* To manually query Zulip's database interactively, use
|
||||
`./manage.py shell` or `manage.py dbshell`.
|
||||
* The database(s) used for the automated tests are independent from
|
||||
the one you use for manual testing in the UI, so changes you make to
|
||||
the database manually will never affect the automated tests.
|
||||
|
|
|
@ -141,20 +141,20 @@ base class `icon-vector` and have dropped support for it. We now only support
|
|||
icons from [FontAwesome](https://fontawesome.com/v4.7.0/) (version 4.7.0) which
|
||||
make use of `fa` as a base class.
|
||||
|
||||
* cog (<i class="fa fa-cog"></i>) icon — `cog (<i
|
||||
class="fa fa-cog"></i>) icon`
|
||||
* cog (<i class="fa fa-cog"></i>) icon —
|
||||
`cog (<i class="fa fa-cog"></i>) icon`
|
||||
* down chevron (<i class="fa fa-chevron-down"></i>) icon —
|
||||
`down chevron (<i class="fa fa-chevron-down"></i>) icon`
|
||||
* eye (<i class="fa fa-eye"></i>) icon — `eye (<i
|
||||
class="fa fa-eye"></i>) icon`
|
||||
* file (<i class="fa fa-file-code-o"></i>) icon — `file (<i
|
||||
class="fa fa-file-code-o"></i>) icon`
|
||||
* eye (<i class="fa fa-eye"></i>) icon —
|
||||
`eye (<i class="fa fa-eye"></i>) icon`
|
||||
* file (<i class="fa fa-file-code-o"></i>) icon —
|
||||
`file (<i class="fa fa-file-code-o"></i>) icon`
|
||||
* filled star (<i class="fa fa-star"></i>) icon —
|
||||
`filled star (<i class="fa fa-star"></i>) icon`
|
||||
* formatting (<i class="fa fa-font"></i>) icon —
|
||||
`formatting (<i class="fa fa-font"></i>) icon`
|
||||
* menu (<i class="fa fa-bars"></i>) icon — `menu (<i
|
||||
class="fa fa-bars"></i>) icon`
|
||||
* menu (<i class="fa fa-bars"></i>) icon —
|
||||
`menu (<i class="fa fa-bars"></i>) icon`
|
||||
* overflow ( <i class="fa fa-ellipsis-v"></i> ) icon —
|
||||
`overflow ( <i class="fa fa-ellipsis-v"></i> ) icon`
|
||||
* paperclip (<i class="fa fa-paperclip"></i>) icon —
|
||||
|
|
|
@ -32,12 +32,12 @@ Checking connectivity... done.
|
|||
```
|
||||
|
||||
(The `--config pull.rebase` option configures Git so that `git pull`
|
||||
will behave like `git pull --rebase` by default. Using `git pull
|
||||
--rebase` to update your changes to resolve merge conflicts is
|
||||
expected by essentially all of open source projects, including Zulip.
|
||||
You can also set that option after cloning using `git config --add
|
||||
pull.rebase true`, or just be careful to always run `git pull
|
||||
--rebase`, never `git pull`).
|
||||
will behave like `git pull --rebase` by default. Using
|
||||
`git pull --rebase` to update your changes to resolve merge conflicts
|
||||
is expected by essentially all of open source projects, including
|
||||
Zulip. You can also set that option after cloning using
|
||||
`git config --add pull.rebase true`, or just be careful to always run
|
||||
`git pull --rebase`, never `git pull`).
|
||||
|
||||
Note: If you receive an error while cloning, you may not have [added your ssh
|
||||
key to GitHub][github-help-add-ssh-key].
|
||||
|
@ -65,8 +65,8 @@ origin git@github.com:YOUR_USERNAME/zulip.git (push)
|
|||
Note: If you've cloned the repository using a graphical client, you may already
|
||||
have the upstream remote repository configured. For example, when you clone
|
||||
[zulip/zulip][github-zulip-zulip] with the GitHub desktop client it configures
|
||||
the remote repository `zulip` and you see the following output from `git remote
|
||||
-v`:
|
||||
the remote repository `zulip` and you see the following output from
|
||||
`git remote -v`:
|
||||
|
||||
```console
|
||||
origin git@github.com:YOUR_USERNAME/zulip.git (fetch)
|
||||
|
|
|
@ -129,9 +129,9 @@ $ git log
|
|||
* 13bea0e (HEAD -> main) test commit for docs.
|
||||
```
|
||||
|
||||
And then realize you actually needed to keep commit 67aea58. First, use `git
|
||||
reflog` to confirm that commit you want to restore and then run `git
|
||||
cherry-pick <commit>`:
|
||||
And then realize you actually needed to keep commit 67aea58. First, use
|
||||
`git reflog` to confirm that commit you want to restore and then run
|
||||
`git cherry-pick <commit>`:
|
||||
|
||||
```console
|
||||
$ git reflog
|
||||
|
|
|
@ -46,9 +46,9 @@ from Zulip's main repositories.
|
|||
|
||||
**Note about git pull**: You might be used to using `git pull` on other
|
||||
projects. With Zulip, because we don't use merge commits, you'll want to avoid
|
||||
it. Rather than using `git pull`, which by default is a shortcut for `git fetch
|
||||
&& git merge FETCH_HEAD` ([docs][gitbook-git-pull]), you should use `git fetch`
|
||||
and then `git rebase`.
|
||||
it. Rather than using `git pull`, which by default is a shortcut for
|
||||
`git fetch && git merge FETCH_HEAD` ([docs][gitbook-git-pull]), you
|
||||
should use `git fetch` and then `git rebase`.
|
||||
|
||||
First, [fetch][gitbook-fetch] changes from Zulip's upstream repository you
|
||||
configured in the step above:
|
||||
|
@ -166,9 +166,10 @@ nothing added to commit but untracked files present (use "git add" to track)
|
|||
|
||||
### Stage additions with git add
|
||||
|
||||
To add changes to your staging area, use `git add <filename>`. Because `git
|
||||
add` is all about staging the changes you want to commit, you use it to add
|
||||
*new files* as well as *files with changes* to your staging area.
|
||||
To add changes to your staging area, use `git add <filename>`. Because
|
||||
`git add` is all about staging the changes you want to commit, you use
|
||||
it to add *new files* as well as *files with changes* to your staging
|
||||
area.
|
||||
|
||||
Continuing our example from above, after we run `git add newfile.py`, we'll see
|
||||
the following from `git status`:
|
||||
|
|
|
@ -45,6 +45,6 @@ working copies:
|
|||
- `git remote`: This helps you configure short names for remotes.
|
||||
- `git pull`: This pulls code, but by default creates a merge commit
|
||||
(which you definitely don't want). However, if you've followed our
|
||||
[cloning documentation](../git/cloning.md), this will do `git pull
|
||||
--rebase` instead, which is the only mode you'll want to use when
|
||||
working on Zulip.
|
||||
[cloning documentation](../git/cloning.md), this will do
|
||||
`git pull --rebase` instead, which is the only mode you'll want to
|
||||
use when working on Zulip.
|
||||
|
|
|
@ -405,8 +405,9 @@ log][commit-log] for an up-to-date list of raw changes.
|
|||
- Fixed Postfix configuration error which would prevent outgoing email
|
||||
to any email address containing `.`, `+`, or starting with `mm`, when
|
||||
configured to use the local Postfix to deliver outgoing email.
|
||||
- Fixed a backporting error which caused the `manage.py
|
||||
change_user_role` tool to not work for `admin`, `member`, or `guest` roles.
|
||||
- Fixed a backporting error which caused the
|
||||
`manage.py change_user_role` tool to not work for `admin`, `member`,
|
||||
or `guest` roles.
|
||||
- Add support for logout events sent from modern versions of the
|
||||
desktop application.
|
||||
- Upgraded minor python dependencies.
|
||||
|
@ -545,8 +546,8 @@ log][commit-log] for an up-to-date list of raw changes.
|
|||
[our new PostgreSQL upgrade guide][postgresql-upgrade].
|
||||
- The format of the `JWT_AUTH_KEYS` setting has changed to include an
|
||||
[algorithms](https://pyjwt.readthedocs.io/en/latest/algorithms.html)
|
||||
list: `{"subdomain": "key"}` becomes `{"subdomain": {"key": "key",
|
||||
"algorithms": ["HS256"]}}`.
|
||||
list: `{"subdomain": "key"}` becomes
|
||||
`{"subdomain": {"key": "key", "algorithms": ["HS256"]}}`.
|
||||
- Added a new organization owner permission above the previous
|
||||
organization administrator. All existing organization
|
||||
administrators are automatically converted into organization owners.
|
||||
|
|
|
@ -53,8 +53,8 @@ In either configuration, you will need to do the following:
|
|||
integration, part 1: Connecting to the LDAP server".
|
||||
* If a password is required, put it in
|
||||
`/etc/zulip/zulip-secrets.conf` by setting
|
||||
`auth_ldap_bind_password`. For example: `auth_ldap_bind_password
|
||||
= abcd1234`.
|
||||
`auth_ldap_bind_password`. For example:
|
||||
`auth_ldap_bind_password = abcd1234`.
|
||||
|
||||
1. Decide how you want to map the information in your LDAP database to
|
||||
users' account data in Zulip. For each Zulip user, two closely
|
||||
|
@ -207,11 +207,11 @@ to the `AUTH_LDAP_USER_ATTR_MAP`.
|
|||
|
||||
Starting with Zulip 2.0, Zulip supports synchronizing the
|
||||
disabled/deactivated status of users from Active Directory. You can
|
||||
configure this by uncommenting the sample line `"userAccountControl":
|
||||
"userAccountControl",` in `AUTH_LDAP_USER_ATTR_MAP` (and restarting
|
||||
the Zulip server). Zulip will then treat users that are disabled via
|
||||
the "Disable Account" feature in Active Directory as deactivated in
|
||||
Zulip.
|
||||
configure this by uncommenting the sample line
|
||||
`"userAccountControl": "userAccountControl",` in
|
||||
`AUTH_LDAP_USER_ATTR_MAP` (and restarting the Zulip server). Zulip
|
||||
will then treat users that are disabled via the "Disable Account"
|
||||
feature in Active Directory as deactivated in Zulip.
|
||||
|
||||
Users disabled in active directory will be immediately unable to log in
|
||||
to Zulip, since Zulip queries the LDAP/Active Directory server on
|
||||
|
@ -360,8 +360,7 @@ it as follows:
|
|||
The `Entity ID` should match the value of
|
||||
`SOCIAL_AUTH_SAML_SP_ENTITY_ID` computed in the Zulip settings.
|
||||
You can get the correct value by running the following:
|
||||
`/home/zulip/deployments/current/scripts/get-django-setting
|
||||
SOCIAL_AUTH_SAML_SP_ENTITY_ID`.
|
||||
`/home/zulip/deployments/current/scripts/get-django-setting SOCIAL_AUTH_SAML_SP_ENTITY_ID`.
|
||||
|
||||
* **SSO URL**:
|
||||
`https://yourzulipdomain.example.com/complete/saml/`. This is
|
||||
|
@ -485,11 +484,11 @@ correctly authenticate the user to Zulip.
|
|||
|
||||
If you're hosting multiple organizations and thus using the
|
||||
`SOCIAL_AUTH_SUBDOMAIN` setting, you'll need to configure a custom
|
||||
`RelayState` in your IdP of the form `{"subdomain":
|
||||
"yourzuliporganization"}` to let Zulip know which organization to
|
||||
authenticate the user to when they visit your SSO URL from the IdP.
|
||||
(If the organization is on the root domain, use the empty string:
|
||||
`{"subdomain": ""}`.).
|
||||
`RelayState` in your IdP of the form
|
||||
`{"subdomain": "yourzuliporganization"}` to let Zulip know which
|
||||
organization to authenticate the user to when they visit your SSO URL
|
||||
from the IdP. (If the organization is on the root domain, use the
|
||||
empty string: `{"subdomain": ""}`.).
|
||||
|
||||
### Restricting access to specific organizations
|
||||
|
||||
|
@ -568,8 +567,8 @@ straightforward way to deploy that SSO solution with Zulip.
|
|||
5. Run `a2ensite zulip-sso` to enable the SSO integration within Apache.
|
||||
|
||||
6. Run `service apache2 reload` to use your new configuration. If
|
||||
Apache isn't already running, you may need to run `service apache2
|
||||
start` instead.
|
||||
Apache isn't already running, you may need to run
|
||||
`service apache2 start` instead.
|
||||
|
||||
Now you should be able to visit your Zulip server in a browser (e.g.,
|
||||
at `https://zulip.example.com/`) and log in via the SSO solution.
|
||||
|
@ -702,8 +701,8 @@ By default, users who attempt to login with OIDC using an email
|
|||
address that does not have a current Zulip account will be prompted
|
||||
for whether they intend to create a new account or would like to login
|
||||
using another authentication method. You can configure automatic
|
||||
account creation on first login attempt by setting `"auto_signup":
|
||||
True` in the IdP configuration dictionary.
|
||||
account creation on first login attempt by setting
|
||||
`"auto_signup": True` in the IdP configuration dictionary.
|
||||
|
||||
The global setting `SOCIAL_AUTH_OIDC_FULL_NAME_VALIDATED` controls how
|
||||
Zulip uses the Full Name provided by the IdP. By default, Zulip
|
||||
|
|
|
@ -371,8 +371,8 @@ make the following changes in two configuration files.
|
|||
following. Place it the appropriate path for your Apache2
|
||||
installation and enable it (E.g. if you use Debian or Ubuntu, then
|
||||
place it in `/etc/apache2/sites-available/zulip.example.com.conf`
|
||||
and then run `a2ensite zulip.example.com && systemctl reload
|
||||
apache2`):
|
||||
and then run
|
||||
`a2ensite zulip.example.com && systemctl reload apache2`):
|
||||
|
||||
```apache
|
||||
<VirtualHost *:80>
|
||||
|
|
|
@ -13,8 +13,8 @@ you'd like to watch the downtime phase of the upgrade closely, you
|
|||
can run them manually before starting the upgrade:
|
||||
|
||||
1. Log in to your Zulip server as the `zulip` user (or as `root` and
|
||||
then run `su zulip` to drop privileges), and `cd
|
||||
/home/zulip/deployments/current`
|
||||
then run `su zulip` to drop privileges), and
|
||||
`cd /home/zulip/deployments/current`
|
||||
2. Run `./manage.py dbshell`. This will open a shell connected to the
|
||||
PostgreSQL database.
|
||||
3. In the PostgreSQL shell, run the following commands:
|
||||
|
|
|
@ -90,10 +90,11 @@ your organization, and your own user account as an administrator.
|
|||
Then, log in!
|
||||
|
||||
The link is a secure one-time-use link. If you need another
|
||||
later, you can generate a new one by running `manage.py
|
||||
generate_realm_creation_link` on the server. See also our doc on
|
||||
running [multiple organizations on the same server](multiple-organizations.md)
|
||||
if that's what you're planning to do.
|
||||
later, you can generate a new one by running
|
||||
`manage.py generate_realm_creation_link` on the server. See also our
|
||||
doc on running [multiple organizations on the same
|
||||
server](multiple-organizations.md) if that's what you're planning to
|
||||
do.
|
||||
|
||||
## Step 4: Configure and use
|
||||
|
||||
|
|
|
@ -111,9 +111,9 @@ There are dozens of useful management commands under
|
|||
with SQL will often not behave correctly because PostgreSQL doesn't
|
||||
know to flush Zulip's caches or notify browsers of changes.
|
||||
* `./manage.py send_custom_email`: Can be used to send an email to a set
|
||||
of users. The `--help` documents how to run it from a `manage.py
|
||||
shell` for use with more complex programmatically computed sets of
|
||||
users.
|
||||
of users. The `--help` documents how to run it from a
|
||||
`manage.py shell` for use with more complex programmatically
|
||||
computed sets of users.
|
||||
* `./manage.py send_password_reset_email`: Sends password reset email(s)
|
||||
to one or more users.
|
||||
* `./manage.py change_realm_subdomain`: Change subdomain of a realm.
|
||||
|
|
|
@ -25,12 +25,13 @@ first.
|
|||
|
||||
You can enable this for your Zulip server as follows:
|
||||
|
||||
1. Uncomment the `PUSH_NOTIFICATION_BOUNCER_URL =
|
||||
'https://push.zulipchat.com'` line in your `/etc/zulip/settings.py`
|
||||
file (i.e. remove the `#` at the start of the line), and
|
||||
[restart your Zulip server](../production/settings.html#making-changes).
|
||||
If you installed your Zulip server with a version older than 1.6,
|
||||
you'll need to add the line (it won't be there to uncomment).
|
||||
1. Uncomment the
|
||||
`PUSH_NOTIFICATION_BOUNCER_URL = 'https://push.zulipchat.com'` line
|
||||
in your `/etc/zulip/settings.py` file (i.e. remove the `#` at the
|
||||
start of the line), and [restart your Zulip
|
||||
server](../production/settings.html#making-changes). If you
|
||||
installed your Zulip server with a version older than 1.6, you'll
|
||||
need to add the line (it won't be there to uncomment).
|
||||
|
||||
1. If you're running Zulip 1.8.1 or newer, you can run the
|
||||
registration command:
|
||||
|
@ -82,9 +83,9 @@ in the installer). You can update your server's registration data by
|
|||
running `manage.py register_server` again.
|
||||
|
||||
If you'd like to rotate your server's API key for this service
|
||||
(`zulip_org_key`), you need to use `manage.py register_server
|
||||
--rotate-key` option; it will automatically generate a new
|
||||
`zulip_org_key` and store that new key in
|
||||
(`zulip_org_key`), you need to use
|
||||
`manage.py register_server --rotate-key` option; it will automatically
|
||||
generate a new `zulip_org_key` and store that new key in
|
||||
`/etc/zulip/zulip-secrets.conf`.
|
||||
|
||||
## Why this is necessary
|
||||
|
|
|
@ -46,9 +46,9 @@ things:
|
|||
[the notes on `SOCIAL_AUTH_SUBDOMAIN` below](#authentication).
|
||||
|
||||
For servers hosting a large number of organizations, like
|
||||
[zulip.com](https://zulip.com), one can set `ROOT_DOMAIN_LANDING_PAGE
|
||||
= True` in `/etc/zulip/settings.py` so that the homepage for the
|
||||
server is a copy of the Zulip homepage.
|
||||
[zulip.com](https://zulip.com), one can set
|
||||
`ROOT_DOMAIN_LANDING_PAGE = True` in `/etc/zulip/settings.py` so that
|
||||
the homepage for the server is a copy of the Zulip homepage.
|
||||
|
||||
### SSL certificates
|
||||
|
||||
|
|
|
@ -84,14 +84,15 @@ which shows the currently running backends and their activity. This is
|
|||
similar to the pg_top output, with the added advantage of showing the
|
||||
complete query, which can be valuable in debugging.
|
||||
|
||||
To stop a runaway query, you can run `SELECT pg_cancel_backend(pid
|
||||
int)` or `SELECT pg_terminate_backend(pid int)` as the 'postgres'
|
||||
user. The former cancels the backend's current query and the latter
|
||||
terminates the backend process. They are implemented by sending SIGINT
|
||||
and SIGTERM to the processes, respectively. We recommend against
|
||||
sending a PostgreSQL process SIGKILL. Doing so will cause the database
|
||||
to kill all current connections, roll back any pending transactions,
|
||||
and enter recovery mode.
|
||||
To stop a runaway query, you can run
|
||||
`SELECT pg_cancel_backend(pid int)` or
|
||||
`SELECT pg_terminate_backend(pid int)` as the 'postgres' user. The
|
||||
former cancels the backend's current query and the latter terminates
|
||||
the backend process. They are implemented by sending SIGINT and
|
||||
SIGTERM to the processes, respectively. We recommend against sending
|
||||
a PostgreSQL process SIGKILL. Doing so will cause the database to kill
|
||||
all current connections, roll back any pending transactions, and enter
|
||||
recovery mode.
|
||||
|
||||
#### Stopping the Zulip PostgreSQL database
|
||||
|
||||
|
|
|
@ -38,9 +38,10 @@ Two good tests include:
|
|||
|
||||
* Alternatively, run a command like `curl -SsI https://zulip.example.com`
|
||||
(using your server's URL) from a machine that can reach your server.
|
||||
Make sure that on the same machine, `curl -SsI
|
||||
https://incomplete-chain.badssl.com` gives an error; `curl` on some
|
||||
machines, including Macs, will accept incomplete chains.
|
||||
Make sure that on the same machine,
|
||||
`curl -SsI https://incomplete-chain.badssl.com` gives an error;
|
||||
`curl` on some machines, including Macs, will accept incomplete
|
||||
chains.
|
||||
|
||||
[ssllabs-tester]: https://www.ssllabs.com/ssltest/analyze.html
|
||||
|
||||
|
|
|
@ -256,8 +256,8 @@ Database monitoring:
|
|||
|
||||
Standard server monitoring:
|
||||
|
||||
* `check_debian_packages`: Checks whether the system is behind on `apt
|
||||
upgrade`.
|
||||
* `check_debian_packages`: Checks whether the system is behind on
|
||||
`apt upgrade`.
|
||||
|
||||
If you're using these plugins, bug reports and pull requests to make
|
||||
it easier to monitor Zulip and maintain it in production are
|
||||
|
|
|
@ -59,9 +59,9 @@ as world-readable, whereas the "uploaded files" one is not.
|
|||
|
||||
With older Zulip, you need to edit
|
||||
`/etc/nginx/sites-available/zulip-enterprise` to comment out the
|
||||
`nginx` configuration block for `/user_avatars` and the `include
|
||||
/etc/nginx/zulip-include/uploads.route` line and then reload the
|
||||
`nginx` service (`service nginx reload`).
|
||||
`nginx` configuration block for `/user_avatars` and the
|
||||
`include /etc/nginx/zulip-include/uploads.route` line and then
|
||||
reload the `nginx` service (`service nginx reload`).
|
||||
|
||||
1. Finally, restart the Zulip server so that your settings changes
|
||||
take effect
|
||||
|
|
|
@ -137,11 +137,11 @@ system:
|
|||
- Tests for the backend views code logic for extracting data from the
|
||||
database and serving it to clients.
|
||||
|
||||
For manual backend testing, it sometimes can be valuable to use `./manage.py
|
||||
dbshell` to inspect the tables manually to check that things look right; but
|
||||
usually anything you feel the need to check manually, you should add some
|
||||
sort of assertion for to the backend analytics tests, to make sure it stays
|
||||
that way as we refactor.
|
||||
For manual backend testing, it sometimes can be valuable to use
|
||||
`./manage.py dbshell` to inspect the tables manually to check that
|
||||
things look right; but usually anything you feel the need to check
|
||||
manually, you should add some sort of assertion for to the backend
|
||||
analytics tests, to make sure it stays that way as we refactor.
|
||||
|
||||
## LoggingCountStats
|
||||
|
||||
|
|
|
@ -269,11 +269,11 @@ the browser console, but for debugging convenience, we have a custom
|
|||
webpack plugin (`tools/debug-require-webpack-plugin.ts`) that exposes
|
||||
a version of the `require()` function to the development environment
|
||||
browser console for this purpose. For example, you can access our
|
||||
`people` module by evaluating `people =
|
||||
require("./static/js/people")`, or the third-party `lodash` module
|
||||
with `_ = require("lodash")`. This mechanism is **not** a stable API
|
||||
and should not be used for any purpose other than interactive
|
||||
debugging.
|
||||
`people` module by evaluating
|
||||
`people = require("./static/js/people")`, or the third-party `lodash`
|
||||
module with `_ = require("lodash")`. This mechanism is **not** a
|
||||
stable API and should not be used for any purpose other than
|
||||
interactive debugging.
|
||||
|
||||
We have one module, `zulip_test`, that’s exposed as a global variable
|
||||
using `expose-loader` for direct use in Puppeteer tests and in the
|
||||
|
|
|
@ -131,8 +131,8 @@ new feature hard to miss.
|
|||
* Blueslip keeps a log of all the notices it has received during a
|
||||
browser session, and includes them in reports to the server, so that
|
||||
one can see cases where exceptions chained together. You can print
|
||||
this log from the browser console using `blueslip =
|
||||
require("./static/js/blueslip"); blueslip.get_log()`.
|
||||
this log from the browser console using
|
||||
`blueslip = require("./static/js/blueslip"); blueslip.get_log()`.
|
||||
|
||||
Blueslip supports several error levels:
|
||||
* `throw new Error(…)`: For fatal errors that cannot be easily
|
||||
|
|
|
@ -106,16 +106,16 @@ memcached to do work.
|
|||
As one can see, there are two categories of endpoints that are
|
||||
important for scalability: those with extremely high request volumes,
|
||||
and those with moderately high request volumes that are also
|
||||
expensive. It doesn't matter how expensive, for example, `POST
|
||||
/users/me/subscriptions` is for scalability, because the volume is
|
||||
negligible.
|
||||
expensive. It doesn't matter how expensive, for example,
|
||||
`POST /users/me/subscriptions` is for scalability, because the volume
|
||||
is negligible.
|
||||
|
||||
### Tornado
|
||||
|
||||
Zulip's Tornado-based [real-time push
|
||||
system](../subsystems/events-system.md), and in particular `GET
|
||||
/events`, accounts for something like 50% of all HTTP requests to a
|
||||
production Zulip server. Despite `GET /events` being extremely
|
||||
system](../subsystems/events-system.md), and in particular
|
||||
`GET /events`, accounts for something like 50% of all HTTP requests to
|
||||
a production Zulip server. Despite `GET /events` being extremely
|
||||
high-volume, the typical request takes 1-3ms to process, and doesn't
|
||||
use the database at all (though it will access `memcached` and
|
||||
`redis`), so they aren't a huge contributor to the overall CPU usage
|
||||
|
@ -228,10 +228,10 @@ of active optimization work.
|
|||
|
||||
### Fetching message history
|
||||
|
||||
Bulk requests for message content and metadata ([`GET
|
||||
/messages`](https://zulip.com/api/get-messages)) account for ~3% of
|
||||
total HTTP requests. The zulip web app has a few major reasons it does
|
||||
a large number of these requests:
|
||||
Bulk requests for message content and metadata
|
||||
([`GET /messages`](https://zulip.com/api/get-messages)) account for
|
||||
~3% of total HTTP requests. The zulip web app has a few major reasons
|
||||
it does a large number of these requests:
|
||||
|
||||
* Most of these requests are from users clicking into different views
|
||||
-- to avoid certain subtle bugs, Zulip's web app currently fetches
|
||||
|
|
|
@ -95,10 +95,10 @@ thread; search views will never mark messages as read.
|
|||
|
||||
## Testing and development
|
||||
|
||||
In a Zulip development environment, you can use `manage.py
|
||||
mark_all_messages_unread` to set every user's pointer to 0 and all
|
||||
messages as unread, for convenience in testing unread count related
|
||||
logic.
|
||||
In a Zulip development environment, you can use
|
||||
`manage.py mark_all_messages_unread` to set every user's pointer to 0
|
||||
and all messages as unread, for convenience in testing unread count
|
||||
related logic.
|
||||
|
||||
It can be useful to combine this with `manage.py populate_db -n 3000`
|
||||
(which rebuilds the database with 3000 initial messages) to ensure a
|
||||
|
|
|
@ -41,8 +41,8 @@ To add a new queue processor:
|
|||
queue worker in the Zulip development environment
|
||||
(`tools/run-dev.py` will automatically restart the queue processors
|
||||
and start running your new queue processor code). You can also run
|
||||
a single queue processor manually using e.g. `./manage.py
|
||||
process_queue --queue=user_activity`.
|
||||
a single queue processor manually using e.g.
|
||||
`./manage.py process_queue --queue=user_activity`.
|
||||
|
||||
* So that supervisord will know to run the queue processor in
|
||||
production, you will need to add to the `queues` variable in
|
||||
|
|
|
@ -22,19 +22,19 @@ migrations.
|
|||
* Commit your changes.
|
||||
* For more complicated migrations where you need to run custom Python
|
||||
code as part of the migration, it's best to read past migrations to
|
||||
understand how to write them well. `git grep RunPython
|
||||
zerver/migrations/02*` will find many good examples. Before writing
|
||||
migrations of this form, you should read Django's docs and the
|
||||
sections below.
|
||||
understand how to write them well.
|
||||
`git grep RunPython zerver/migrations/02*` will find many good
|
||||
examples. Before writing migrations of this form, you should read
|
||||
Django's docs and the sections below.
|
||||
* **Numbering conflicts across branches**: If you've done your schema
|
||||
change in a branch, and meanwhile another schema change has taken
|
||||
place, Django will now have two migrations with the same
|
||||
number. There are two easy way to fix this:
|
||||
* If your migrations were automatically generated using `manage.py
|
||||
makemigrations`, a good option is to just remove your migration
|
||||
and rerun the command after rebasing. Remember to `git rebase` to
|
||||
do this in the the commit that changed `models.py` if you have a
|
||||
multi-commit branch.
|
||||
* If your migrations were automatically generated using
|
||||
`manage.py makemigrations`, a good option is to just remove your
|
||||
migration and rerun the command after rebasing. Remember to
|
||||
`git rebase` to do this in the the commit that changed `models.py`
|
||||
if you have a multi-commit branch.
|
||||
* If you wrote code as part of preparing your migrations, or prefer
|
||||
this workflow, you can use run `./tools/renumber-migrations`,
|
||||
which renumbers your migration(s) and fixes up the "dependencies"
|
||||
|
|
|
@ -138,9 +138,9 @@ want those settings.
|
|||
|
||||
### Testing non-default settings
|
||||
|
||||
You can write tests for settings using e.g. `with
|
||||
self.settings(TERMS_OF_SERVICE=None)`. However, this only works for
|
||||
settings which are checked at runtime, not settings which are only
|
||||
You can write tests for settings using e.g.
|
||||
`with self.settings(TERMS_OF_SERVICE=None)`. However, this only works
|
||||
for settings which are checked at runtime, not settings which are only
|
||||
accessed in initialization of Django (or Zulip) internals
|
||||
(e.g. `DATABASES`). See the [Django docs on overriding settings in
|
||||
tests][django-test-settings] for more details.
|
||||
|
|
|
@ -27,10 +27,10 @@ run to iteratively debug something.
|
|||
### Useful debugging tips and tools
|
||||
|
||||
* GitHub Actions stores timestamps for every line in the logs. They
|
||||
are hidden by default; you can see them by toggling the `Show
|
||||
timestamps` option in the menu on any job's log page. (You can get
|
||||
this sort of timestamp in a development environment by piping output
|
||||
to `ts`).
|
||||
are hidden by default; you can see them by toggling the
|
||||
`Show timestamps` option in the menu on any job's log page. (You can
|
||||
get this sort of timestamp in a development environment by piping
|
||||
output to `ts`).
|
||||
|
||||
* GitHub Actions runs on every branch you push on your Zulip fork.
|
||||
This is helpful when debugging something complicated.
|
||||
|
|
|
@ -41,8 +41,8 @@ CI testing process in the `backend` build.
|
|||
mypy is installed by default in the Zulip development environment. If
|
||||
you'd like to install just the version of `mypy` that we're using
|
||||
(useful if e.g. you want `mypy` installed on your laptop outside the
|
||||
Vagrant guest), you can do that with `pip install -r
|
||||
requirements/mypy.txt`.
|
||||
Vagrant guest), you can do that with
|
||||
`pip install -r requirements/mypy.txt`.
|
||||
|
||||
## Running mypy on Zulip's code locally
|
||||
|
||||
|
@ -277,8 +277,8 @@ alternatives first:
|
|||
single site, you may want a [**`Union`
|
||||
type**](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#union-types).
|
||||
`Union` is checked: before using `value: Union[str, int]` as a
|
||||
`str`, mypy requires that you validate it with an `instance(value,
|
||||
str)` test.
|
||||
`str`, mypy requires that you validate it with an
|
||||
`instance(value, str)` test.
|
||||
|
||||
* If you really have no information about the type of a value, use the
|
||||
**`object` type**. Since every type is a subtype of `object`, you
|
||||
|
@ -325,8 +325,8 @@ Instead of using `cast`:
|
|||
|
||||
### Avoid `# type: ignore` comments
|
||||
|
||||
Mypy allows you to ignore any type checking error with a [`# type:
|
||||
ignore`
|
||||
Mypy allows you to ignore any type checking error with a
|
||||
[`# type: ignore`
|
||||
comment](https://mypy.readthedocs.io/en/stable/common_issues.html#spurious-errors-and-locally-silencing-the-checker),
|
||||
but you should avoid this in the absence of a very good reason, such
|
||||
as a bug in mypy itself. If there are no safe options for dealing
|
||||
|
@ -378,9 +378,9 @@ collection. For example:
|
|||
* An exclude list where the default is to exclude nothing should be
|
||||
non-`Optional` with default `[]`.
|
||||
|
||||
Don't test an `Optional` value using truthiness (`if value:`, `not
|
||||
value`, `value or default_value`), especially when the type might have
|
||||
falsy values other than `None`.
|
||||
Don't test an `Optional` value using truthiness (`if value:`,
|
||||
`not value`, `value or default_value`), especially when the type might
|
||||
have falsy values other than `None`.
|
||||
|
||||
```python
|
||||
s: Optional[str]
|
||||
|
@ -491,8 +491,8 @@ def f(s: str) -> str:
|
|||
return s
|
||||
```
|
||||
|
||||
(A generic decorator with an argument would return `Callable[[FuncT],
|
||||
FuncT]`.)
|
||||
(A generic decorator with an argument would return
|
||||
`Callable[[FuncT], FuncT]`.)
|
||||
|
||||
But Mypy doesn't yet support the advanced type annotations that would
|
||||
be needed to correctly type generic signature-changing decorators,
|
||||
|
|
|
@ -58,10 +58,11 @@ that failed in the last test run.
|
|||
**Webhook integrations**. For performance, `test-backend` with no
|
||||
arguments will not run webhook integration tests (`zerver/webhooks/`),
|
||||
which would otherwise account for about 25% of the total runtime.
|
||||
When working on webhooks, we recommend instead running `test-backend
|
||||
zerver/webhooks` manually (or better, the direction for the specific
|
||||
webhooks you're working on). And of course our CI is configured to
|
||||
always use `test-backend --include-webhooks` and run all of the tests.
|
||||
When working on webhooks, we recommend instead running
|
||||
`test-backend zerver/webhooks` manually (or better, the direction for
|
||||
the specific webhooks you're working on). And of course our CI is
|
||||
configured to always use `test-backend --include-webhooks` and run all
|
||||
of the tests.
|
||||
|
||||
## Writing tests
|
||||
|
||||
|
@ -483,8 +484,8 @@ is exposed in your development environment).
|
|||
the console; use `with self.assertLogs` to capture and verify any
|
||||
logging output. Note that we reconfigure various loggers in
|
||||
`zproject/test_extra_settings.py` where the output is unlikely to be
|
||||
interesting when running our test suite. `test-backend
|
||||
--ban-console-output` checks for stray print statements.
|
||||
interesting when running our test suite.
|
||||
`test-backend --ban-console-output` checks for stray print statements.
|
||||
|
||||
Note that `test-backend --coverage` will assert that
|
||||
various specific files in the project have 100% test coverage and
|
||||
|
|
|
@ -204,8 +204,8 @@ These instructions assume you're using the Vagrant development environment.
|
|||
3. You'll now need to set up a WebStorm "Debug Configuration". Open
|
||||
the `Run/Debug Configuration` menu and create a new `Node.js` config:
|
||||
1. Under `Node interpreter:` click the 3 dots to the right side and
|
||||
click on the little plus in the bottom left of the `Node.js
|
||||
Interpreters` window.
|
||||
click on the little plus in the bottom left of the
|
||||
`Node.js Interpreters` window.
|
||||
1. Select `Add Remote...`.
|
||||
1. In the `Configure Node.js Remote Interpreter`, window select `Vagrant`
|
||||
1. Wait for WebStorm to connect to Vagrant. This will be displayed
|
||||
|
|
|
@ -148,13 +148,13 @@ notes above:
|
|||
wait function to make sure the page or element is ready before you
|
||||
interact with it. The [puppeteer docs site](https://pptr.dev/) is a
|
||||
useful reference for the available wait functions.
|
||||
- When using `waitForSelector`, you always want to use the `{visible:
|
||||
true}` option; otherwise the test will stop waiting as soon as the
|
||||
target selector is present in the DOM even if it's hidden. For the
|
||||
common UI pattern of having an element always be present in the DOM
|
||||
whose presence is managed via show/hide rather than adding/removing
|
||||
it from the DOM, `waitForSelector` without `visible: true` won't
|
||||
wait at all.
|
||||
- When using `waitForSelector`, you always want to use the
|
||||
`{visible: true}` option; otherwise the test will stop waiting as
|
||||
soon as the target selector is present in the DOM even if it's
|
||||
hidden. For the common UI pattern of having an element always be
|
||||
present in the DOM whose presence is managed via show/hide rather
|
||||
than adding/removing it from the DOM, `waitForSelector` without
|
||||
`visible: true` won't wait at all.
|
||||
- The test suite uses a smaller set of default user accounts and other
|
||||
data initialized in the database than the normal development
|
||||
environment; specifically, it uses the same setup as the [backend
|
||||
|
|
|
@ -78,8 +78,8 @@ those that:
|
|||
* Don't have large open pull requests (to avoid merge conflicts); one
|
||||
can scan for these using [TinglingGit](https://github.com/zulip/TinglingGit).
|
||||
* Have good unit test coverage, which limits the risk of breaking
|
||||
correctness through refactoring. Use `tools/test-js-with-node
|
||||
--coverage` to get a coverage report.
|
||||
correctness through refactoring. Use
|
||||
`tools/test-js-with-node --coverage` to get a coverage report.
|
||||
|
||||
When migrating a module, we want to be especially thoughtful about
|
||||
putting together a commit structure that makes mistakes unlikely and
|
||||
|
|
|
@ -77,10 +77,10 @@ The end-to-end tooling process for translations in Zulip is as follows.
|
|||
[frontend](#frontend-translations) translations for details on
|
||||
this).
|
||||
|
||||
2. Translation resource files are created using the `./manage.py
|
||||
makemessages` command. This command will create, for each language,
|
||||
a resource file called `translations.json` for the frontend strings
|
||||
and `django.po` for the backend strings.
|
||||
2. Translation resource files are created using the
|
||||
`./manage.py makemessages` command. This command will create, for
|
||||
each language, a resource file called `translations.json` for the
|
||||
frontend strings and `django.po` for the backend strings.
|
||||
|
||||
The `makemessages` command is idempotent in that:
|
||||
|
||||
|
|
|
@ -183,11 +183,10 @@ REQ also helps us with request variable validation. For example:
|
|||
as JSON, and pass it into the function as the `msg_ids` Python
|
||||
keyword argument.
|
||||
|
||||
* `streams_raw = REQ("subscriptions",
|
||||
json_validator=check_list(check_string))` will check that the
|
||||
"subscriptions" HTTP parameter is a list of strings, marshalled as
|
||||
JSON, and pass it into the function with the Python keyword argument
|
||||
`streams_raw`.
|
||||
* `streams_raw = REQ("subscriptions", json_validator=check_list(check_string))`
|
||||
will check that the "subscriptions" HTTP parameter is a list of
|
||||
strings, marshalled as JSON, and pass it into the function with the
|
||||
Python keyword argument `streams_raw`.
|
||||
|
||||
* `message_id=REQ(converter=to_non_negative_int)` will check that the
|
||||
`message_id` HTTP parameter is a string containing a non-negative
|
||||
|
|
|
@ -138,8 +138,8 @@ Rough steps:
|
|||
and shut down the droplet.
|
||||
1. Go to the Images tab on DigitalOcean, and "Take a Snapshot".
|
||||
1. Wait for several minutes.
|
||||
1. Do something like `curl -X GET -H "Content-Type: application/json"
|
||||
-u <API_KEY>: "https://api.digitalocean.com/v2/images?page=11" | grep --color=always base.zulipdev.org`
|
||||
1. Do something like
|
||||
`curl -X GET -H "Content-Type: application/json" -u <API_KEY>: "https://api.digitalocean.com/v2/images?page=11" | grep --color=always base.zulipdev.org`
|
||||
(maybe with a different page number, and replace your API_KEY).
|
||||
1. Replace `template_id` in `create.py` in this directory with the
|
||||
appropriate `id`.
|
||||
|
@ -181,8 +181,8 @@ Rough steps:
|
|||
1. `> ~/.bash_history && history -c && sudo shutdown -h now`
|
||||
1. Go to the Images tab on DigitalOcean, and "Take a Snapshot".
|
||||
1. Wait for several minutes.
|
||||
1. Do something like `curl -X GET -H "Content-Type: application/json"
|
||||
-u <API_KEY>: "https://api.digitalocean.com/v2/images?page=11" | grep --color=always base.zulipdev.org`
|
||||
1. Do something like
|
||||
`curl -X GET -H "Content-Type: application/json" -u <API_KEY>: "https://api.digitalocean.com/v2/images?page=11" | grep --color=always base.zulipdev.org`
|
||||
(maybe with a different page number, and replace your API_KEY).
|
||||
1. Replace `template_id` in `create.py` in this directory with the
|
||||
appropriate `id`.
|
||||
|
|
Loading…
Reference in New Issue