diff --git a/hc/accounts/management/commands/pruneusers.py b/hc/accounts/management/commands/pruneusers.py
index d17f8f12..b45063c2 100644
--- a/hc/accounts/management/commands/pruneusers.py
+++ b/hc/accounts/management/commands/pruneusers.py
@@ -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()
diff --git a/hc/accounts/models.py b/hc/accounts/models.py
index f07235b9..c41bc8a4 100644
--- a/hc/accounts/models.py
+++ b/hc/accounts/models.py
@@ -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")
diff --git a/hc/accounts/views.py b/hc/accounts/views.py
index ec4d9c56..5d5d4db4 100644
--- a/hc/accounts/views.py
+++ b/hc/accounts/views.py
@@ -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")
diff --git a/hc/front/templatetags/hc_extras.py b/hc/front/templatetags/hc_extras.py
index 14a54bc5..06c52695 100644
--- a/hc/front/templatetags/hc_extras.py
+++ b/hc/front/templatetags/hc_extras.py
@@ -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(".", "."))
+@register.filter
+def mangle_link(s):
+ return mark_safe(escape(s).replace(".", "."))
+
+
@register.simple_tag
def site_root():
return settings.SITE_ROOT
diff --git a/templates/accounts/notifications.html b/templates/accounts/notifications.html
index a39aa8e4..2d1958bf 100644
--- a/templates/accounts/notifications.html
+++ b/templates/accounts/notifications.html
@@ -40,7 +40,7 @@
type="checkbox"
{% if profile.reports_allowed %} checked {% endif %}>
- The status of checks my checks
+ The status of checks in all teams I belong to
diff --git a/templates/emails/summary-html.html b/templates/emails/summary-html.html
index ac24ed2e..23100f2c 100644
--- a/templates/emails/summary-html.html
+++ b/templates/emails/summary-html.html
@@ -1,12 +1,14 @@
{% load humanize hc_extras %}
-
+{% regroup checks by user as groups %}
- | Name | -Last Ping | ++ {{ group.grouper.profile|mangle_link }} + | +Last Ping | |
\ No newline at end of file |