forked from GithubBackups/healthchecks
Better welcome page.
This commit is contained in:
parent
7b2e9ead5f
commit
7db4185267
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
|
local_settings.py
|
@ -10,6 +10,7 @@ from django.http import HttpResponseBadRequest
|
|||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
|
|
||||||
from hc.accounts.forms import EmailForm
|
from hc.accounts.forms import EmailForm
|
||||||
|
from hc.api.models import Check
|
||||||
|
|
||||||
|
|
||||||
def _make_user(email):
|
def _make_user(email):
|
||||||
@ -20,6 +21,13 @@ def _make_user(email):
|
|||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
def _associate_demo_check(request, user):
|
||||||
|
if "welcome_code" in request.session:
|
||||||
|
check = Check.objects.get(code=request.session["welcome_code"])
|
||||||
|
check.user = user
|
||||||
|
check.save()
|
||||||
|
|
||||||
|
|
||||||
def login(request):
|
def login(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = EmailForm(request.POST)
|
form = EmailForm(request.POST)
|
||||||
@ -29,6 +37,7 @@ def login(request):
|
|||||||
user = User.objects.get(email=email)
|
user = User.objects.get(email=email)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
user = _make_user(email)
|
user = _make_user(email)
|
||||||
|
_associate_demo_check(request, user)
|
||||||
|
|
||||||
# We don't want to reset passwords of staff users :-)
|
# We don't want to reset passwords of staff users :-)
|
||||||
if user.is_staff:
|
if user.is_staff:
|
||||||
|
20
hc/api/migrations/0005_auto_20150630_2021.py
Normal file
20
hc/api/migrations/0005_auto_20150630_2021.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0004_auto_20150616_1319'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='check',
|
||||||
|
name='user',
|
||||||
|
field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -11,7 +11,7 @@ DEFAULT_TIMEOUT = td(days=1)
|
|||||||
class Check(models.Model):
|
class Check(models.Model):
|
||||||
name = models.CharField(max_length=100, blank=True)
|
name = models.CharField(max_length=100, blank=True)
|
||||||
code = models.UUIDField(default=uuid.uuid4, editable=False)
|
code = models.UUIDField(default=uuid.uuid4, editable=False)
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User, blank=True, null=True)
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
timeout = models.DurationField(default=DEFAULT_TIMEOUT)
|
timeout = models.DurationField(default=DEFAULT_TIMEOUT)
|
||||||
last_ping = models.DateTimeField(null=True, blank=True)
|
last_ping = models.DateTimeField(null=True, blank=True)
|
||||||
|
@ -11,4 +11,5 @@ urlpatterns = [
|
|||||||
url(r'^pricing/$', views.pricing, name="hc-pricing"),
|
url(r'^pricing/$', views.pricing, name="hc-pricing"),
|
||||||
url(r'^docs/$', views.docs, name="hc-docs"),
|
url(r'^docs/$', views.docs, name="hc-docs"),
|
||||||
url(r'^about/$', views.about, name="hc-about"),
|
url(r'^about/$', views.about, name="hc-about"),
|
||||||
|
url(r'^welcome/timer/$', views.welcome_timer, name="hc-welcome-timer"),
|
||||||
]
|
]
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.http import HttpResponseForbidden
|
from django.contrib.humanize.templatetags.humanize import naturaltime
|
||||||
|
from django.http import HttpResponse, HttpResponseForbidden
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
@ -8,7 +11,32 @@ from hc.front.forms import TimeoutForm, TIMEOUT_CHOICES
|
|||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
return render(request, "index.html", {"page": "welcome"})
|
if "welcome_code" not in request.session:
|
||||||
|
check = Check()
|
||||||
|
check.save()
|
||||||
|
code = str(check.code)
|
||||||
|
request.session["welcome_code"] = code
|
||||||
|
else:
|
||||||
|
code = request.session["welcome_code"]
|
||||||
|
check = Check.objects.get(code=code)
|
||||||
|
|
||||||
|
if check.alert_after:
|
||||||
|
duration = check.alert_after - timezone.now()
|
||||||
|
timer = int(duration.total_seconds())
|
||||||
|
timer_formatted = "%dh %dm %ds" % (timer / 3600, (timer / 60) % 60, timer % 60)
|
||||||
|
else:
|
||||||
|
timer = 0
|
||||||
|
timer_formatted = "Never"
|
||||||
|
|
||||||
|
ctx = {
|
||||||
|
"page": "welcome",
|
||||||
|
"check": check,
|
||||||
|
"timer": timer,
|
||||||
|
"timer_formatted": timer_formatted,
|
||||||
|
"ping_url": "http://healthchecks.io/ping/%s/" % check.code
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "index.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
def pricing(request):
|
def pricing(request):
|
||||||
@ -23,6 +51,24 @@ def about(request):
|
|||||||
return render(request, "about.html", {"page": "about"})
|
return render(request, "about.html", {"page": "about"})
|
||||||
|
|
||||||
|
|
||||||
|
def welcome_timer(request):
|
||||||
|
code = request.session["welcome_code"]
|
||||||
|
|
||||||
|
check = Check.objects.get(code=code)
|
||||||
|
if check.last_ping and check.alert_after:
|
||||||
|
duration = check.alert_after - timezone.now()
|
||||||
|
response = {
|
||||||
|
"last_ping": check.last_ping.isoformat(),
|
||||||
|
"last_ping_human": naturaltime(check.last_ping),
|
||||||
|
"timer": int(duration.total_seconds())
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
response = {"last_ping": None, "timer": None}
|
||||||
|
|
||||||
|
return HttpResponse(json.dumps(response),
|
||||||
|
content_type="application/javascript")
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def checks(request):
|
def checks(request):
|
||||||
|
|
||||||
|
@ -4,18 +4,20 @@ html, body {
|
|||||||
|
|
||||||
#pitch {
|
#pitch {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 2em 0 3em 0;
|
padding: 2em 0 2em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-number {
|
#pitch-subtitle {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 48px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #777;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#get-started {
|
#pitch-url {
|
||||||
|
text-align: center;
|
||||||
|
font-family: monospace;
|
||||||
|
padding-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#welcome-status, #get-started {
|
||||||
margin-top: 4em;
|
margin-top: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ $(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(".timeout-edit-cancel").click(function() {
|
$(".timeout-edit-cancel").click(function() {
|
||||||
console.log("aaa");
|
|
||||||
$(this).parents("td").addClass("inactive");
|
$(this).parents("td").addClass("inactive");
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
45
static/js/index.js
Normal file
45
static/js/index.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
$(function () {
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
|
||||||
|
var url = $("#pitch-url").text();
|
||||||
|
var lastPing = null;
|
||||||
|
var lastPingHuman = null;
|
||||||
|
|
||||||
|
$("#run-it").click(function() {
|
||||||
|
$.get(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
function checkLastPing() {
|
||||||
|
$.getJSON("/welcome/timer/", function(data) {
|
||||||
|
if (data.last_ping != lastPing) {
|
||||||
|
lastPing = data.last_ping;
|
||||||
|
$("#timer").data("timer", data.timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.last_ping_human.indexOf("seconds ago") > 0)
|
||||||
|
data.last_ping_human = "seconds ago";
|
||||||
|
|
||||||
|
if (data.last_ping_human != lastPingHuman) {
|
||||||
|
lastPingHuman = data.last_ping_human;
|
||||||
|
$("#last-ping").text(lastPingHuman);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTimer() {
|
||||||
|
var timer = parseInt($("#timer").data("timer"));
|
||||||
|
if (timer == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var s = timer % 60;
|
||||||
|
var m = parseInt(timer / 60) % 60;
|
||||||
|
var h = parseInt(timer / 3600);
|
||||||
|
$("#timer").text(h + "h " + m + "m " + s + "s");
|
||||||
|
|
||||||
|
$("#timer").data("timer", timer - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(checkLastPing, 3000);
|
||||||
|
setInterval(updateTimer, 1000);
|
||||||
|
|
||||||
|
});
|
@ -9,15 +9,22 @@
|
|||||||
Hello, my name is Pēteris Caune, I live in Riga, Latvia and do programming for living.
|
Hello, my name is Pēteris Caune, I live in Riga, Latvia and do programming for living.
|
||||||
You can contact me <a href="mailto:cuu508@gmail.com">via email</a>.
|
You can contact me <a href="mailto:cuu508@gmail.com">via email</a>.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Code is on
|
||||||
|
<a href="https://github.com/healthchecks/healthchecks">GitHub</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3>Reliability Guarantees</h3>
|
<h3>Reliability Guarantees</h3>
|
||||||
<p>
|
<p>
|
||||||
Health Checks is currently at a very early stage as you can probably tell.
|
Health Checks is currently at a very early stage as you can probably tell.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The service is currently run on single $5 Digital Ocean box. The service
|
The service is currently run on single $5 Digital Ocean box.
|
||||||
can and will have ocassional outages. User data should be safe however,
|
It can and will have ocassional outages. <!-- User data should be safe however,
|
||||||
as we are doing regular database backups to Amazon S3.
|
as we are doing regular database backups to Amazon S3. -->
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
If all this does not sound very inspiring,
|
If all this does not sound very inspiring,
|
||||||
there are also alternative services:
|
there are also alternative services:
|
||||||
|
@ -57,6 +57,6 @@
|
|||||||
|
|
||||||
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
|
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
|
||||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||||
<script src="{% static 'js/checks.js' %}"></script>
|
{% block scripts %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load humanize %}
|
{% load humanize staticfiles %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -47,7 +47,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
<td class="url-cell">
|
<td class="url-cell">
|
||||||
<code>https://healthchecks.io{% url 'hc-ping' check.code %}</code>
|
<code>http://healthchecks.io{% url 'hc-ping' check.code %}</code>
|
||||||
</td>
|
</td>
|
||||||
<td class="timeout-cell inactive">
|
<td class="timeout-cell inactive">
|
||||||
<div class="timeout-dialog popover bottom">
|
<div class="timeout-dialog popover bottom">
|
||||||
@ -116,4 +116,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script src="{% static 'js/checks.js' %}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
5
templates/front/snippets/bash.txt
Normal file
5
templates/front/snippets/bash.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# using curl:
|
||||||
|
curl {{ ping_url }}
|
||||||
|
|
||||||
|
# using wget:
|
||||||
|
wget {{ ping_url }} -O /dev/null
|
3
templates/front/snippets/browser.txt
Normal file
3
templates/front/snippets/browser.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', '{{ ping_url }}', true);
|
||||||
|
xhr.send(null);
|
2
templates/front/snippets/crontab.txt
Normal file
2
templates/front/snippets/crontab.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# m h dom mon dow command
|
||||||
|
8 6 * * * /home/user/tasks/backup_all.sh && curl {{ ping_url }}
|
7
templates/front/snippets/python.txt
Normal file
7
templates/front/snippets/python.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
>>> # using urllib2:
|
||||||
|
>>> import urllib2
|
||||||
|
>>> urllib2.urlopen("{{ ping_url }}")
|
||||||
|
|
||||||
|
>>> # using requests:
|
||||||
|
>>> import requests
|
||||||
|
>>> requests.get("{{ ping_url }}")
|
@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load staticfiles %}
|
{% load humanize staticfiles %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -9,47 +9,89 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-12">
|
||||||
<p class="step-number">1</p>
|
<h2 id="pitch-subtitle">Here's an unique ping address for you:</h2>
|
||||||
<p>
|
<div id="pitch-url">{{ ping_url }}</div>
|
||||||
Create a ping URL on healtchecks.io
|
</div>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<p class="step-number">2</p>
|
|
||||||
Add a single line at the bottom of your batch processing task:
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li role="presentation" class="active">
|
<li class="active">
|
||||||
<a href="#bash" aria-controls="home" role="tab" data-toggle="tab">Bash</a>
|
<a href="#crontab" data-toggle="tab">Crontab</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation">
|
<li>
|
||||||
<a href="#python" aria-controls="profile" role="tab" data-toggle="tab">Python</a>
|
<a href="#bash" data-toggle="tab">Bash</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#python" data-toggle="tab">Python</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#node" data-toggle="tab">Node.js</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#php" data-toggle="tab">PHP</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#browser" data-toggle="tab">Browser</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div role="tabpanel" class="tab-pane active" id="bash">
|
<div role="tabpanel" class="tab-pane active" id="crontab">
|
||||||
<pre>wget https://healthchecks.io/ping/b2012751-c542-4deb-b054-ff51322102b9/ -O /dev/null
|
<pre>{% include "front/snippets/crontab.txt" %}</pre>
|
||||||
</pre>
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane" id="bash">
|
||||||
|
<pre>{% include "front/snippets/bash.txt" %}</pre>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="python">
|
<div role="tabpanel" class="tab-pane" id="python">
|
||||||
<pre>
|
<pre>{% include "front/snippets/python.txt" %}</pre>
|
||||||
>>> import urllib2
|
</div>
|
||||||
>>> urllib2.urlopen("https://healthchecks.io/ping/b2012751-c542-4deb-b054-ff51322102b9/")
|
<div class="tab-pane" id="browser">
|
||||||
|
<pre>{% include "front/snippets/browser.txt" %}</pre>
|
||||||
</pre>
|
<div class="welcome-browser-controls">
|
||||||
|
<button id="run-it" class="btn btn-default">Run It!</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
|
||||||
<p class="step-number">3</p>
|
|
||||||
Receive an email from healthchecks.io when the task has an issue
|
<div id="welcome-status" class="col-sm-6">
|
||||||
|
<h2>Status
|
||||||
|
<small>{{ check.code }}</small>
|
||||||
|
</h2>
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th>Last ping</th>
|
||||||
|
<th>Frequency</th>
|
||||||
|
<th>Alert in</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="last-ping">
|
||||||
|
{% if check.last_ping %}
|
||||||
|
{{ check.last_ping|naturaltime }}
|
||||||
|
{% else %}
|
||||||
|
Never
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>1 day
|
||||||
|
<span
|
||||||
|
class="glyphicon glyphicon-question-sign"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="Sign in to change frequency"></span>
|
||||||
|
</td>
|
||||||
|
<td id="timer" data-timer="{{ timer}}">
|
||||||
|
{{ timer_formatted }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="get-started" class="col-sm-6">
|
||||||
<div id="get-started" class="col-sm-6 col-sm-offset-3">
|
<h3>E-mail Address to Receive Alerts:</h3>
|
||||||
<h3>E-mail Address to Receive Notifications:</h3>
|
|
||||||
<form action="{% url 'hc-login' %}" method="post">
|
<form action="{% url 'hc-login' %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
@ -75,4 +117,8 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script src="{% static 'js/index.js' %}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user