Browse Source

Add "Get a List of Existing Integrations" API call

pull/211/head v1.3.0
Pēteris Caune 6 years ago
parent
commit
a7061fe6a5
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
11 changed files with 147 additions and 10 deletions
  1. +3
    -2
      CHANGELOG.md
  2. +7
    -0
      hc/api/models.py
  3. +54
    -0
      hc/api/tests/test_list_channels.py
  4. +3
    -0
      hc/api/urls.py
  5. +10
    -1
      hc/api/views.py
  6. +2
    -0
      hc/front/management/commands/pygmentize.py
  7. +36
    -7
      templates/front/docs_api.html
  8. +2
    -0
      templates/front/snippets/list_channels_request.html
  9. +1
    -0
      templates/front/snippets/list_channels_request.txt
  10. +15
    -0
      templates/front/snippets/list_channels_response.html
  11. +14
    -0
      templates/front/snippets/list_channels_response.txt

+ 3
- 2
CHANGELOG.md View File

@ -1,7 +1,7 @@
# Changelog
All notable changes to this project will be documented in this file.
## Unreleased
## 1.3.0 - 2018-11-21
### Improvements
- Load settings from environment variables
@ -13,8 +13,9 @@ All notable changes to this project will be documented in this file.
- Show a warning when running with DEBUG=True
- Add "channels" attribute to the Check API resource
- Can specify channel codes when updating a check via API
- Added a workaround for email agents automatically opening "Unsubscribe" links
- Add a workaround for email agents automatically opening "Unsubscribe" links
- Add Channel.name field, users can now name integrations
- Add "Get a List of Existing Integrations" API call
### Bug Fixes
- During DST transition, handle ambiguous dates as pre-transition


+ 7
- 0
hc/api/models.py View File

@ -254,6 +254,13 @@ class Channel(models.Model):
return self.get_kind_display()
def to_dict(self):
return {
"id": str(self.code),
"name": self.name,
"kind": self.kind
}
def assign_all_checks(self):
checks = Check.objects.filter(user=self.user)
self.checks.add(*checks)


+ 54
- 0
hc/api/tests/test_list_channels.py View File

@ -0,0 +1,54 @@
import json
from hc.api.models import Channel
from hc.test import BaseTestCase
class ListChannelsTestCase(BaseTestCase):
def setUp(self):
super(ListChannelsTestCase, self).setUp()
self.c1 = Channel(user=self.alice)
self.c1.kind = "email"
self.c1.name = "Email to Alice"
self.c1.save()
def get(self):
return self.client.get("/api/v1/channels/", HTTP_X_API_KEY="X" * 32)
def test_it_works(self):
r = self.get()
self.assertEqual(r.status_code, 200)
doc = r.json()
self.assertEqual(len(doc["channels"]), 1)
c = doc["channels"][0]
self.assertEqual(c["id"], str(self.c1.code))
self.assertEqual(c["kind"], "email")
self.assertEqual(c["name"], "Email to Alice")
def test_it_shows_only_users_channels(self):
Channel.objects.create(user=self.bob, kind="email", name="Bob")
r = self.get()
data = r.json()
self.assertEqual(len(data["channels"]), 1)
for c in data["channels"]:
self.assertNotEqual(c["name"], "Bob")
def test_it_accepts_api_key_from_request_body(self):
payload = json.dumps({"api_key": "X" * 32})
r = self.client.generic("GET", "/api/v1/channels/", payload,
content_type="application/json")
self.assertEqual(r.status_code, 200)
self.assertContains(r, "Email to Alice")
def test_readonly_key_works(self):
self.profile.api_key_readonly = "R" * 32
self.profile.save()
r = self.client.get("/api/v1/channels/", HTTP_X_API_KEY="R" * 32)
self.assertEqual(r.status_code, 200)

+ 3
- 0
hc/api/urls.py View File

@ -14,6 +14,9 @@ urlpatterns = [
path('api/v1/notifications/<uuid:code>/bounce', views.bounce,
name="hc-api-bounce"),
path('api/v1/channels/', views.channels),
path('badge/<slug:username>/<slug:signature>/<slug:tag>.svg', views.badge,
name="hc-badge"),


+ 10
- 1
hc/api/views.py View File

@ -10,7 +10,7 @@ from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.views.decorators.http import require_GET, require_POST
from hc.api import schemas
from hc.api.decorators import authorize, authorize_read, validate_json
@ -150,6 +150,15 @@ def checks(request):
return HttpResponse(status=405)
@require_GET
@validate_json()
@authorize_read
def channels(request):
q = Channel.objects.filter(user=request.user)
channels = [ch.to_dict() for ch in q]
return JsonResponse({"channels": channels})
@csrf_exempt
@validate_json(schemas.check)
@authorize


+ 2
- 0
hc/front/management/commands/pygmentize.py View File

@ -44,6 +44,8 @@ class Command(BaseCommand):
# API examples
_process("list_checks_request", lexers.BashLexer())
_process("list_checks_response", lexers.JsonLexer())
_process("list_channels_request", lexers.BashLexer())
_process("list_channels_response", lexers.JsonLexer())
_process("create_check_request_a", lexers.BashLexer())
_process("create_check_request_b", lexers.BashLexer())
_process("update_check_request_a", lexers.BashLexer())


+ 36
- 7
templates/front/docs_api.html View File

@ -17,7 +17,7 @@
<h2>API Endpoints</h2>
<table class="table table-bordered">
<tr>
<td><a href="#list-checks">Get list of existing checks</a></td>
<td><a href="#list-checks">Get a list of existing checks</a></td>
<td>
<code>GET {{ SITE_ROOT }}/api/v1/checks/</code>
</td>
@ -46,6 +46,12 @@
<code>DELETE {{ SITE_ROOT }}/api/v1/checks/&lt;code&gt;</code>
</td>
</tr>
<tr>
<td><a href="#list-channels">Get a list of existing integrations</a></td>
<td>
<code>GET {{ SITE_ROOT }}/api/v1/channels/</code>
</td>
</tr>
</table>
<h2>Authentication</h2>
@ -90,7 +96,7 @@ The response may contain a JSON document with additional data.
<!-- ********************************************************************** /-->
<a class="section" name="list-checks">
<h2 class="rule">Get List of Existing Checks</h2>
<h2 class="rule">Get a List of Existing Checks</h2>
</a>
<div class="api-path">GET {{ SITE_ROOT }}/api/v1/checks/</div>
@ -205,12 +211,18 @@ To create a "cron" check, specify the "schedule" and "tz" parameters.
<td>
<p>string, optional</p>
<p>By default, if a check is created through API, no notification
channels are assigned to it. So, when the check goes up or down,
no notifications will get sent.</p>
channels (integrations) are assigned to it.
So, when the check goes up or down, no notifications will get
sent.</p>
<p>Set this field to a special value "*"
to automatically assign all existing notification channels.</p>
<p>To assign specific notification channels, use a comma-separated
list of channel identifiers.</p>
to automatically assign all existing integrations.</p>
<p>To assign specific integrations, use a comma-separated
list of integration identifiers. Use the
<a href="#list-channels">Get a List of Existing Integrations</a>
call to look up integration identifiers.
</p>
</td>
</tr>
<tr>
@ -426,6 +438,23 @@ is sometimes required by some network proxies and web servers.
<h3 class="api-section">Example Response</h3>
{% include "front/snippets/create_check_response.html" %}
<!-- ********************************************************************** /-->
<a class="section" name="list-channels">
<h2 class="rule">Get a List of Existing Integrations</h2>
</a>
<div class="api-path">GET {{ SITE_ROOT }}/api/v1/channels/</div>
<p>Returns a list of integrations belonging to the user.</p>
<h3 class="api-section">Example Request</h3>
{% include "front/snippets/list_channels_request.html" %}
<h3 class="api-section">Example Response</h3>
{% include "front/snippets/list_channels_response.html" %}
{% endblock %}
{% block scripts %}


+ 2
- 0
templates/front/snippets/list_channels_request.html View File

@ -0,0 +1,2 @@
<div class="highlight"><pre><span></span>curl --header <span class="s2">&quot;X-Api-Key: your-api-key&quot;</span> {{ SITE_ROOT }}/api/v1/channels/
</pre></div>

+ 1
- 0
templates/front/snippets/list_channels_request.txt View File

@ -0,0 +1 @@
curl --header "X-Api-Key: your-api-key" SITE_ROOT/api/v1/channels/

+ 15
- 0
templates/front/snippets/list_channels_response.html View File

@ -0,0 +1,15 @@
<div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nt">&quot;channels&quot;</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;4ec5a071-2d08-4baa-898a-eb4eb3cd6941&quot;</span><span class="p">,</span>
<span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;My Work Email&quot;</span><span class="p">,</span>
<span class="nt">&quot;kind&quot;</span><span class="p">:</span> <span class="s2">&quot;email&quot;</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="nt">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;746a083e-f542-4554-be1a-707ce16d3acc&quot;</span><span class="p">,</span>
<span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;My Phone&quot;</span><span class="p">,</span>
<span class="nt">&quot;kind&quot;</span><span class="p">:</span> <span class="s2">&quot;sms&quot;</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</pre></div>

+ 14
- 0
templates/front/snippets/list_channels_response.txt View File

@ -0,0 +1,14 @@
{
"channels": [
{
"id": "4ec5a071-2d08-4baa-898a-eb4eb3cd6941",
"name": "My Work Email",
"kind": "email"
},
{
"id": "746a083e-f542-4554-be1a-707ce16d3acc",
"name": "My Phone",
"kind": "sms"
}
]
}

Loading…
Cancel
Save