docs: Wrap a bunch of long lines.

This commit is contained in:
Tim Abbott 2017-01-05 14:23:16 -08:00
parent c57ef13a62
commit efb8f8c26d
7 changed files with 117 additions and 46 deletions

View File

@ -192,8 +192,10 @@ mind:
Browsing this list can be a great way to find feature ideas to Browsing this list can be a great way to find feature ideas to
implement that other Zulip users are excited about. implement that other Zulip users are excited about.
* [2016 roadmap milestone](http://zulip.readthedocs.io/en/latest/roadmap.html): The * [2016 roadmap milestone](http://zulip.readthedocs.io/en/latest/roadmap.html):
projects that are [priorities for the Zulip project](https://zulip.readthedocs.io/en/latest/roadmap.html). These are great projects if you're looking to make an impact. The projects that are
[priorities for the Zulip project](https://zulip.readthedocs.io/en/latest/roadmap.html).
These are great projects if you're looking to make an impact.
Another way to find issues in Zulip is to take advantage of our Another way to find issues in Zulip is to take advantage of our
"area:<foo>" convention in separating out issues. We partition all of "area:<foo>" convention in separating out issues. We partition all of

View File

@ -42,41 +42,59 @@ It presumes that you already have a fully implemented `<my-bot>.py` bot and now
3. Register a new bot on your Zulip server's web interface. 3. Register a new bot on your Zulip server's web interface.
* Navigate to *Settings* -> *Your Bots* -> *Add a New Bot*, fill out the form and click on *Create Bot*. * Navigate to *Settings* -> *Your Bots* -> *Add a New Bot*, fill
out the form and click on *Create Bot*.
* A new bot should appear in the *Your Bots* panel. * A new bot should appear in the *Your Bots* panel.
4. Add the bot's configuration file on your Zulip server. 4. Add the bot's configuration file on your Zulip server.
* In the *Your Bots* panel, click on the green icon to download its configuration file *.zuliprc* (the structure of this file is explained [here](#configuration-file). * In the *Your Bots* panel, click on the green icon to download
its configuration file *.zuliprc* (the structure of this file is
explained [here](#configuration-file).
* Copy the file to a destination of your choice on your Zulip server, e.g. to `~/.zuliprc` or `~/zuliprc-test`. * Copy the file to a destination of your choice on your Zulip server, e.g. to `~/.zuliprc` or `~/zuliprc-test`.
5. Subscribe the bot to the streams that the bot needs to read messages from or write messages to. 5. Subscribe the bot to the streams that the bot needs to read messages from or write messages to.
* To subscribe your bot to streams, navigate to *Manage Streams*. Select a stream and add your bot by its email address (the address you assigned in step 3). * To subscribe your bot to streams, navigate to *Manage
Streams*. Select a stream and add your bot by its email address
(the address you assigned in step 3).
* Now, the bot will do its job on the streams you subscribed it to. * Now, the bot will do its job on the streams you subscribed it to.
6. Run the bot. 6. Run the bot.
* On your Zulip server (and outside the Vagrant environment), navigate to `~/zulip/contrib_bots/` * On your Zulip server (and outside the Vagrant environment), navigate to `~/zulip/contrib_bots/`
* Run `python run.py ~/zulip/contrib_bots/lib/<my-bot>.py --config-file ~/.zuliprc`. The `~/` before `.zuliprc` should point to the directory containing the file (in this case, it is the home directory). * Run `python run.py ~/zulip/contrib_bots/lib/<my-bot>.py
* Check the output of the command. It should start with the text the `usage` function returns, followed by logging output similar to this: --config-file ~/.zuliprc`. The `~/` before `.zuliprc` should
``` point to the directory containing the file (in this case, it is
INFO:root:starting message handling... the home directory).
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost * Check the output of the command. It should start with the text
``` the `usage` function returns, followed by logging output similar
to this:
```
INFO:root:starting message handling...
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost
```
* Congrats! Now, your bot should be ready to test on the streams you've subscribed it to. * Congrats! Now, your bot should be ready to test on the streams you've subscribed it to.
### Test the `followup.py` bot ### Test the `followup.py` bot
1. Do the previous steps for the `followup.py` bot. 1. Do the previous steps for the `followup.py` bot.
2. Create the *followup* stream. 2. Create the *followup* stream.
3. Subscribe the bot to the newly created *followup* stream and a stream you want to use it from, e.g. *social*. 3. Subscribe the bot to the newly created *followup* stream and a
4. Send a message to the stream you've subscribed the bot to (other than *followup*). If everything works, a copy of the message should now pop up in the *followup* stream. stream you want to use it from, e.g. *social*.
4. Send a message to the stream you've subscribed the bot to (other
than *followup*). If everything works, a copy of the message should
now pop up in the *followup* stream.
## How to develop a bot ## How to develop a bot
The tutorial below explains the structure of a bot `<my-bot>.py`. You can use this as boilerplate code for developing your own bot. The tutorial below explains the structure of a bot `<my-bot>.py`. You
can use this as boilerplate code for developing your own bot.
Every bot is built upon this structure: Every bot is built upon this structure:
``` ```
class MyBotHandler(object): class MyBotHandler(object):
''' '''
@ -94,7 +112,11 @@ class MyBotHandler(object):
handler_class = MyBotHandler handler_class = MyBotHandler
``` ```
* The class name (in this case *MyBotHandler*) can be defined by you and should match the name of your bot. To register your bot's class, adjust the last line `handler_class = MyBotHandler` to match your class name.
* The class name (in this case *MyBotHandler*) can be defined by you
and should match the name of your bot. To register your bot's class,
adjust the last line `handler_class = MyBotHandler` to match your
class name.
* Every bot needs to implement the functions * Every bot needs to implement the functions
* `usage(self)` * `usage(self)`
@ -104,7 +126,9 @@ handler_class = MyBotHandler
* These functions are documented in the [next section](#bot-api). * These functions are documented in the [next section](#bot-api).
## Bot API ## Bot API
This section documents the functions every bot needs to implement and the structure of the bot's config file.
This section documents the functions every bot needs to implement and
the structure of the bot's config file.
### usage ### usage
*usage(self)* *usage(self)*
@ -212,13 +236,17 @@ None.
site=<dev-url> site=<dev-url>
``` ```
* key - the API key you created for the bot; this is how Zulip knows the request is from an authorized user. * key - the API key you created for the bot; this is how Zulip knows
the request is from an authorized user.
* email - the email address of the bot, e.g. `some-bot@zulip.com` * email - the email address of the bot, e.g. `some-bot@zulip.com`
* site - your development environment URL; if you are working on a development environment hosted on your computer, use `localhost:9991` * site - your development environment URL; if you are working on a
development environment hosted on your computer, use
`localhost:9991`
## Common problems ## Common problems
* I modified my bot's code, yet the changes don't seem to have an effect. * I modified my bot's code, yet the changes don't seem to have an effect.
* Ensure that you restarted the `run.py` script. * Ensure that you restarted the `run.py` script.

View File

@ -320,7 +320,11 @@ Now run these commands:
./tools/install-mypy ./tools/install-mypy
./tools/setup/emoji/build_emoji ./tools/setup/emoji/build_emoji
./scripts/setup/generate_secrets.py --development ./scripts/setup/generate_secrets.py --development
if [ $(uname) = "OpenBSD" ]; then sudo cp ./puppet/zulip/files/postgresql/zulip_english.stop /var/postgresql/tsearch_data/; else sudo cp ./puppet/zulip/files/postgresql/zulip_english.stop /usr/share/postgresql/9.*/tsearch_data/; fi if [ $(uname) = "OpenBSD" ]; then
sudo cp ./puppet/zulip/files/postgresql/zulip_english.stop /var/postgresql/tsearch_data/
else
sudo cp ./puppet/zulip/files/postgresql/zulip_english.stop /usr/share/postgresql/9.*/tsearch_data/
fi
./scripts/setup/configure-rabbitmq ./scripts/setup/configure-rabbitmq
./tools/setup/postgres-init-dev-db ./tools/setup/postgres-init-dev-db
./tools/do-destroy-rebuild-database ./tools/do-destroy-rebuild-database

View File

@ -13,9 +13,13 @@ Zulip uses the [Django web
framework](https://docs.djangoproject.com/en/1.8/), so a lot of these framework](https://docs.djangoproject.com/en/1.8/), so a lot of these
paths will be familiar to Django developers. paths will be familiar to Django developers.
* `zproject/urls.py` Main [Django routes file](https://docs.djangoproject.com/en/1.8/topics/http/urls/). Defines which URLs are handled by which view functions or templates. * `zproject/urls.py` Main
[Django routes file](https://docs.djangoproject.com/en/1.8/topics/http/urls/).
Defines which URLs are handled by which view functions or templates.
* `zerver/models.py` Main [Django models](https://docs.djangoproject.com/en/1.8/topics/db/models/) file. Defines Zulip's database tables. * `zerver/models.py` Main
[Django models](https://docs.djangoproject.com/en/1.8/topics/db/models/)
file. Defines Zulip's database tables.
* `zerver/lib/actions.py` Most code doing writes to user-facing database tables. * `zerver/lib/actions.py` Most code doing writes to user-facing database tables.
@ -40,7 +44,8 @@ paths will be familiar to Django developers.
See [our translating docs](translating.html) for details on Zulip's See [our translating docs](translating.html) for details on Zulip's
templating systems. templating systems.
* `templates/zerver/` For [Jinja2](http://jinja.pocoo.org/) templates for the backend (for zerver app). * `templates/zerver/` For [Jinja2](http://jinja.pocoo.org/) templates
for the backend (for zerver app).
* `static/templates/` [Handlebars](http://handlebarsjs.com/) templates for the frontend. * `static/templates/` [Handlebars](http://handlebarsjs.com/) templates for the frontend.

View File

@ -21,10 +21,14 @@ are in your git checkout under `static`, and are served unminified.
## Nginx secures traffic with [SSL](prod-install.html) ## Nginx secures traffic with [SSL](prod-install.html)
If you visit your Zulip server in your browser and discover that your If you visit your Zulip server in your browser and discover that your
traffic isn't being properly encrypted, an [nginx misconfiguration](https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/sites-available/zulip-enterprise) is the traffic isn't being properly encrypted, an [nginx misconfiguration][nginx-config] is the
likely culprit. likely culprit.
## Static files are [served directly](https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/zulip-include-frontend/app) by Nginx [nginx-config]: https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/sites-available/zulip-enterprise
## Static files are [served directly][served-directly] by Nginx
[served-directly]: https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/zulip-include-frontend/app
Static files include JavaScript, css, static assets (like emoji, avatars), Static files include JavaScript, css, static assets (like emoji, avatars),
and user uploads (if stored locally and not on S3). and user uploads (if stored locally and not on S3).
@ -36,7 +40,9 @@ location /static/ {
} }
``` ```
## Nginx routes other requests [between tornado and django](architecture-overview.html?highlight=tornado#tornado-and-django) ## Nginx routes other requests [between tornado and django][tornado-django]
[tornado-django]: architecture-overview.html?highlight=tornado#tornado-and-django
All our connected clients hold open long-polling connections so that All our connected clients hold open long-polling connections so that
they can recieve events (messages, presence notifications, and so on) in they can recieve events (messages, presence notifications, and so on) in
@ -45,7 +51,9 @@ real-time. Events are served by Zulip's `tornado` application.
Nearly every other kind of request is served by the `zerver` Django Nearly every other kind of request is served by the `zerver` Django
application. application.
[Here is the relevant nginx routing configuration.](https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/zulip-include-frontend/app) [Here is the relevant nginx routing configuration.][nginx-config-link]
[nginx-config-link]: https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/zulip-include-frontend/app
## Django routes the request to a view in urls.py files ## Django routes the request to a view in urls.py files
@ -101,7 +109,9 @@ show my message multiple times. PATCH is special--it can be
idempotent, and we like to write API endpoints in an idempotent fashion, idempotent, and we like to write API endpoints in an idempotent fashion,
as much as possible. as much as possible.
This [cookbook](http://restcookbook.com/) and [tutorial](http://www.restapitutorial.com/) can be helpful if you are new to REST web applications. This [cookbook](http://restcookbook.com/) and
[tutorial](http://www.restapitutorial.com/) can be helpful if you are
new to REST web applications.
### PUT is only for creating new things ### PUT is only for creating new things
@ -137,7 +147,8 @@ In this way, the API is partially self-documenting.
The endpoints from the legacy JSON API are written without REST in The endpoints from the legacy JSON API are written without REST in
mind. They are used extensively by the web client, and use POST. mind. They are used extensively by the web client, and use POST.
You can see them in [zproject/legacy_urls.py](https://github.com/zulip/zulip/blob/master/zproject/legacy_urls.py). You can see them in
[zproject/legacy_urls.py](https://github.com/zulip/zulip/blob/master/zproject/legacy_urls.py).
### Webhook integrations may not be RESTful ### Webhook integrations may not be RESTful
@ -147,23 +158,29 @@ only POST.
## Django calls rest_dispatch for REST endpoints, and authenticates ## Django calls rest_dispatch for REST endpoints, and authenticates
For requests that correspond to a REST url pattern, Zulip configures its For requests that correspond to a REST url pattern, Zulip configures
url patterns (see [zerver/lib/rest.py](https://github.com/zulip/zulip/blob/master/zerver/lib/rest.py)) so that the action called is its url patterns (see
`rest_dispatch`. This method will authenticate the user, either through [zerver/lib/rest.py](https://github.com/zulip/zulip/blob/master/zerver/lib/rest.py))
a session token from a cookie, or from an `email:api-key` string given so that the action called is `rest_dispatch`. This method will
via HTTP Basic Auth for API clients. authenticate the user, either through a session token from a cookie,
or from an `email:api-key` string given via HTTP Basic Auth for API
clients.
It will then look up what HTTP verb was used (GET, POST, etc) to make It will then look up what HTTP verb was used (GET, POST, etc) to make
the request, and then figure out which view to show from that. the request, and then figure out which view to show from that.
In our example, In our example,
``` ```
{'GET': 'zerver.views.users.get_members_backend', {'GET': 'zerver.views.users.get_members_backend',
'PUT': 'zerver.views.users.create_user_backend'} 'PUT': 'zerver.views.users.create_user_backend'}
``` ```
is supplied as an argument to `rest_dispatch`, along with the [HTTPRequest](https://docs.djangoproject.com/en/1.8/ref/request-response/).
is supplied as an argument to `rest_dispatch`, along with the
[HTTPRequest](https://docs.djangoproject.com/en/1.8/ref/request-response/).
The request has the HTTP verb `PUT`, which `rest_dispatch` can use to The request has the HTTP verb `PUT`, which `rest_dispatch` can use to
find the correct view to show: `zerver.views.users.create_user_backend`. find the correct view to show:
`zerver.views.users.create_user_backend`.
## The view will authorize the user, extract request variables, and validate them ## The view will authorize the user, extract request variables, and validate them
@ -176,7 +193,9 @@ return `json_error` in the case of an error, which gives a JSON string:
`{'result': 'error', 'msg': <some error message>}` `{'result': 'error', 'msg': <some error message>}`
in a [HTTP Response](https://docs.djangoproject.com/en/1.8/ref/request-response/) with a content type of 'application/json'. in a
[HTTP Response](https://docs.djangoproject.com/en/1.8/ref/request-response/)
with a content type of 'application/json'.
To pass back data from the server to the calling client, in the event of To pass back data from the server to the calling client, in the event of
a successfully handled request, we use `json_success(data=<some python object which can be converted to a JSON string>`. a successfully handled request, we use `json_success(data=<some python object which can be converted to a JSON string>`.

View File

@ -16,18 +16,29 @@ override that configuration).
If you want to use a remote Postgresql database, you should configure If you want to use a remote Postgresql database, you should configure
the information about the connection with the server. You need a user the information about the connection with the server. You need a user
called "zulip" in your database server. You can configure these called "zulip" in your database server. You can configure these
options in /etc/zulip/settings.py: options in /etc/zulip/settings.py (the below descriptions are from the
Postgresql documentation):
* REMOTE_POSTGRES_HOST: Name or IP address of the remote host * REMOTE_POSTGRES_HOST: Name or IP address of the remote host
* REMOTE_POSTGRES_SSLMODE: SSL Mode used to connect to the server, different options you can use are: * REMOTE_POSTGRES_SSLMODE: SSL Mode used to connect to the server,
* disable: I don't care about security, and I don't want to pay the overhead of encryption. different options you can use are:
* allow: I don't care about security, but I will pay the overhead of encryption if the server insists on it. * disable: I don't care about security, and I don't want to pay the
* prefer: I don't care about encryption, but I wish to pay the overhead of encryption if the server supports it. overhead of encryption.
* require: I want my data to be encrypted, and I accept the overhead. I trust that the network will make sure I always connect to the server I want. * allow: I don't care about security, but I will pay the overhead of
* verify-ca: I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server that I trust. encryption if the server insists on it.
* verify-full: I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server I trust, and that it's the one I specify. * prefer: I don't care about encryption, but I wish to pay the
overhead of encryption if the server supports it.
* require: I want my data to be encrypted, and I accept the
overhead. I trust that the network will make sure I always connect
to the server I want.
* verify-ca: I want my data encrypted, and I accept the overhead. I
want to be sure that I connect to a server that I trust.
* verify-full: I want my data encrypted, and I accept the
overhead. I want to be sure that I connect to a server I trust,
and that it's the one I specify.
Then you should specify the password of the user zulip for the database in /etc/zulip/zulip-secrets.conf: Then you should specify the password of the user zulip for the
database in /etc/zulip/zulip-secrets.conf:
``` ```
postgres_password = xxxx postgres_password = xxxx

View File

@ -194,7 +194,9 @@ REQ also helps us with request variable validation. For example:
integer (`converter` differs from `validator` in that it does not integer (`converter` differs from `validator` in that it does not
automatically marshall the input from JSON). automatically marshall the input from JSON).
See [zerver/lib/validator.py](https://github.com/zulip/zulip/blob/master/zerver/lib/validator.py) for more validators and their documentation. See
[zerver/lib/validator.py](https://github.com/zulip/zulip/blob/master/zerver/lib/validator.py)
for more validators and their documentation.
### Deciding which HTTP verb to use ### Deciding which HTTP verb to use