mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-10 23:40:11 +00:00
Email reports list checks from all teams the user has access to.
This commit is contained in:
parent
f3c6b0fb0d
commit
f611a23f0b
6 changed files with 44 additions and 23 deletions
hc
templates
|
@ -27,14 +27,14 @@ class Command(BaseCommand):
|
|||
|
||||
# Old accounts, never logged in, no team memberships
|
||||
q = User.objects
|
||||
q = q.annotate(n_teams=Count("member"))
|
||||
q = q.annotate(n_teams=Count("memberships"))
|
||||
q = q.filter(date_joined__lt=cutoff, last_login=None, n_teams=0)
|
||||
n1, _ = q.delete()
|
||||
|
||||
# Not logged in for 1 month, 0 checks, no team memberships
|
||||
q = User.objects
|
||||
q = q.annotate(n_checks=Count("check"))
|
||||
q = q.annotate(n_teams=Count("member"))
|
||||
q = q.annotate(n_teams=Count("memberships"))
|
||||
q = q.filter(last_login__lt=cutoff, n_checks=0, n_teams=0)
|
||||
n2, _ = q.delete()
|
||||
|
||||
|
|
|
@ -116,13 +116,24 @@ class Profile(models.Model):
|
|||
self.api_key = base64.urlsafe_b64encode(os.urandom(24))
|
||||
self.save()
|
||||
|
||||
def checks_from_all_teams(self):
|
||||
""" Return a queryset of checks from all teams we have access for. """
|
||||
|
||||
team_ids = set(self.user.memberships.values_list("team_id", flat=True))
|
||||
team_ids.add(self.id)
|
||||
|
||||
from hc.api.models import Check
|
||||
return Check.objects.filter(user__profile__id__in=team_ids)
|
||||
|
||||
def send_report(self, nag=False):
|
||||
# Are there any non-new checks in the account?
|
||||
q = self.user.check_set.filter(last_ping__isnull=False)
|
||||
if not q.exists():
|
||||
checks = self.checks_from_all_teams()
|
||||
|
||||
# Is there at least one check that has received a ping?
|
||||
if not checks.filter(last_ping__isnull=False).exists():
|
||||
return False
|
||||
|
||||
num_down = q.filter(status="down").count()
|
||||
# Is there at least one check that is down?
|
||||
num_down = checks.filter(status="down").count()
|
||||
if nag and num_down == 0:
|
||||
return False
|
||||
|
||||
|
@ -130,8 +141,12 @@ class Profile(models.Model):
|
|||
path = reverse("hc-unsubscribe-reports", args=[self.user.username])
|
||||
unsub_link = "%s%s?token=%s" % (settings.SITE_ROOT, path, token)
|
||||
|
||||
# Sort checks by team name, then by email, and then by creation date:
|
||||
checks = checks.order_by(
|
||||
"user__profile__team_name", "user__email", "created")
|
||||
|
||||
ctx = {
|
||||
"checks": self.user.check_set.order_by("created"),
|
||||
"checks": checks,
|
||||
"now": timezone.now(),
|
||||
"unsub_link": unsub_link,
|
||||
"notifications_url": self.notifications_url,
|
||||
|
@ -184,7 +199,7 @@ class Profile(models.Model):
|
|||
""" Set next_nag_date for all members of this team. """
|
||||
|
||||
is_owner = models.Q(id=self.id)
|
||||
is_member = models.Q(user__member__team=self)
|
||||
is_member = models.Q(user__memberships__team=self)
|
||||
q = Profile.objects.filter(is_owner | is_member)
|
||||
q = q.exclude(nag_period=NO_NAG)
|
||||
|
||||
|
@ -193,4 +208,4 @@ class Profile(models.Model):
|
|||
|
||||
class Member(models.Model):
|
||||
team = models.ForeignKey(Profile, models.CASCADE)
|
||||
user = models.ForeignKey(User, models.CASCADE)
|
||||
user = models.ForeignKey(User, models.CASCADE, related_name="memberships")
|
||||
|
|
|
@ -364,8 +364,8 @@ def unsubscribe_reports(request, username):
|
|||
@login_required
|
||||
def switch_team(request, target_username):
|
||||
try:
|
||||
other_user = User.objects.get(username=target_username)
|
||||
except User.DoesNotExist:
|
||||
target_team = Profile.objects.get(user__username=target_username)
|
||||
except Profile.DoesNotExist:
|
||||
return HttpResponseForbidden()
|
||||
|
||||
# The rules:
|
||||
|
@ -373,20 +373,17 @@ def switch_team(request, target_username):
|
|||
access_ok = request.user.is_superuser
|
||||
|
||||
# Users can switch to their own teams.
|
||||
if not access_ok and other_user.id == request.user.id:
|
||||
if not access_ok and target_team == request.profile:
|
||||
access_ok = True
|
||||
|
||||
# Users can switch to teams they are members of.
|
||||
if not access_ok:
|
||||
for membership in request.user.member_set.all():
|
||||
if membership.team.user.id == other_user.id:
|
||||
access_ok = True
|
||||
break
|
||||
access_ok = request.user.memberships.filter(team=target_team).exists()
|
||||
|
||||
if not access_ok:
|
||||
return HttpResponseForbidden()
|
||||
|
||||
request.profile.current_team = other_user.profile
|
||||
request.profile.current_team = target_team
|
||||
request.profile.save()
|
||||
|
||||
return redirect("hc-checks")
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django import template
|
||||
from django.conf import settings
|
||||
from django.utils.html import escape
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from hc.lib.date import format_duration
|
||||
|
@ -22,6 +23,11 @@ def escaped_site_name():
|
|||
return mark_safe(settings.SITE_NAME.replace(".", "<span>.</span>"))
|
||||
|
||||
|
||||
@register.filter
|
||||
def mangle_link(s):
|
||||
return mark_safe(escape(s).replace(".", "<span>.</span>"))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def site_root():
|
||||
return settings.SITE_ROOT
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
type="checkbox"
|
||||
{% if profile.reports_allowed %} checked {% endif %}>
|
||||
<span class="checkmark"></span>
|
||||
The status of checks my checks
|
||||
The status of checks in all teams I belong to
|
||||
</label>
|
||||
|
||||
<br>
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
{% load humanize hc_extras %}
|
||||
<br />
|
||||
{% regroup checks by user as groups %}
|
||||
<table style="margin: 0; width: 100%; font-size: 16px;" cellpadding="0" cellspacing="0">
|
||||
{% for group in groups %}
|
||||
<tr>
|
||||
<td style="padding: 8px; margin: 0; font-size: 12px; color: #9BA2AB; font-family: Helvetica, Arial, sans-serif;"></td>
|
||||
<td style="padding: 8px; margin: 0; font-size: 12px; color: #9BA2AB; font-family: Helvetica, Arial, sans-serif;">Name</td>
|
||||
<td class="mobile-hide" style="padding: 8px; margin: 0; font-size: 12px; color: #9BA2AB; font-family: Helvetica, Arial, sans-serif;">Last Ping</td>
|
||||
<td colspan="2" style="font-weight: bold; padding: 32px 8px 8px 8px; color: #333;">
|
||||
{{ group.grouper.profile|mangle_link }}
|
||||
</td>
|
||||
<td class="mobile-hide" style="padding: 32px 8px 8px 8px; margin: 0; font-size: 12px; color: #9BA2AB; font-family: Helvetica, Arial, sans-serif;">Last Ping</td>
|
||||
</tr>
|
||||
{% for check in checks %}
|
||||
{% for check in group.list %}
|
||||
<tr>
|
||||
<td style="border-top: 1px solid #EDEFF2; padding: 16px 8px;">
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
|
@ -65,5 +67,6 @@
|
|||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
<br />
|
Loading…
Add table
Reference in a new issue