diff --git a/static/js/portico/api.js b/static/js/portico/api.js index c8ac04b99d..49fcf78cc5 100644 --- a/static/js/portico/api.js +++ b/static/js/portico/api.js @@ -1,6 +1,21 @@ -$(function () { - $('a[data-toggle="tab"]').on('shown', function (e) { - $("." + $(e.target).data("class")).show(); - $("." + $(e.relatedTarget).data("class")).hide(); +function registerCodeSection($codeSection) { + const $li = $codeSection.find("ul.nav li"); + const $blocks = $codeSection.find(".blocks div"); + + $li.click(function () { + const language = this.dataset.language; + + $li.removeClass("active"); + $li.filter("[data-language="+language+"]").addClass("active"); + + $blocks.removeClass("active"); + $blocks.filter("[data-language="+language+"]").addClass("active"); }); + + $li.eq(0).click(); +} + + +$(".code-section").each(function () { + registerCodeSection($(this)); }); diff --git a/static/styles/portico.css b/static/styles/portico.css index 948e887f56..b0c2ec8d5a 100644 --- a/static/styles/portico.css +++ b/static/styles/portico.css @@ -76,6 +76,57 @@ body { -moz-osx-font-smoothing: grayscale; } +.app.api-docs .sidebar { + background-color: #fff; + border-right: 1px solid #ddd; + color: #444; +} + +.app.api-docs .sidebar h2 { + color: #444; +} + +.app.api-docs .sidebar li { + opacity: 0.8; +} + +.code-section ul.nav { + margin: 0; +} + +.code-section ul.nav li { + display: inline-block; + padding: 3px 10px; + margin: 0; + + border: 1px solid #ddd; + border-bottom: none; + border-radius: 4px 4px 0px 0px; + + cursor: pointer; +} + +.code-section ul.nav li.active { + color: hsl(176, 46%, 41%); +} + +.code-section .blocks { + padding: 20px; + + background-color: #fafafa; + border: 1px solid #ddd; + + border-radius: 0px 4px 4px 4px; +} + +.code-section .blocks > div { + display: none; +} + +.code-section .blocks > .active { + display: block; +} + .app.help { position: fixed; width: 100vw; diff --git a/templates/zerver/api/api-keys.md b/templates/zerver/api/api-keys.md new file mode 100644 index 0000000000..a849b7dac7 --- /dev/null +++ b/templates/zerver/api/api-keys.md @@ -0,0 +1,44 @@ +# API keys + +You can create bots on your [settings page](/#settings). +Once you have a bot, you can use its email and API key to send messages.

+ +Create a bot: + + +Look for the bot's email and API key: + + +If you prefer to send messages as your own user, you can also find your API key on your [settings page](/#settings). +When using our python bindings, you may either specify the user +and API key for each Client object that you initialize, or let the binding look for +them in your `~/.zuliprc`, the default config file, which you can create as follows: + +``` +[api] +key=BOT_API_KEY +email=BOT_EMAIL_ADDRESS +``` + +Additionally, you can also specify the parameters as environment variables as follows: + +``` +export ZULIP_CONFIG=/path/to/zulipconfig +export ZULIP_EMAIL=BOT_EMAIL_ADDRESS +export ZULIP_API_KEY=BOT_API_KEY +``` + +The parameters specified in environment variables would override the parameters +provided in the config file. For example, if you specify the variable `key` +in the config file and specify `ZULIP_API_KEY` as an environment variable, +the value of `ZULIP_API_KEY` would be considered. + +The following variables can be specified: + +1. `ZULIP_CONFIG` +2. `ZULIP_API_KEY` +3. `ZULIP_EMAIL` +4. `ZULIP_SITE` +5. `ZULIP_CERT` +6. `ZULIP_CERT_KEY` +7. `ZULIP_CERT_BUNDLE` diff --git a/templates/zerver/api/index.md b/templates/zerver/api/index.md new file mode 100644 index 0000000000..3f39eda357 --- /dev/null +++ b/templates/zerver/api/index.md @@ -0,0 +1,12 @@ +# We hear you like APIs... + +We have a [well-documented API](/api/endpoints) that allows you to build +custom integrations, in addition to our [existing integrations](/integrations). +For ease-of-use, we've created a Python module that you can drop in to a +project to start interacting with our API. There is also a +[JavaScript library](https://github.com/zulip/zulip-js) that can be used +either in the browser or in Node.js. + +**Don't want to make it yourself?** Zulip [already integrates with lots of services](/integrations). + +{{ render_markdown_path("zerver/api/sidebar.md") }} diff --git a/templates/zerver/api/installation-instructions.md b/templates/zerver/api/installation-instructions.md new file mode 100644 index 0000000000..2c13f68642 --- /dev/null +++ b/templates/zerver/api/installation-instructions.md @@ -0,0 +1,163 @@ +# Installation instructions + +#### Python Installation +Install it with [pip](https://pypi.python.org/pypi/zulip/): +``` +pip install zulip +``` +#### JavaScript Installation +Install it with [npm](https://www.npmjs.com/package/zulip-js): +``` +npm install zulip-js +``` + +### Usage examples +
+ +
+ +
+No download required! + +#### Stream message + +``` +curl {{ api_url }}/v1/messages \ +-u BOT_EMAIL_ADDRESS:BOT_API_KEY \ +-d "type=stream" \ +-d "to=Denmark" \ +-d "subject=Castle" \ +-d "content=Something is rotten in the state of Denmark." +``` + +#### Private message +``` +curl {{ api_url }}/v1/messages \ +-u BOT_EMAIL_ADDRESS:BOT_API_KEY \ +-d "type=private" \ +-d "to=hamlet@example.com" \ +-d "content=I come not, friends, to steal away your hearts." +``` +
+ +
+```python +#!/usr/bin/env python + +import zulip +import sys + +# Keyword arguments 'email' and 'api_key' are not required if you are using ~/.zuliprc +client = zulip.Client(email="othello-bot@example.com", + api_key="a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5", + site="{{ api_url }}") +# Send a stream message +client.send_message({ +"type": "stream", +"to": "Denmark", +"subject": "Castle", +"content": "Something is rotten in the state of Denmark." +}) +# Send a private message +client.send_message({ +"type": "private", +"to": "hamlet@example.com", +"content": "I come not, friends, to steal away your hearts." +}) + +# Print each message the user receives +# This is a blocking call that will run forever +client.call_on_each_message(lambda msg: sys.stdout.write(str(msg) + "\n")) + +# Print every event relevant to the user +# This is a blocking call that will run forever +# This will never be reached unless you comment out the previous line +client.call_on_each_event(lambda msg: sys.stdout.write(str(msg) + "\n")) +``` +
+ +
+You can use `zulip-send` (found in `bin/` in the tarball) to easily send Zulips +from the command-line, providing the message to be sent on STDIN. + +#### Stream message + +```bash +zulip-send --stream Denmark --subject Castle \ +--user othello-bot@example.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 +``` + +#### Private message + +```bash +zulip-send hamlet@example.com \ +--user othello-bot@example.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 +``` + +#### Passing in the message on the command-line + +If you'd like, you can also provide the message on the command-line with the `-m` flag, as follows: + + +```bash +zulip-send --stream Denmark --subject Castle \ +-m "Something is rotten in the state of Denmark." \ +--user othello-bot@example.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 +``` + +You can omit the `user` and `api-key` arguments if you have a `~/.zuliprc` file. + +See also the [full API endpoint documentation.](/api/endpoints). +
+ +
+More examples and documentation can be found [here](https://github.com/zulip/zulip-js). +```js +const zulip = require('zulip'); + +const config = { +username: 'othello-bot@example.com', +apiKey: 'a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5', +realm: '{{ api_url }}' +}; + +const client = zulip(config); + +// Send a message +client.messages.send({ +to: 'Denmark', +type: 'stream', +subject: 'Castle', +content: 'Something is rotten in the state of Denmark.' +}); + +// Send a private message +client.messages.send({ +to: 'hamlet@example.com', +type: 'private', +content: 'I come not, friends, to steal away your hearts.' +}); + +// Register queue to receive messages for user +client.queues.register({ +event_types: ['message'] +}).then((res) => { +// Retrieve events from a queue +// Blocking until there is an event (or the request times out) +client.events.retrieve({ +queue_id: res.queue_id, +last_event_id: -1, +dont_block: false +}).then(console.log); +}); +``` +
+ +
+ +
diff --git a/templates/zerver/api/main.html b/templates/zerver/api/main.html new file mode 100644 index 0000000000..bec486bdb2 --- /dev/null +++ b/templates/zerver/api/main.html @@ -0,0 +1,33 @@ +{% extends "zerver/portico-help.html" %} + +{# API information page #} + +{% block portico_content %} +
+ + + + + + +
+
+ {{ render_markdown_path(article) }} + + +
+
+
+ +{{ render_bundle("api") }} +{% endblock %} diff --git a/templates/zerver/api/missing.md b/templates/zerver/api/missing.md new file mode 120000 index 0000000000..76475d17b4 --- /dev/null +++ b/templates/zerver/api/missing.md @@ -0,0 +1 @@ +../help/missing.md \ No newline at end of file diff --git a/templates/zerver/api/sidebar.md b/templates/zerver/api/sidebar.md new file mode 100644 index 0000000000..edd84059df --- /dev/null +++ b/templates/zerver/api/sidebar.md @@ -0,0 +1,4 @@ +## API + +* [Installation instructions](/api-new/installation-instructions) +* [API keys](/api-new/api-keys) diff --git a/tools/check-templates b/tools/check-templates index 08d7d41cee..5e003e2104 100755 --- a/tools/check-templates +++ b/tools/check-templates @@ -63,6 +63,7 @@ def check_html_templates(templates, all_dups): 'id_terms', 'send_confirm', 'register', + 'footer', ] bad_ids_dict = {ids: fns for ids, fns in template_id_dict.items() if (ids not in IGNORE_IDS) and len(fns) > 1} diff --git a/tools/linter_lib/custom_check.py b/tools/linter_lib/custom_check.py index 3a4fb41eeb..c8305a5a6a 100644 --- a/tools/linter_lib/custom_check.py +++ b/tools/linter_lib/custom_check.py @@ -530,6 +530,7 @@ def build_custom_checkers(by_lang): 'templates/zerver/accounts_send_confirm.html', 'templates/zerver/integrations/index.html', 'templates/zerver/help/main.html', + 'templates/zerver/api/main.html', 'templates/analytics/realm_summary_table.html', 'templates/corporate/zephyr.html', 'templates/corporate/zephyr-mirror.html', diff --git a/zerver/tests/test_docs.py b/zerver/tests/test_docs.py index 74c8ef6cab..2f54a73855 100644 --- a/zerver/tests/test_docs.py +++ b/zerver/tests/test_docs.py @@ -53,6 +53,9 @@ class DocPageTest(ZulipTestCase): # type: () -> None self._test('/api/', 'We hear you like APIs') self._test('/api/endpoints/', 'pre-built API bindings for') + self._test('/api-new/', 'We hear you like APIs') + self._test('/api-new/api-keys', 'you can use its email and API key') + self._test('/api-new/installation-instructions', 'Python Installation') self._test('/about/', 'Cambridge, Massachusetts') # Test the i18n version of one of these pages. self._test('/en/about/', 'Cambridge, Massachusetts') diff --git a/zproject/urls.py b/zproject/urls.py index d17dad4378..11561bf173 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -546,6 +546,9 @@ urls += [url(r'^', include('social_django.urls', namespace='social'))] urls += [url(r'^help/(?P
.*)$', MarkdownDirectoryView.as_view(template_name='zerver/help/main.html', path_template='/zerver/help/%s.md'))] +urls += [url(r'^api-new/(?P
[-\w]*\/?)$', + MarkdownDirectoryView.as_view(template_name='zerver/api/main.html', + path_template='/zerver/api/%s.md'))] if settings.DEVELOPMENT: urls += dev_urls.urls