@ -9,7 +9,7 @@ class BadgesTestCase(BaseTestCase): | |||
Check.objects.create(project=self.bobs_project, tags="bobs-tag") | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get("/accounts/profile/badges/") | |||
r = self.client.get("/projects/%s/badges/" % self.project.code) | |||
self.assertContains(r, "foo.svg") | |||
self.assertContains(r, "a-B_1.svg") | |||
@ -27,6 +27,6 @@ class BadgesTestCase(BaseTestCase): | |||
self.project.save() | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get("/accounts/profile/badges/") | |||
r = self.client.get("/projects/%s/badges/" % self.project.code) | |||
self.assertContains(r, "badge/alices-badge-key/") | |||
self.assertContains(r, "badge/alices-badge-key/") |
@ -5,17 +5,22 @@ from hc.test import BaseTestCase | |||
from hc.accounts.models import Member | |||
class ProfileTestCase(BaseTestCase): | |||
class ProjectTestCase(BaseTestCase): | |||
def setUp(self): | |||
super(ProfileTestCase, self).setUp() | |||
super(ProjectTestCase, self).setUp() | |||
self.url = "/projects/%s/settings/" % self.project.code | |||
def test_it_checks_access(self): | |||
self.client.login(username="bob@example.org", password="password") | |||
self.client.login(username="charlie@example.org", password="password") | |||
r = self.client.get(self.url) | |||
self.assertEqual(r.status_code, 404) | |||
def test_it_allows_team_access(self): | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.get(self.url) | |||
self.assertContains(r, "Change Project Name") | |||
def test_it_shows_api_keys(self): | |||
self.project.api_key_readonly = "R" * 32 | |||
self.project.save() | |||
@ -78,6 +83,13 @@ class ProfileTestCase(BaseTestCase): | |||
" Alice's Project on %s" % settings.SITE_NAME) | |||
self.assertEqual(mail.outbox[0].subject, subj) | |||
def test_it_requires_owner_to_add_team_member(self): | |||
self.client.login(username="[email protected]", password="password") | |||
form = {"invite_team_member": "1", "email": "[email protected]"} | |||
r = self.client.post(self.url, form) | |||
self.assertEqual(r.status_code, 403) | |||
def test_it_checks_team_size(self): | |||
self.profile.team_limit = 0 | |||
self.profile.save() | |||
@ -100,6 +112,13 @@ class ProfileTestCase(BaseTestCase): | |||
self.bobs_profile.refresh_from_db() | |||
self.assertEqual(self.bobs_profile.current_project, None) | |||
def test_it_requires_owner_to_remove_team_member(self): | |||
self.client.login(username="[email protected]", password="password") | |||
form = {"remove_team_member": "1", "email": "[email protected]"} | |||
r = self.client.post(self.url, form) | |||
self.assertEqual(r.status_code, 403) | |||
def test_it_checks_membership_when_removing_team_member(self): | |||
self.client.login(username="[email protected]", password="password") | |||
@ -1,93 +0,0 @@ | |||
{% extends "base.html" %} | |||
{% load compress static hc_extras %} | |||
{% block title %}Account Settings - {% site_name %}{% endblock %} | |||
{% block content %} | |||
<div class="row"> | |||
<div class="col-sm-12"> | |||
<h1 class="settings-title">Settings <small>{{ request.user.email }}</small></h1> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-2"> | |||
<ul class="nav nav-pills nav-stacked"> | |||
<li><a href="{% url 'hc-profile' %}">Account</a></li> | |||
{% if show_pricing %} | |||
<li><a href="{% url 'hc-billing' %}">Billing</a></li> | |||
{% endif %} | |||
<li><a href="{% url 'hc-notifications' %}">Email Reports</a></li> | |||
<li class="active"><a href="{% url 'hc-badges' %}">Badges</a></li> | |||
</ul> | |||
</div> | |||
<div class="col-sm-10"> | |||
<div class="panel panel-default"> | |||
<div class="panel-body settings-block"> | |||
<h2 class="settings-title">Status Badges</h2> | |||
<p id="badges-description"> | |||
{% site_name %} provides status badges for each of the tags | |||
you have used. Additionally, the "{% site_name %}" | |||
badge shows the overall status of all checks in a | |||
project. The badges have public, but hard-to-guess | |||
URLs. You can use them in your READMEs, | |||
dashboards or status pages. | |||
</p> | |||
<div id="b-format" class="btn-group" data-toggle="buttons"> | |||
<label id="show-svg" class="btn btn-default active"> | |||
<input type="radio" autocomplete="off" checked> SVG | |||
</label> | |||
<label id="show-json" class="btn btn-default"> | |||
<input type="radio" autocomplete="off"> JSON | |||
</label> | |||
</div> | |||
<table id="badges-svg" class="badges table"> | |||
{% for badge_set in badges %} | |||
<tr> | |||
<th colspan="2">{{ badge_set.project }}</th> | |||
</tr> | |||
{% for urldict in badge_set.urls %} | |||
<tr> | |||
<td> | |||
<img src="{{ urldict.svg }}" alt="" /> | |||
</td> | |||
<td class="svg-url"> | |||
<code>{{ urldict.svg }}</code> | |||
</td> | |||
</tr> | |||
{% endfor %} | |||
{% endfor %} | |||
</table> | |||
<table id="badges-json" class="badges table"> | |||
{% for badge_set in badges %} | |||
<tr> | |||
<th colspan="2">{{ badge_set.project }}</th> | |||
</tr> | |||
{% for urldict in badge_set.urls %} | |||
<tr> | |||
<td class="json-response" data-url="{{ urldict.json }}"> | |||
</td> | |||
<td class="json-url"> | |||
<code>{{ urldict.json }}</code> | |||
</td> | |||
</tr> | |||
{% endfor %} | |||
{% endfor %} | |||
</table> | |||
</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> | |||
<script src="{% static 'js/badges.js' %}"></script> | |||
{% endcompress %} | |||
{% endblock %} |
@ -0,0 +1,169 @@ | |||
<!DOCTYPE html>{% load compress staticfiles hc_extras %} | |||
<html lang="en"> | |||
<head> | |||
<meta charset="utf-8"> | |||
<title>{% block title %}{% site_name %} - Monitor Cron Jobs. Get Notified When Your Cron Jobs Fail{% endblock %}</title> | |||
{% block description %} | |||
<meta name="description" content="Monitor and Get Notified When Your Cron Jobs Fail. Free alternative to Cronitor and Dead Man's Snitch."> | |||
{% endblock %} | |||
{% block keywords %} | |||
<meta name="keywords" content="healthchecks, monitor cron jobs, cron monitoring, cron job syntax, health checks, crontab cheat sheet, crontab monitoring, cronjob monitoring, cron dashboard"> | |||
{% endblock %} | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||
<meta name="apple-mobile-web-app-title" content="{% site_name %}"> | |||
<meta name="application-name" content="{% site_name %}"> | |||
<link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}"> | |||
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'img/apple-touch-180.png' %}"> | |||
{% compress css %} | |||
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/icomoon.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/nouislider.min.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/nouislider.pips.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/bootstrap-select.min.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/snippet-copy.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/base.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/docs.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/docs_cron.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/welcome.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/my_checks.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/my_checks_desktop.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/pricing.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/syntax.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/channels.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/channel_checks.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/details.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/log.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/add_pushover.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/add_webhook.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/settings.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/ping_details.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/profile.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/checkbox.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/radio.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/billing.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/login.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/projects.css' %}" type="text/css"> | |||
<link rel="stylesheet" href="{% static 'css/add_project_modal.css' %}" type="text/css"> | |||
{% endcompress %} | |||
</head> | |||
<body class="page-{{ page }}"> | |||
{% debug_warning %} | |||
<nav class="navbar navbar-default"> | |||
<div class="container{% if page == "checks" or page == "details" %}-fluid{% endif %}"> | |||
<div class="navbar-header"> | |||
<button | |||
type="button" | |||
class="navbar-toggle collapsed" | |||
data-toggle="collapse" | |||
data-target="#navbar" | |||
aria-expanded="false" | |||
aria-controls="navbar"> | |||
<span class="sr-only">Toggle navigation</span> | |||
<span class="icon-bar"></span> | |||
<span class="icon-bar"></span> | |||
<span class="icon-bar"></span> | |||
</button> | |||
<a class="navbar-brand" href="/"> | |||
{{ project }} | |||
<span class="caret"></span> | |||
</a> | |||
</div> | |||
<div id="navbar" class="navbar-collapse collapse"> | |||
<ul id="nav-main-sections" class="nav navbar-nav"> | |||
{% if project %} | |||
<li {% if page == 'checks' %} class="active" {% endif %}> | |||
<a href="{% url 'hc-checks' project.code %}">Checks</a> | |||
</li> | |||
<li {% if page == 'channels' %} class="active" {% endif %}> | |||
<a href="{% url 'hc-channels' %}">Integrations</a> | |||
</li> | |||
<li {% if page == 'badges' %} class="active" {% endif %}> | |||
<a href="{% url 'hc-badges' project.code %}">Badges</a> | |||
</li> | |||
<li {% if page == 'project' %} class="active" {% endif %}> | |||
<a href="{% url 'hc-project-settings' project.code %}">Settings</a> | |||
</li> | |||
{% endif %} | |||
</ul> | |||
{% if request.user.is_authenticated %} | |||
<ul id="global-links" class="nav navbar-nav navbar-right"> | |||
{% if show_pricing %} | |||
<li {% if page == 'pricing' %} class="active" {% endif %}> | |||
<a href="{% url 'hc-pricing' %}">Pricing</a> | |||
</li> | |||
{% endif %} | |||
<li {% if page == 'docs' %} class="active" {% endif %}> | |||
<a href="{% url 'hc-docs' %}">Docs</a> | |||
</li> | |||
<li class="dropdown"> | |||
<a id="nav-email" href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"> | |||
Account | |||
<span class="caret"></span> | |||
</a> | |||
<ul class="dropdown-menu"> | |||
<li class="dropdown-header">Projects</li> | |||
{% for project in request.profile.annotated_projects %} | |||
<li class="project-item"> | |||
<a href="{% url 'hc-checks' project.code %}"> | |||
<span class="name">{{ project }}</span> | |||
{% if project.n_down %} | |||
<span class="badge badge-down pull-right"> | |||
{{ project.n_down }} | |||
</span> | |||
{% endif %} | |||
</a> | |||
</li> | |||
{% endfor %} | |||
<li role="separator" class="divider"></li> | |||
<li><a href="{% url 'hc-profile' %}">Account Settings</a></li> | |||
<li><a href="{% url 'hc-logout' %}">Log Out</a></li> | |||
</ul> | |||
</li> | |||
</ul> | |||
{% elif page != "login" %} | |||
<ul class="nav navbar-nav navbar-right"> | |||
<li><a href="{% url 'hc-login' %}">Sign In</a></li> | |||
</ul> | |||
{% endif %} | |||
</div> | |||
</div> | |||
</nav> | |||
{% block containers %} | |||
<div class="container{% if page == "checks" or page == "details" %}-fluid{% endif %}"> | |||
{% block content %}{% endblock %} | |||
</div> | |||
{% endblock %} | |||
<footer class="footer"> | |||
<div class="container{% if page == "checks" or page == "details" %}-fluid{% endif %}"> | |||
<ul> | |||
<li> | |||
Powered by Healthchecks open-source project | |||
(<a href="https://github.com/healthchecks/healthchecks">github</a>, | |||
<a href="https://healthchecks.io">healthchecks.io</a>) | |||
</li> | |||
</ul> | |||
</div> | |||
</footer> | |||
{% 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 %} | |||
</body> | |||
</html> |
@ -0,0 +1,86 @@ | |||
{% extends "base_project.html" %} | |||
{% load compress static hc_extras %} | |||
{% block title %}Account Settings - {% site_name %}{% endblock %} | |||
{% block content %} | |||
<div class="row"> | |||
<div class="col-sm-10"> | |||
<h1>Status Badges</h1> | |||
<p id="badges-description"> | |||
{% site_name %} provides status badges for each of the tags | |||
you have used. Additionally, the "{% site_name %}" | |||
badge shows the overall status of all checks in a | |||
project. The badges have public, but hard-to-guess | |||
URLs. You can use them in your READMEs, | |||
dashboards or status pages. | |||
</p> | |||
<div id="b-format" class="btn-group" data-toggle="buttons"> | |||
<label id="show-svg" class="btn btn-default active"> | |||
<input type="radio" autocomplete="off" checked> SVG | |||
</label> | |||
<label id="show-json" class="btn btn-default"> | |||
<input type="radio" autocomplete="off"> JSON | |||
</label> | |||
</div> | |||
<table id="badges-svg" class="badges table"> | |||
{% if have_tags %} | |||
<tr> | |||
<th colspan="2">Tags</th> | |||
</tr> | |||
{% endif %} | |||
{% for urldict in badges %} | |||
{% if urldict.tag == "*" %} | |||
<tr> | |||
<th colspan="2">Overall Status</th> | |||
</tr> | |||
{% endif %} | |||
<tr> | |||
<td> | |||
<img src="{{ urldict.svg }}" alt="" /> | |||
</td> | |||
<td class="svg-url"> | |||
<code>{{ urldict.svg }}</code> | |||
</td> | |||
</tr> | |||
{% endfor %} | |||
</table> | |||
<table id="badges-json" class="badges table"> | |||
{% if have_tags %} | |||
<tr> | |||
<th colspan="2">Tags</th> | |||
</tr> | |||
{% endif %} | |||
{% for urldict in badges %} | |||
{% if urldict.tag == "*" %} | |||
<tr> | |||
<th colspan="2">Overall Status</th> | |||
</tr> | |||
{% endif %} | |||
<tr> | |||
<td class="json-response" data-url="{{ urldict.json }}"> | |||
</td> | |||
<td class="json-url"> | |||
<code>{{ urldict.json }}</code> | |||
</td> | |||
</tr> | |||
{% endfor %} | |||
</table> | |||
</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> | |||
<script src="{% static 'js/badges.js' %}"></script> | |||
{% endcompress %} | |||
{% endblock %} |