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 %} + {% for group in groups %} - - - + + - {% for check in checks %} + {% for check in group.list %}
NameLast Ping + {{ group.grouper.profile|mangle_link }} + Last Ping
@@ -65,5 +67,6 @@ {% endfor %} + {% endfor %}

\ No newline at end of file