@ -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.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 | |||