mirror of https://github.com/zulip/zulip.git
docs: Wrap a bunch of long lines.
This commit is contained in:
parent
c57ef13a62
commit
efb8f8c26d
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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>`.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue