Browse Source

Split "Account Settings" page into subpages.

pull/114/merge
Pēteris Caune 8 years ago
parent
commit
4906a5247c
12 changed files with 267 additions and 125 deletions
  1. +20
    -0
      hc/accounts/tests/test_badges.py
  2. +24
    -0
      hc/accounts/tests/test_notifications.py
  3. +0
    -15
      hc/accounts/tests/test_profile.py
  4. +2
    -0
      hc/accounts/urls.py
  5. +45
    -11
      hc/accounts/views.py
  6. +5
    -1
      static/css/base.css
  7. +2
    -2
      static/css/bootstrap.css
  8. +2
    -2
      stuff/bootstrap/variables.less
  9. +63
    -0
      templates/accounts/badges.html
  10. +58
    -0
      templates/accounts/notifications.html
  11. +44
    -92
      templates/accounts/profile.html
  12. +2
    -2
      templates/base.html

+ 20
- 0
hc/accounts/tests/test_badges.py View File

@ -0,0 +1,20 @@
from hc.test import BaseTestCase
from hc.api.models import Check
class BadgesTestCase(BaseTestCase):
def test_it_shows_badges(self):
self.client.login(username="[email protected]", password="password")
Check.objects.create(user=self.alice, tags="foo a-B_1 baz@")
Check.objects.create(user=self.bob, tags="bobs-tag")
r = self.client.get("/accounts/profile/badges/")
self.assertContains(r, "foo.svg")
self.assertContains(r, "a-B_1.svg")
# Expect badge URLs only for tags that match \w+
self.assertNotContains(r, "[email protected]")
# Expect only Alice's tags
self.assertNotContains(r, "bobs-tag.svg")

+ 24
- 0
hc/accounts/tests/test_notifications.py View File

@ -0,0 +1,24 @@
from hc.test import BaseTestCase
class NotificationsTestCase(BaseTestCase):
def test_it_saves_reports_allowed_true(self):
self.client.login(username="[email protected]", password="password")
form = {"reports_allowed": "on"}
r = self.client.post("/accounts/profile/notifications/", form)
assert r.status_code == 200
self.alice.profile.refresh_from_db()
self.assertTrue(self.alice.profile.reports_allowed)
def test_it_saves_reports_allowed_false(self):
self.client.login(username="[email protected]", password="password")
form = {}
r = self.client.post("/accounts/profile/notifications/", form)
assert r.status_code == 200
self.alice.profile.refresh_from_db()
self.assertFalse(self.alice.profile.reports_allowed)

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

@ -123,18 +123,3 @@ class ProfileTestCase(BaseTestCase):
# to user's default team.
self.bobs_profile.refresh_from_db()
self.assertEqual(self.bobs_profile.current_team, self.bobs_profile)
def test_it_shows_badges(self):
self.client.login(username="[email protected]", password="password")
Check.objects.create(user=self.alice, tags="foo a-B_1 baz@")
Check.objects.create(user=self.bob, tags="bobs-tag")
r = self.client.get("/accounts/profile/")
self.assertContains(r, "foo.svg")
self.assertContains(r, "a-B_1.svg")
# Expect badge URLs only for tags that match \w+
self.assertNotContains(r, "[email protected]")
# Expect only Alice's tags
self.assertNotContains(r, "bobs-tag.svg")

+ 2
- 0
hc/accounts/urls.py View File

@ -14,6 +14,8 @@ urlpatterns = [
views.check_token, name="hc-check-token"),
url(r'^profile/$', views.profile, name="hc-profile"),
url(r'^profile/notifications/$', views.notifications, name="hc-notifications"),
url(r'^profile/badges/$', views.badges, name="hc-badges"),
url(r'^unsubscribe_reports/([\w-]+)/$',
views.unsubscribe_reports, name="hc-unsubscribe-reports"),


+ 45
- 11
hc/accounts/views.py View File

@ -169,12 +169,6 @@ def profile(request):
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.success(request, "Your settings have been updated!")
elif "invite_team_member" in request.POST:
if not profile.team_access_allowed:
return HttpResponseForbidden()
@ -213,6 +207,48 @@ def profile(request):
profile.save()
messages.success(request, "Team Name updated!")
ctx = {
"page": "profile",
"profile": profile,
"show_api_key": show_api_key
}
return render(request, "accounts/profile.html", ctx)
@login_required
def notifications(request):
profile = request.user.profile
# Switch user back to its default team
if profile.current_team_id != profile.id:
request.team = profile
profile.current_team_id = profile.id
profile.save()
if request.method == "POST":
form = ReportSettingsForm(request.POST)
if form.is_valid():
profile.reports_allowed = form.cleaned_data["reports_allowed"]
profile.save()
messages.success(request, "Your settings have been updated!")
ctx = {
"page": "profile",
"profile": profile,
}
return render(request, "accounts/notifications.html", ctx)
@login_required
def badges(request):
profile = request.user.profile
# Switch user back to its default team
if profile.current_team_id != profile.id:
request.team = profile
profile.current_team_id = profile.id
profile.save()
tags = set()
for check in Check.objects.filter(user=request.team.user):
tags.update(check.tags_list())
@ -228,11 +264,9 @@ def profile(request):
ctx = {
"page": "profile",
"badge_urls": badge_urls,
"profile": profile,
"show_api_key": show_api_key
}
return render(request, "accounts/profile.html", ctx)
return render(request, "accounts/badges.html", ctx)
@login_required
@ -286,11 +320,11 @@ def switch_team(request, target_username):
# Superuser can switch to any team.
access_ok = request.user.is_superuser
# Users can switch to teams they are members of.
# Users can switch to their own teams.
if not access_ok and other_user.id == request.user.id:
access_ok = True
# Users can switch to their own teams.
# Users can switch to teams they are members of.
if not access_ok:
for membership in request.user.member_set.all():
if membership.team.user.id == other_user.id:


+ 5
- 1
static/css/base.css View File

@ -78,4 +78,8 @@ body {
pre {
border: 0;
}
}
.nav-pills > li > a {
color: #888;
}

+ 2
- 2
static/css/bootstrap.css View File

@ -3274,8 +3274,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
.nav-pills > li.active > a,
.nav-pills > li.active > a:hover,
.nav-pills > li.active > a:focus {
color: #ffffff;
background-color: #22bc66;
color: #888888;
background-color: #eeeeee;
}
.nav-stacked > li {
float: none;


+ 2
- 2
stuff/bootstrap/variables.less View File

@ -440,8 +440,8 @@
//== Pills
@nav-pills-border-radius: @border-radius-base;
@nav-pills-active-link-hover-bg: @component-active-bg;
@nav-pills-active-link-hover-color: @component-active-color;
@nav-pills-active-link-hover-bg: #EEE;
@nav-pills-active-link-hover-color: #888;
//== Pagination


+ 63
- 0
templates/accounts/badges.html View File

@ -0,0 +1,63 @@
{% extends "base.html" %}
{% load compress staticfiles hc_extras %}
{% block title %}Account Settings - {% site_name %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<h1 class="settings-title">Settings</h1>
</div>
</div>
<div class="row">
<div class="col-sm-3">
<ul class="nav nav-pills nav-stacked">
<li><a href="{% url 'hc-profile' %}">Security</a></li>
<li><a href="{% url 'hc-notifications' %}">Notifications</a></li>
<li class="active"><a href="{% url 'hc-badges' %}">Badges</a></li>
</ul>
</div>
<div class="col-sm-9">
<div class="panel panel-default">
<div class="panel-body settings-block">
<h2 class="settings-title">Status Badges</h2>
<p id="badges-description">
healthchecks.io provides status badges for each of the tags
you have used. The badges have public, but hard-to-guess
URLs. If you wish, you can add them to your READMEs,
dashboards or status pages.
</p>
{% if badge_urls %}
<table class="badges table">
{% for badge_url in badge_urls %}
<tr>
<td>
<img src="{{ badge_url }}" alt="" />
</td>
<td>
<code>{{ badge_url }}</code>
</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>
To get started with status badges, add some tags to
your checks!
</p>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
{% compress js %}
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
{% endcompress %}
{% endblock %}

+ 58
- 0
templates/accounts/notifications.html View File

@ -0,0 +1,58 @@
{% extends "base.html" %}
{% load compress staticfiles hc_extras %}
{% block title %}Account Settings - {% site_name %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<h1 class="settings-title">Settings</h1>
</div>
{% if messages %}
<div class="col-sm-12">
{% for message in messages %}
<p class="alert alert-{{ message.tags }}">{{ message }}</p>
{% endfor %}
</div>
{% endif %}
</div>
<div class="row">
<div class="col-sm-3">
<ul class="nav nav-pills nav-stacked">
<li><a href="{% url 'hc-profile' %}">Account</a></li>
<li class="active"><a href="{% url 'hc-notifications' %}">Notifications</a></li>
<li><a href="{% url 'hc-badges' %}">Badges</a></li>
</ul>
</div>
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-body settings-block">
<h2>Monthly Reports</h2>
<form method="post">
{% csrf_token %}
<label>
<input
name="reports_allowed"
type="checkbox"
{% if profile.reports_allowed %} checked {% endif %}>
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>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
{% compress js %}
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
{% endcompress %}
{% endblock %}

+ 44
- 92
templates/accounts/profile.html View File

@ -19,26 +19,13 @@
</div>
<div class="row">
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-body settings-block">
<form method="post">
{% csrf_token %}
<h2>Monthly Reports</h2>
<label>
<input
name="reports_allowed"
type="checkbox"
{% if profile.reports_allowed %} checked {% endif %}>
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>
</div>
</div>
<div class="col-sm-3">
<ul class="nav nav-pills nav-stacked">
<li class="active"><a href="{% url 'hc-profile' %}">Account</a></li>
<li><a href="{% url 'hc-notifications' %}">Notifications</a></li>
<li><a href="{% url 'hc-badges' %}">Badges</a></li>
</ul>
</div>
<div class="col-sm-6">
@ -55,9 +42,44 @@
</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 %}
<form method="post">
<span class="icon-ok"></span>
API access is enabled.
{% csrf_token %}
<button
type="submit"
name="show_api_key"
class="btn btn-default pull-right">Show API key</button>
</form>
{% endif %}
{% else %}
<span class="icon-cancel"></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 class="panel panel-default">
<div class="panel-body settings-block">
<h2>Team Access</h2>
@ -115,77 +137,7 @@
</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="icon-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="icon-cancel"></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>
{% if badge_urls %}
<div class="row">
<div class="col-sm-12">
<div class="panel panel-default">
<div class="panel-body settings-block">
<h2 class="settings-title">Status Badges</h2>
<p id="badges-description">
Here are status badges for each of the tags you have used. The
badges have public, but hard-to-guess URLs. If you wish, you can
add them to your READMEs, dashboards or status pages.
</p>
<table class="badges table">
{% for badge_url in badge_urls %}
<tr>
<td>
<img src="{{ badge_url }}" alt="" />
</td>
<td>
<code>{{ badge_url }}</code>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
</div>
{% endif %}
<div id="revoke-api-key-modal" class="modal">
<div class="modal-dialog">


+ 2
- 2
templates/base.html View File

@ -8,8 +8,8 @@
<meta name="keywords" content="monitor cron jobs daemon background worker service cronjob monitoring crontab alert notify cronitor deadmanssnitch webhook">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href='//fonts.googleapis.com/css?family=Open+Sans:400,300,600' rel='stylesheet' type='text/css'>
{% load compress staticfiles %}
<!-- <link href='//fonts.googleapis.com/css?family=Open+Sans:400,300,600' rel='stylesheet' type='text/css'>
--> {% load compress staticfiles %}
<link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">
{% compress css %}


Loading…
Cancel
Save