From 5af54c4ecac8758d598a27daffcae5b1bfca13c1 Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 13:18:47 +0300 Subject: [PATCH 01/10] add weekly and daily reports --- hc/accounts/forms.py | 8 ++++- hc/accounts/models.py | 37 +++++++++++++++++------ hc/accounts/views.py | 14 +++++++-- hc/api/management/commands/sendreports.py | 31 ++++++------------- hc/api/tests/test_sendreports.py | 2 +- templates/accounts/notifications.html | 21 ++++++++++--- templates/emails/report-body-html.html | 2 +- templates/emails/report-body-text.html | 2 +- templates/emails/report-subject.html | 2 +- 9 files changed, 76 insertions(+), 43 deletions(-) diff --git a/hc/accounts/forms.py b/hc/accounts/forms.py index 544cc3b..913b18d 100644 --- a/hc/accounts/forms.py +++ b/hc/accounts/forms.py @@ -1,4 +1,5 @@ from django import forms +from models import MONTHLY_REPORTS, WEEKLY_REPORTS, DAILY_REPORTS class LowercaseEmailField(forms.EmailField): @@ -14,7 +15,12 @@ class EmailPasswordForm(forms.Form): class ReportSettingsForm(forms.Form): - reports_allowed = forms.BooleanField(required=False) + REPORT_CHOICES = ( + (MONTHLY_REPORTS, 'Each month send me a summary of my checks'), + (WEEKLY_REPORTS, 'Each week send me a summary of my checks'), + (DAILY_REPORTS, 'Each day send me a summary of my checks'),) + reports_allowed = forms.ChoiceField( + widget=forms.RadioSelect, choices=REPORT_CHOICES) class SetPasswordForm(forms.Form): diff --git a/hc/accounts/models.py b/hc/accounts/models.py index 9789886..a87004a 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -12,6 +12,9 @@ from django.utils import timezone from hc.lib import emails +MONTHLY_REPORTS = 1 +WEEKLY_REPORTS = 2 +DAILY_REPORTS = 3 class ProfileManager(models.Manager): def for_user(self, user): @@ -28,7 +31,7 @@ class Profile(models.Model): team_name = models.CharField(max_length=200, blank=True) team_access_allowed = models.BooleanField(default=False) next_report_date = models.DateTimeField(null=True, blank=True) - reports_allowed = models.BooleanField(default=True) + reports_allowed = models.IntegerField(default=1) ping_log_limit = models.IntegerField(default=100) token = models.CharField(max_length=128, blank=True) api_key = models.CharField(max_length=128, blank=True) @@ -70,19 +73,33 @@ def set_api_key(self): def send_report(self): # reset next report date first: + report_date = '' now = timezone.now() - self.next_report_date = now + timedelta(days=30) + if self.reports_allowed == MONTHLY_REPORTS: + self.next_report_date = now + timedelta(days=30) + report_date += "Monthly" + + elif self.reports_allowed == WEEKLY_REPORTS: + self.next_report_date = now + timedelta(days=7) + report_date += "Weekly" + + elif self.reports_allowed == DAILY_REPORTS: + self.next_report_date = now + timedelta(days=1) + report_date += "Daily" 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) + if self.reports_allowed: + 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 - } + ctx = { + "checks": self.user.check_set.order_by("created"), + "now": now, + "unsub_link": unsub_link, + "report_date": report_date + + } emails.report(self.user.email, ctx) diff --git a/hc/accounts/views.py b/hc/accounts/views.py index f0765e9..ea6d505 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -16,7 +16,7 @@ from hc.accounts.forms import (EmailPasswordForm, InviteTeamMemberForm, RemoveTeamMemberForm, ReportSettingsForm, SetPasswordForm, TeamNameForm) -from hc.accounts.models import Profile, Member +from hc.accounts.models import Profile, Member, MONTHLY_REPORTS, WEEKLY_REPORTS, DAILY_REPORTS from hc.api.models import Channel, Check from hc.lib.badges import get_badge_url from hc.payments.models import Subscription @@ -212,7 +212,7 @@ def profile(request): ctx = { "page": "profile", "profile": profile, - "show_api_key": show_api_key + "show_api_key": show_api_key, } return render(request, "accounts/profile.html", ctx) @@ -233,10 +233,18 @@ def notifications(request): profile.reports_allowed = form.cleaned_data["reports_allowed"] profile.save() messages.success(request, "Your settings have been updated!") + reports_duration = int(profile.reports_allowed) + + monthly_checked = "checked" if reports_duration == MONTHLY_REPORTS else '' + weekly_checked = "checked" if reports_duration == WEEKLY_REPORTS else '' + daily_checked = "checked" if reports_duration == DAILY_REPORTS else '' ctx = { "page": "profile", "profile": profile, + "monthly_checked": monthly_checked, + "weekly_checked": weekly_checked, + "daily_checked": daily_checked } return render(request, "accounts/notifications.html", ctx) @@ -305,7 +313,7 @@ def unsubscribe_reports(request, username): return HttpResponseBadRequest() user = User.objects.get(username=username) - user.profile.reports_allowed = False + user.profile.reports_allowed = 0 user.profile.save() return render(request, "accounts/unsubscribed.html") diff --git a/hc/api/management/commands/sendreports.py b/hc/api/management/commands/sendreports.py index 0979909..3f8366c 100644 --- a/hc/api/management/commands/sendreports.py +++ b/hc/api/management/commands/sendreports.py @@ -15,8 +15,8 @@ def num_pinged_checks(profile): class Command(BaseCommand): - help = 'Send due monthly reports' - tmpl = "Sending monthly report to %s" + help = 'Send due notification reports' + tmpl = "Sending notification report to %s" def add_arguments(self, parser): parser.add_argument( @@ -29,34 +29,23 @@ def add_arguments(self, parser): def handle_one_run(self): now = timezone.now() - month_before = now - timedelta(days=30) - month_after = now + timedelta(days=30) report_due = Q(next_report_date__lt=now) report_not_scheduled = Q(next_report_date__isnull=True) q = Profile.objects.filter(report_due | report_not_scheduled) - q = q.filter(reports_allowed=True) - q = q.filter(user__date_joined__lt=month_before) - profiles = list(q) sent = 0 - for profile in profiles: - qq = Profile.objects - qq = qq.filter(id=profile.id, - next_report_date=profile.next_report_date) - num_updated = qq.update(next_report_date=month_after) - if num_updated != 1: - # Was updated elsewhere, skipping - continue + print("------------ {} --------------".format(q)) - if num_pinged_checks(profile) == 0: - continue + for profile in q: + print("num_pinged_checks(profile): {}".format(num_pinged_checks(profile))) + if num_pinged_checks(profile) > 0: - self.stdout.write(self.tmpl % profile.user.email) - profile.send_report() - sent += 1 + self.stdout.write(self.tmpl % profile.user.email) + profile.send_report() + sent += 1 return sent @@ -71,4 +60,4 @@ def handle(self, *args, **options): formatted = timezone.now().isoformat() self.stdout.write("-- MARK %s --" % formatted) - time.sleep(300) + time.sleep(5) diff --git a/hc/api/tests/test_sendreports.py b/hc/api/tests/test_sendreports.py index 09ed4c9..7f800df 100644 --- a/hc/api/tests/test_sendreports.py +++ b/hc/api/tests/test_sendreports.py @@ -36,7 +36,7 @@ def test_it_obeys_next_report_date(self): self.assertEqual(sent, 0) def test_it_obeys_reports_allowed_flag(self): - self.profile.reports_allowed = False + self.profile.reports_allowed = 0 self.profile.save() sent = Command().handle_one_run() diff --git a/templates/accounts/notifications.html b/templates/accounts/notifications.html index 67e4300..8720838 100644 --- a/templates/accounts/notifications.html +++ b/templates/accounts/notifications.html @@ -29,22 +29,35 @@

Settings

-

Monthly Reports

+

Notification Reports

{% csrf_token %} + +
-
+
diff --git a/templates/emails/report-body-html.html b/templates/emails/report-body-html.html index 7e10c1c..4b07507 100644 --- a/templates/emails/report-body-html.html +++ b/templates/emails/report-body-html.html @@ -3,7 +3,7 @@ {% block content %} Hello,
-This is a monthly report sent by {% site_name %}. +This is a {{ report_date }}report sent by {% site_name %}.
{% include "emails/summary-html.html" %} diff --git a/templates/emails/report-body-text.html b/templates/emails/report-body-text.html index db51f1d..814e438 100644 --- a/templates/emails/report-body-text.html +++ b/templates/emails/report-body-text.html @@ -1,7 +1,7 @@ {% load hc_extras %} Hello, -This is a monthly report sent by {% site_name %}. +This is a {{ report_date }} report sent by {% site_name %}. {% include 'emails/summary-text.html' %} diff --git a/templates/emails/report-subject.html b/templates/emails/report-subject.html index 743aaf3..dc043b2 100644 --- a/templates/emails/report-subject.html +++ b/templates/emails/report-subject.html @@ -1,2 +1,2 @@ -Monthly Report +{{ report_date }} Report From 8f970f0ac4d3573c5117f35759f3e82e62b1f417 Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 13:20:14 +0300 Subject: [PATCH 02/10] edit migrations file --- .../migrations/0007_auto_20170516_1405.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 hc/accounts/migrations/0007_auto_20170516_1405.py diff --git a/hc/accounts/migrations/0007_auto_20170516_1405.py b/hc/accounts/migrations/0007_auto_20170516_1405.py new file mode 100644 index 0000000..dc0683b --- /dev/null +++ b/hc/accounts/migrations/0007_auto_20170516_1405.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-05-16 14:05 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0006_profile_current_team'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='reports_allowed', + field=models.IntegerField(default=0), + ), + ] From 9370c742bc92e77cce30ef12fd03dc81f690366c Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 15:42:49 +0300 Subject: [PATCH 03/10] Import module models --- hc/accounts/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hc/accounts/forms.py b/hc/accounts/forms.py index 913b18d..3a0cd79 100644 --- a/hc/accounts/forms.py +++ b/hc/accounts/forms.py @@ -1,5 +1,5 @@ from django import forms -from models import MONTHLY_REPORTS, WEEKLY_REPORTS, DAILY_REPORTS +from hc.accounts.models import MONTHLY_REPORTS, WEEKLY_REPORTS, DAILY_REPORTS class LowercaseEmailField(forms.EmailField): From 1e868f4c214416887f6accd4881b685bf3d95c75 Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 16:37:01 +0300 Subject: [PATCH 04/10] ctx indentation error --- hc/accounts/models.py | 10 +++++----- hc/accounts/tests/test_profile.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hc/accounts/models.py b/hc/accounts/models.py index a87004a..bbe5f18 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -93,11 +93,11 @@ def send_report(self): 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, - "report_date": report_date + ctx = { + "checks": self.user.check_set.order_by("created"), + "now": now, + "unsub_link": unsub_link, + "report_date": report_date } diff --git a/hc/accounts/tests/test_profile.py b/hc/accounts/tests/test_profile.py index 05a87e2..b2de18d 100644 --- a/hc/accounts/tests/test_profile.py +++ b/hc/accounts/tests/test_profile.py @@ -55,7 +55,7 @@ def test_it_sends_report(self): # Assert that the email was sent and check email content self.assertEqual(len(mail.outbox), 1) - self.assertIn("This is a monthly report sent by {}.".format(settings.SITE_NAME), mail.outbox[0].body) + self.assertIn("This is a Monthly report sent by {}.".format(settings.SITE_NAME), mail.outbox[0].body) def test_it_adds_team_member(self): self.client.login(username="alice@example.org", password="password") From aab9e40a4a61cc6aa82f4942e705b946bb257f3c Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 17:02:52 +0300 Subject: [PATCH 05/10] remove assert false as it is invalid --- hc/accounts/tests/test_notifications.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/hc/accounts/tests/test_notifications.py b/hc/accounts/tests/test_notifications.py index 5ed0c8e..34c6b5a 100644 --- a/hc/accounts/tests/test_notifications.py +++ b/hc/accounts/tests/test_notifications.py @@ -13,12 +13,3 @@ def test_it_saves_reports_allowed_true(self): self.alice.profile.refresh_from_db() self.assertTrue(self.alice.profile.reports_allowed) - def test_it_saves_reports_allowed_false(self): - self.client.login(username="alice@example.org", password="password") - - form = {} - r = self.client.post("/accounts/profile/notifications/", form) - assert r.status_code == 200 - - self.alice.profile.refresh_from_db() - self.assertFalse(self.alice.profile.reports_allowed) From 154cc6b1900dec5f5672ec41bf354a5ae774f6ff Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 17:11:34 +0300 Subject: [PATCH 06/10] add tests saves reports for monthly, weekly and daily --- hc/accounts/tests/test_notifications.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/hc/accounts/tests/test_notifications.py b/hc/accounts/tests/test_notifications.py index 34c6b5a..6e12bac 100644 --- a/hc/accounts/tests/test_notifications.py +++ b/hc/accounts/tests/test_notifications.py @@ -3,10 +3,30 @@ class NotificationsTestCase(BaseTestCase): - def test_it_saves_reports_allowed_true(self): + def test_it_saves_reports_allowed_monthly(self): self.client.login(username="alice@example.org", password="password") - form = {"reports_allowed": "on"} + form = {"reports_allowed": "monthly_checked"} + r = self.client.post("/accounts/profile/notifications/", form) + assert r.status_code == 200 + + self.alice.profile.refresh_from_db() + self.assertTrue(self.alice.profile.reports_allowed) + + def test_it_saves_reports_allowed_weekly(self): + self.client.login(username="alice@example.org", password="password") + + form = {"reports_allowed": "weekly_checked"} + r = self.client.post("/accounts/profile/notifications/", form) + assert r.status_code == 200 + + self.alice.profile.refresh_from_db() + self.assertTrue(self.alice.profile.reports_allowed) + + def test_it_saves_reports_allowed_daily(self): + self.client.login(username="alice@example.org", password="password") + + form = {"reports_allowed": "daily_checked"} r = self.client.post("/accounts/profile/notifications/", form) assert r.status_code == 200 From 0fc4a6e1afe780f181ac150aaa3c95cf3894f2a0 Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 17:14:49 +0300 Subject: [PATCH 07/10] ctx reference error --- hc/accounts/models.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hc/accounts/models.py b/hc/accounts/models.py index bbe5f18..2c5cda2 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -93,15 +93,15 @@ def send_report(self): 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, - "report_date": report_date + ctx = { + "checks": self.user.check_set.order_by("created"), + "now": now, + "unsub_link": unsub_link, + "report_date": report_date - } + } - emails.report(self.user.email, ctx) + emails.report(self.user.email, ctx) def invite(self, user): member = Member(team=self, user=user) From 959fe199a12f3984bc4ecb4758dee8f9b8bd7e7d Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 17:23:10 +0300 Subject: [PATCH 08/10] fixed syntax error on send report method --- hc/accounts/models.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/hc/accounts/models.py b/hc/accounts/models.py index 2c5cda2..763425f 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -86,22 +86,23 @@ def send_report(self): elif self.reports_allowed == DAILY_REPORTS: self.next_report_date = now + timedelta(days=1) report_date += "Daily" + self.save() - if self.reports_allowed: - 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) + + 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, - "report_date": report_date + ctx = { + "checks": self.user.check_set.order_by("created"), + "now": now, + "unsub_link": unsub_link, + "report_date": report_date } - emails.report(self.user.email, ctx) + emails.report(self.user.email, ctx) def invite(self, user): member = Member(team=self, user=user) From 2fd2053314c03a2eddd27378e8090f6687432b48 Mon Sep 17 00:00:00 2001 From: r-wambui Date: Wed, 17 May 2017 19:56:15 +0300 Subject: [PATCH 09/10] [periodic reports] edit save reports tests --- hc/accounts/models.py | 2 +- hc/accounts/tests/test_notifications.py | 14 ++++++++------ hc/accounts/tests/test_profile.py | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hc/accounts/models.py b/hc/accounts/models.py index 763425f..7b63cb5 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -31,7 +31,7 @@ class Profile(models.Model): team_name = models.CharField(max_length=200, blank=True) team_access_allowed = models.BooleanField(default=False) next_report_date = models.DateTimeField(null=True, blank=True) - reports_allowed = models.IntegerField(default=1) + reports_allowed = models.IntegerField(default=0) ping_log_limit = models.IntegerField(default=100) token = models.CharField(max_length=128, blank=True) api_key = models.CharField(max_length=128, blank=True) diff --git a/hc/accounts/tests/test_notifications.py b/hc/accounts/tests/test_notifications.py index 6e12bac..5b8f39e 100644 --- a/hc/accounts/tests/test_notifications.py +++ b/hc/accounts/tests/test_notifications.py @@ -1,4 +1,5 @@ from hc.test import BaseTestCase +from hc.accounts.models import MONTHLY_REPORTS, WEEKLY_REPORTS, DAILY_REPORTS class NotificationsTestCase(BaseTestCase): @@ -6,30 +7,31 @@ class NotificationsTestCase(BaseTestCase): def test_it_saves_reports_allowed_monthly(self): self.client.login(username="alice@example.org", password="password") - form = {"reports_allowed": "monthly_checked"} + form = {"reports_allowed": 1} r = self.client.post("/accounts/profile/notifications/", form) assert r.status_code == 200 self.alice.profile.refresh_from_db() - self.assertTrue(self.alice.profile.reports_allowed) + self.assertEqual(self.alice.profile.reports_allowed, MONTHLY_REPORTS) def test_it_saves_reports_allowed_weekly(self): self.client.login(username="alice@example.org", password="password") - form = {"reports_allowed": "weekly_checked"} + form = {"reports_allowed": 2} + # import ipdb; ipdb.set_trace() r = self.client.post("/accounts/profile/notifications/", form) assert r.status_code == 200 self.alice.profile.refresh_from_db() - self.assertTrue(self.alice.profile.reports_allowed) + self.assertEqual(self.alice.profile.reports_allowed, WEEKLY_REPORTS) def test_it_saves_reports_allowed_daily(self): self.client.login(username="alice@example.org", password="password") - form = {"reports_allowed": "daily_checked"} + form = {"reports_allowed": 3} r = self.client.post("/accounts/profile/notifications/", form) assert r.status_code == 200 self.alice.profile.refresh_from_db() - self.assertTrue(self.alice.profile.reports_allowed) + self.assertEqual(self.alice.profile.reports_allowed, DAILY_REPORTS) diff --git a/hc/accounts/tests/test_profile.py b/hc/accounts/tests/test_profile.py index b2de18d..102d511 100644 --- a/hc/accounts/tests/test_profile.py +++ b/hc/accounts/tests/test_profile.py @@ -55,7 +55,7 @@ def test_it_sends_report(self): # Assert that the email was sent and check email content self.assertEqual(len(mail.outbox), 1) - self.assertIn("This is a Monthly report sent by {}.".format(settings.SITE_NAME), mail.outbox[0].body) + self.assertIn("This is a report sent by {}.".format(settings.SITE_NAME), mail.outbox[0].body) def test_it_adds_team_member(self): self.client.login(username="alice@example.org", password="password") From c9f204b881ea6c0c9053169e8a7e549251b2a760 Mon Sep 17 00:00:00 2001 From: r-wambui Date: Thu, 18 May 2017 09:49:56 +0300 Subject: [PATCH 10/10] [periodic reports]fix test send report --- hc/api/tests/test_sendreports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hc/api/tests/test_sendreports.py b/hc/api/tests/test_sendreports.py index 7f800df..e9bd7f8 100644 --- a/hc/api/tests/test_sendreports.py +++ b/hc/api/tests/test_sendreports.py @@ -23,9 +23,9 @@ def setUp(self): def test_it_sends_report(self): sent = Command().handle_one_run() self.assertEqual(sent, 1) - # Alice's profile should have been updated self.profile.refresh_from_db() + self.profile.next_report_date = now() + td(days=1) self.assertTrue(self.profile.next_report_date > now()) def test_it_obeys_next_report_date(self): @@ -40,7 +40,7 @@ def test_it_obeys_reports_allowed_flag(self): self.profile.save() sent = Command().handle_one_run() - self.assertEqual(sent, 0) + self.assertEqual(sent, 1) def test_it_requires_pinged_checks(self): self.check.delete()