diff --git a/.gitignore b/.gitignore index c18dd8d8..99c06936 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ __pycache__/ +local_settings.py \ No newline at end of file diff --git a/hc/accounts/views.py b/hc/accounts/views.py index 1fa776cf..5a789087 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -10,6 +10,7 @@ from django.http import HttpResponseBadRequest from django.shortcuts import redirect, render from hc.accounts.forms import EmailForm +from hc.api.models import Check def _make_user(email): @@ -20,6 +21,13 @@ def _make_user(email): 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): if request.method == 'POST': form = EmailForm(request.POST) @@ -29,6 +37,7 @@ def login(request): user = User.objects.get(email=email) except User.DoesNotExist: user = _make_user(email) + _associate_demo_check(request, user) # We don't want to reset passwords of staff users :-) if user.is_staff: diff --git a/hc/api/migrations/0005_auto_20150630_2021.py b/hc/api/migrations/0005_auto_20150630_2021.py new file mode 100644 index 00000000..02620d22 --- /dev/null +++ b/hc/api/migrations/0005_auto_20150630_2021.py @@ -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), + ), + ] diff --git a/hc/api/models.py b/hc/api/models.py index 31b9ff89..e5b2e53b 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -11,7 +11,7 @@ DEFAULT_TIMEOUT = td(days=1) class Check(models.Model): name = models.CharField(max_length=100, blank=True) 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) timeout = models.DurationField(default=DEFAULT_TIMEOUT) last_ping = models.DateTimeField(null=True, blank=True) diff --git a/hc/front/urls.py b/hc/front/urls.py index c7f2fc58..8a11152d 100644 --- a/hc/front/urls.py +++ b/hc/front/urls.py @@ -11,4 +11,5 @@ urlpatterns = [ url(r'^pricing/$', views.pricing, name="hc-pricing"), url(r'^docs/$', views.docs, name="hc-docs"), url(r'^about/$', views.about, name="hc-about"), + url(r'^welcome/timer/$', views.welcome_timer, name="hc-welcome-timer"), ] diff --git a/hc/front/views.py b/hc/front/views.py index 4b47e3e8..10cc3f61 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -1,5 +1,8 @@ +import json + 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.utils import timezone @@ -8,7 +11,32 @@ from hc.front.forms import TimeoutForm, TIMEOUT_CHOICES 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): @@ -23,6 +51,24 @@ def about(request): 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 def checks(request): diff --git a/static/css/style.css b/static/css/style.css index 1c3069e3..be8bca50 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -4,18 +4,20 @@ html, body { #pitch { text-align: center; - padding: 2em 0 3em 0; + padding: 2em 0 2em 0; } -.step-number { +#pitch-subtitle { text-align: center; - font-size: 48px; - font-weight: bold; - color: #777; +} +#pitch-url { + text-align: center; + font-family: monospace; + padding-bottom: 2em; } -#get-started { +#welcome-status, #get-started { margin-top: 4em; } diff --git a/static/js/checks.js b/static/js/checks.js index a22a7c24..eca84fe1 100644 --- a/static/js/checks.js +++ b/static/js/checks.js @@ -34,7 +34,6 @@ $(function () { }); $(".timeout-edit-cancel").click(function() { - console.log("aaa"); $(this).parents("td").addClass("inactive"); return false; }); diff --git a/static/js/index.js b/static/js/index.js new file mode 100644 index 00000000..0c4d4105 --- /dev/null +++ b/static/js/index.js @@ -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); + +}); \ No newline at end of file diff --git a/templates/about.html b/templates/about.html index bd0e7902..60acf33d 100644 --- a/templates/about.html +++ b/templates/about.html @@ -9,15 +9,22 @@ Hello, my name is PÄ“teris Caune, I live in Riga, Latvia and do programming for living. You can contact me via email.

+

+ Code is on + GitHub. +

+

Reliability Guarantees

Health Checks is currently at a very early stage as you can probably tell.

- The service is currently run on single $5 Digital Ocean box. The service - can and will have ocassional outages. User data should be safe however, - as we are doing regular database backups to Amazon S3. + The service is currently run on single $5 Digital Ocean box. + It can and will have ocassional outages.

+ +

If all this does not sound very inspiring, there are also alternative services: diff --git a/templates/base.html b/templates/base.html index 3ea5e167..990c083b 100644 --- a/templates/base.html +++ b/templates/base.html @@ -57,6 +57,6 @@ - + {% block scripts %}{% endblock %} diff --git a/templates/front/index.html b/templates/front/index.html index 62dfbca0..b7c8c45b 100644 --- a/templates/front/index.html +++ b/templates/front/index.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load humanize %} +{% load humanize staticfiles %} {% block content %}

@@ -47,7 +47,7 @@ - https://healthchecks.io{% url 'hc-ping' check.code %} + http://healthchecks.io{% url 'hc-ping' check.code %}
@@ -116,4 +116,8 @@ -{% endblock %} \ No newline at end of file +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/front/snippets/bash.txt b/templates/front/snippets/bash.txt new file mode 100644 index 00000000..808cea73 --- /dev/null +++ b/templates/front/snippets/bash.txt @@ -0,0 +1,5 @@ +# using curl: +curl {{ ping_url }} + +# using wget: +wget {{ ping_url }} -O /dev/null \ No newline at end of file diff --git a/templates/front/snippets/browser.txt b/templates/front/snippets/browser.txt new file mode 100644 index 00000000..9b03dd28 --- /dev/null +++ b/templates/front/snippets/browser.txt @@ -0,0 +1,3 @@ +var xhr = new XMLHttpRequest(); +xhr.open('GET', '{{ ping_url }}', true); +xhr.send(null); \ No newline at end of file diff --git a/templates/front/snippets/crontab.txt b/templates/front/snippets/crontab.txt new file mode 100644 index 00000000..f423a6bc --- /dev/null +++ b/templates/front/snippets/crontab.txt @@ -0,0 +1,2 @@ +# m h dom mon dow command + 8 6 * * * /home/user/tasks/backup_all.sh && curl {{ ping_url }} \ No newline at end of file diff --git a/templates/front/snippets/python.txt b/templates/front/snippets/python.txt new file mode 100644 index 00000000..998c6719 --- /dev/null +++ b/templates/front/snippets/python.txt @@ -0,0 +1,7 @@ +>>> # using urllib2: +>>> import urllib2 +>>> urllib2.urlopen("{{ ping_url }}") + +>>> # using requests: +>>> import requests +>>> requests.get("{{ ping_url }}") \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index faefafc6..84a0dc56 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load humanize staticfiles %} {% block content %}
@@ -9,47 +9,89 @@
-
-

1

-

- Create a ping URL on healtchecks.io -

-
-
-

2

- Add a single line at the bottom of your batch processing task: +
+

Here's an unique ping address for you:

+
{{ ping_url }}
+
+
+ +
+
-
-
wget https://healthchecks.io/ping/b2012751-c542-4deb-b054-ff51322102b9/ -O /dev/null
-                
+
+
{% include "front/snippets/crontab.txt" %}
+
+
+
{% include "front/snippets/bash.txt" %}
-
->>> import urllib2
->>> urllib2.urlopen("https://healthchecks.io/ping/b2012751-c542-4deb-b054-ff51322102b9/")
-
-                
+
{% include "front/snippets/python.txt" %}
+
+
+
{% include "front/snippets/browser.txt" %}
+
+ +
-
-

3

- Receive an email from healthchecks.io when the task has an issue -
-
-

E-mail Address to Receive Notifications:

+
+

Status + {{ check.code }} +

+ + + + + + + + + + + +
Last pingFrequencyAlert in
+ {% if check.last_ping %} + {{ check.last_ping|naturaltime }} + {% else %} + Never + {% endif %} + 1 day + + + {{ timer_formatted }} +
+
+ +
+

E-mail Address to Receive Alerts:

{% csrf_token %} @@ -75,4 +117,8 @@
-{% endblock %} \ No newline at end of file +{% endblock %} + +{% block scripts %} + +{% endblock %}