Browse Source

Set and revoke API key in Settings page.

pull/46/head
Pēteris Caune 9 years ago
parent
commit
5d2cc0b0fc
7 changed files with 181 additions and 12 deletions
  1. +20
    -0
      hc/accounts/migrations/0004_profile_api_key.py
  2. +9
    -1
      hc/accounts/models.py
  3. +43
    -0
      hc/accounts/tests/test_profile.py
  4. +18
    -6
      hc/accounts/views.py
  5. +20
    -0
      hc/api/migrations/0025_auto_20160216_1214.py
  6. +0
    -4
      static/js/checks.js
  7. +71
    -1
      templates/accounts/profile.html

+ 20
- 0
hc/accounts/migrations/0004_profile_api_key.py View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-02-16 12:14
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0003_profile_token'),
]
operations = [
migrations.AddField(
model_name='profile',
name='api_key',
field=models.CharField(blank=True, max_length=128),
),
]

+ 9
- 1
hc/accounts/models.py View File

@ -1,4 +1,8 @@
import base64
import os
import uuid
from datetime import timedelta
from django.conf import settings
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import User
@ -7,7 +11,6 @@ from django.core.urlresolvers import reverse
from django.db import models
from django.utils import timezone
from hc.lib import emails
import uuid
class ProfileManager(models.Manager):
@ -28,6 +31,7 @@ class Profile(models.Model):
reports_allowed = models.BooleanField(default=True)
ping_log_limit = models.IntegerField(default=100)
token = models.CharField(max_length=128, blank=True)
api_key = models.CharField(max_length=128, blank=True)
objects = ProfileManager()
@ -49,6 +53,10 @@ class Profile(models.Model):
ctx = {"set_password_link": settings.SITE_ROOT + path}
emails.set_password(self.user.email, ctx)
def set_api_key(self):
self.api_key = base64.urlsafe_b64encode(os.urandom(24))
self.save()
def send_report(self):
# reset next report date first:
now = timezone.now()


+ 43
- 0
hc/accounts/tests/test_profile.py View File

@ -0,0 +1,43 @@
from django.core import mail
from hc.test import BaseTestCase
from hc.accounts.models import Profile
class LoginTestCase(BaseTestCase):
def test_it_sends_set_password_link(self):
self.client.login(username="[email protected]", password="password")
form = {"set_password": "1"}
r = self.client.post("/accounts/profile/", form)
assert r.status_code == 302
# profile.token should be set now
profile = Profile.objects.for_user(self.alice)
self.assertTrue(len(profile.token) > 10)
# And an email should have been sent
self.assertEqual(len(mail.outbox), 1)
expected_subject = 'Set password on healthchecks.io'
self.assertEqual(mail.outbox[0].subject, expected_subject)
def test_it_creates_api_key(self):
self.client.login(username="[email protected]", password="password")
form = {"create_api_key": "1"}
r = self.client.post("/accounts/profile/", form)
assert r.status_code == 200
profile = Profile.objects.for_user(self.alice)
self.assertTrue(len(profile.api_key) > 10)
def test_it_revokes_api_key(self):
self.client.login(username="[email protected]", password="password")
form = {"revoke_api_key": "1"}
r = self.client.post("/accounts/profile/", form)
assert r.status_code == 200
profile = Profile.objects.for_user(self.alice)
self.assertEqual(profile.api_key, "")

+ 18
- 6
hc/accounts/views.py View File

@ -120,19 +120,31 @@ def check_token(request, username, token):
def profile(request):
profile = Profile.objects.for_user(request.user)
show_api_key = False
if request.method == "POST":
if "set_password" in request.POST:
profile.send_set_password_link()
return redirect("hc-set-password-link-sent")
form = ReportSettingsForm(request.POST)
if form.is_valid():
profile.reports_allowed = form.cleaned_data["reports_allowed"]
elif "create_api_key" in request.POST:
profile.set_api_key()
show_api_key = True
messages.info(request, "The API key has been created!")
elif "revoke_api_key" in request.POST:
profile.api_key = ""
profile.save()
messages.info(request, "Your settings have been updated!")
messages.info(request, "The API key has been revoked!")
elif "show_api_key" in request.POST:
show_api_key = True
elif "update_reports_allowed" in request.POST:
form = ReportSettingsForm(request.POST)
if form.is_valid():
profile.reports_allowed = form.cleaned_data["reports_allowed"]
profile.save()
messages.info(request, "Your settings have been updated!")
ctx = {
"profile": profile
"profile": profile,
"show_api_key": show_api_key
}
return render(request, "accounts/profile.html", ctx)


+ 20
- 0
hc/api/migrations/0025_auto_20160216_1214.py View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-02-16 12:14
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0024_auto_20160203_2227'),
]
operations = [
migrations.AlterField(
model_name='channel',
name='kind',
field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('po', 'Pushover'), ('victorops', 'VictorOps')], max_length=20),
),
]

+ 0
- 4
static/js/checks.js View File

@ -165,8 +165,4 @@ $(function () {
});
});

+ 71
- 1
templates/accounts/profile.html View File

@ -33,6 +33,7 @@
Each month send me a summary of my checks
</label>
<button
name="update_reports_allowed"
type="submit"
class="btn btn-default pull-right">Save</button>
</form>
@ -47,15 +48,84 @@
{% csrf_token %}
<h2>Set Password</h2>
Attach a password to your healthchecks.io account
<input type="hidden" name="set_password" value="1" />
<button
type="submit"
value="set_password"
class="btn btn-default pull-right">Set Password</button>
</form>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-body settings-block">
<h2>API Access</h2>
{% if profile.api_key %}
{% if show_api_key %}
API key: <code>{{ profile.api_key }}</code>
<button
data-toggle="modal"
data-target="#revoke-api-key-modal"
class="btn btn-danger pull-right">Revoke</button>
{% else %}
<span class="text-success glyphicon glyphicon-ok"></span>
API access is enabled.
<form method="post">
{% csrf_token %}
<button
type="submit"
name="show_api_key"
class="btn btn-default pull-right">Show API key</button>
</form>
{% endif %}
{% else %}
<span class="glyphicon glyphicon-remove"></span>
API access is disabled.
<form method="post">
{% csrf_token %}
<button
type="submit"
name="create_api_key"
class="btn btn-default pull-right">Create API key</button>
</form>
{% endif %}
</div>
</div>
</div>
</div>
<div id="revoke-api-key-modal" class="modal">
<div class="modal-dialog">
<form id="revoke-api-key-form" method="post">
{% csrf_token %}
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</span></button>
<h4 class="remove-check-title">Revoke API Key</h4>
</div>
<div class="modal-body">
<p>You are about to revoke the current API key.</p>
<p>Afterwards, you can create a new API key, but there will
be <strong>no way of getting the current API
key back</strong>.
</p>
<p>Are you sure?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button
type="submit"
name="revoke_api_key"
class="btn btn-danger">Revoke API Key</button>
</div>
</div>
</form>
</div>
</div>
{% endblock %}

Loading…
Cancel
Save