@ -0,0 +1,14 @@ | |||||
from django.core.management.base import BaseCommand | |||||
from django.contrib.auth.models import User | |||||
from hc.accounts.models import Profile | |||||
class Command(BaseCommand): | |||||
help = 'Make sure all users have profiles' | |||||
def handle(self, *args, **options): | |||||
for user in User.objects.all(): | |||||
# this should create profile object if it does not exist | |||||
Profile.objects.for_user(user) | |||||
print("Done.") |
@ -0,0 +1,24 @@ | |||||
# -*- coding: utf-8 -*- | |||||
from __future__ import unicode_literals | |||||
from django.db import migrations, models | |||||
from django.conf import settings | |||||
class Migration(migrations.Migration): | |||||
dependencies = [ | |||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |||||
] | |||||
operations = [ | |||||
migrations.CreateModel( | |||||
name='Profile', | |||||
fields=[ | |||||
('id', models.AutoField(auto_created=True, serialize=False, verbose_name='ID', primary_key=True)), | |||||
('next_report_date', models.DateTimeField(null=True, blank=True)), | |||||
('reports_allowed', models.BooleanField(default=True)), | |||||
('user', models.OneToOneField(blank=True, to=settings.AUTH_USER_MODEL, null=True)), | |||||
], | |||||
), | |||||
] |
@ -1,3 +1,47 @@ | |||||
from datetime import timedelta | |||||
from django.conf import settings | |||||
from django.contrib.auth.models import User | |||||
from django.core import signing | |||||
from django.core.urlresolvers import reverse | |||||
from django.db import models | from django.db import models | ||||
from django.utils import timezone | |||||
from hc.lib import emails | |||||
import uuid | |||||
# Create your models here. | |||||
class ProfileManager(models.Manager): | |||||
def for_user(self, user): | |||||
try: | |||||
profile = self.get(user_id=user.id) | |||||
except Profile.DoesNotExist: | |||||
profile = Profile(user=user) | |||||
profile.save() | |||||
return profile | |||||
class Profile(models.Model): | |||||
user = models.OneToOneField(User, blank=True, null=True) | |||||
next_report_date = models.DateTimeField(null=True, blank=True) | |||||
reports_allowed = models.BooleanField(default=True) | |||||
objects = ProfileManager() | |||||
def send_report(self): | |||||
# reset next report date first: | |||||
now = timezone.now() | |||||
self.next_report_date = now + timedelta(days=30) | |||||
self.save() | |||||
token = signing.Signer().sign(uuid.uuid4()) | |||||
path = reverse("hc-unsubscribe-reports", args=[self.user.username]) | |||||
unsub_link = "%s%s?token=%s" % (settings.SITE_ROOT, path, token) | |||||
ctx = { | |||||
"checks": self.user.check_set.order_by("created"), | |||||
"now": now, | |||||
"unsub_link": unsub_link | |||||
} | |||||
emails.report(self.user.email, ctx) |
@ -0,0 +1,12 @@ | |||||
#settings-title { | |||||
padding-bottom: 24px; | |||||
} | |||||
.settings-block { | |||||
padding: 24px; | |||||
} | |||||
.settings-block h2 { | |||||
margin: 0; | |||||
padding-bottom: 24px; | |||||
} |
@ -0,0 +1,44 @@ | |||||
{% extends "base.html" %} | |||||
{% load compress staticfiles %} | |||||
{% block title %}Account Settings - healthchecks.io{% endblock %} | |||||
{% block content %} | |||||
<div class="row"> | |||||
<div class="col-sm-12"> | |||||
<h1 id="settings-title">Settings</h1> | |||||
</div> | |||||
{% if messages %} | |||||
<div class="col-sm-12"> | |||||
{% for message in messages %} | |||||
<p class="alert alert-success">{{ message }}</p> | |||||
{% endfor %} | |||||
</div> | |||||
{% endif %} | |||||
</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 | |||||
type="submit" | |||||
class="btn btn-default pull-right">Save</button> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{% endblock %} | |||||
@ -0,0 +1,12 @@ | |||||
{% extends "base.html" %} | |||||
{% block content %} | |||||
<div class="row"> | |||||
<div class="col-sm-6 col-sm-offset-3"> | |||||
<div class="hc-dialog"> | |||||
<h1>You have been unsubscribed</h1> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{% endblock %} |
@ -0,0 +1,102 @@ | |||||
{% load humanize hc_extras %} | |||||
<style> | |||||
th { | |||||
text-align: left; | |||||
padding: 8px; | |||||
} | |||||
td { | |||||
border-top: 1px solid #ddd; | |||||
padding: 8px; | |||||
} | |||||
.badge { | |||||
font-size: 10px; | |||||
color: white; | |||||
padding: 4px; | |||||
font-family: sans; | |||||
} | |||||
.new { background: #AAA; } | |||||
.paused { background: #AAA; } | |||||
.up { background: #5cb85c; } | |||||
.grace { background: #f0ad4e; } | |||||
.down { background: #d9534f; } | |||||
.unnamed { | |||||
color: #888; | |||||
font-style: italic; | |||||
} | |||||
</style> | |||||
<p>Hello,</p> | |||||
<p>This is a monthly report sent by <a href="https://healthchecks.io">healthchecks.io</a>.</p> | |||||
<table> | |||||
<tr> | |||||
<th></th> | |||||
<th>Name</th> | |||||
<th>URL</th> | |||||
<th>Period</th> | |||||
<th>Last Ping</th> | |||||
</tr> | |||||
{% for check in checks %} | |||||
<tr> | |||||
<td> | |||||
{% if check.get_status == "new" %} | |||||
<span class="badge new">NEW</span> | |||||
{% elif check.get_status == "up" %} | |||||
<span class="badge up">UP</span> | |||||
{% elif check.get_status == "grace" %} | |||||
<span class="badge grace">LATE</span> | |||||
{% elif check.get_status == "down" %} | |||||
<span class="badge down">DOWN</span> | |||||
{% elif check.get_status == "paused" %} | |||||
<span class="badge paused">PAUSED</span> | |||||
{% endif %} | |||||
</td> | |||||
<td> | |||||
{% if check.name %} | |||||
{{ check.name }} | |||||
{% else %} | |||||
<span class="unnamed">unnamed</span> | |||||
{% endif %} | |||||
{% if check.tags %} | |||||
<br /> | |||||
<small>{{ check.tags }}</small> | |||||
{% endif %} | |||||
</td> | |||||
<td class="url-cell"> | |||||
<code>{{ check.url }}</code> | |||||
</td> | |||||
<td> | |||||
{{ check.timeout|hc_duration }} | |||||
</td> | |||||
<td> | |||||
{% if check.last_ping %} | |||||
{{ check.last_ping|naturaltime }} | |||||
{% else %} | |||||
Never | |||||
{% endif %} | |||||
</td> | |||||
</tr> | |||||
{% endfor %} | |||||
</table> | |||||
<p><strong>Just one more thing to check:</strong> | |||||
Do you have more cron jobs, | |||||
not yet on this list, that would benefit from monitoring? | |||||
Get the ball rolling by adding one more!</p> | |||||
<p> | |||||
--<br /> | |||||
Regards,<br /> | |||||
healthchecks.io | |||||
</p> | |||||
<p> | |||||
<a href="{{ unsub_link }}">Unsubscribe from future monthly reports</a> | |||||
</p> |
@ -0,0 +1,2 @@ | |||||
Monthly Report | |||||