Add Profile.reports field

This is in preparation of adding an option for weekly
reports (#407)
This commit is contained in:
Pēteris Caune 2021-05-24 11:20:28 +03:00
parent 5ca7262164
commit 03a538c5e2
No known key found for this signature in database
GPG Key ID: E28D7679E9A9EDE2
9 changed files with 76 additions and 22 deletions

View File

@ -43,7 +43,7 @@ class ProfileFieldset(Fieldset):
name = "User Profile" name = "User Profile"
fields = ( fields = (
"email", "email",
"reports_allowed", "reports",
"next_report_date", "next_report_date",
"nag_period", "nag_period",
"next_nag_date", "next_nag_date",
@ -109,7 +109,7 @@ class ProfileAdmin(admin.ModelAdmin):
"projects", "projects",
"invited", "invited",
"sms", "sms",
"reports_allowed", "reports",
) )
list_filter = ( list_filter = (
"user__date_joined", "user__date_joined",

View File

@ -6,6 +6,7 @@ from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.contrib.auth.models import User from django.contrib.auth.models import User
from hc.accounts.models import REPORT_CHOICES
from hc.api.models import TokenBucket from hc.api.models import TokenBucket
@ -84,7 +85,7 @@ class PasswordLoginForm(forms.Form):
class ReportSettingsForm(forms.Form): class ReportSettingsForm(forms.Form):
reports_allowed = forms.BooleanField(required=False) reports = forms.ChoiceField(choices=REPORT_CHOICES)
nag_period = forms.IntegerField(min_value=0, max_value=86400) nag_period = forms.IntegerField(min_value=0, max_value=86400)
def clean_nag_period(self): def clean_nag_period(self):

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.2 on 2021-05-24 07:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0034_credential'),
]
operations = [
migrations.AddField(
model_name='profile',
name='reports',
field=models.CharField(choices=[('off', 'Off'), ('weekly', 'Weekly'), ('monthly', 'Monthly')], default='monthly', max_length=10),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.2 on 2021-05-24 07:38
from django.db import migrations
def fill_reports_field(apps, schema_editor):
Profile = apps.get_model("accounts", "Profile")
Profile.objects.filter(reports_allowed=False).update(reports="off")
Profile.objects.filter(reports_allowed=True).update(reports="monthly")
class Migration(migrations.Migration):
dependencies = [
("accounts", "0035_profile_reports"),
]
operations = [migrations.RunPython(fill_reports_field, migrations.RunPython.noop)]

View File

@ -23,6 +23,8 @@ NAG_PERIODS = (
(timedelta(days=1), "Daily"), (timedelta(days=1), "Daily"),
) )
REPORT_CHOICES = (("off", "Off"), ("weekly", "Weekly"), ("monthly", "Monthly"))
def month(dt): def month(dt):
""" For a given datetime, return the matching first-day-of-month date. """ """ For a given datetime, return the matching first-day-of-month date. """
@ -50,6 +52,7 @@ class Profile(models.Model):
user = models.OneToOneField(User, models.CASCADE, blank=True, null=True) user = models.OneToOneField(User, models.CASCADE, blank=True, null=True)
next_report_date = models.DateTimeField(null=True, blank=True) next_report_date = models.DateTimeField(null=True, blank=True)
reports_allowed = models.BooleanField(default=True) reports_allowed = models.BooleanField(default=True)
reports = models.CharField(max_length=10, default="monthly", choices=REPORT_CHOICES)
nag_period = models.DurationField(default=NO_NAG, choices=NAG_PERIODS) nag_period = models.DurationField(default=NO_NAG, choices=NAG_PERIODS)
next_nag_date = models.DateTimeField(null=True, blank=True) next_nag_date = models.DateTimeField(null=True, blank=True)
ping_log_limit = models.IntegerField(default=100) ping_log_limit = models.IntegerField(default=100)

View File

@ -6,33 +6,37 @@ from hc.test import BaseTestCase
class NotificationsTestCase(BaseTestCase): class NotificationsTestCase(BaseTestCase):
def test_it_saves_reports_allowed_true(self): def test_it_saves_reports_monthly(self):
self.profile.reports = "off"
self.profile.reports_allowed = False self.profile.reports_allowed = False
self.profile.save() self.profile.save()
self.client.login(username="alice@example.org", password="password") self.client.login(username="alice@example.org", password="password")
form = {"reports_allowed": "on", "nag_period": "0"} form = {"reports": "monthly", "nag_period": "0"}
r = self.client.post("/accounts/profile/notifications/", form) r = self.client.post("/accounts/profile/notifications/", form)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.profile.refresh_from_db() self.profile.refresh_from_db()
self.assertTrue(self.profile.reports_allowed) self.assertTrue(self.profile.reports_allowed)
self.assertEqual(self.profile.reports, "monthly")
self.assertIsNotNone(self.profile.next_report_date) self.assertIsNotNone(self.profile.next_report_date)
def test_it_saves_reports_allowed_false(self): def test_it_saves_reports_off(self):
self.profile.reports_allowed = True self.profile.reports_allowed = True
self.profile.reports = "monthly"
self.profile.next_report_date = now() self.profile.next_report_date = now()
self.profile.save() self.profile.save()
self.client.login(username="alice@example.org", password="password") self.client.login(username="alice@example.org", password="password")
form = {"nag_period": "0"} form = {"reports": "off", "nag_period": "0"}
r = self.client.post("/accounts/profile/notifications/", form) r = self.client.post("/accounts/profile/notifications/", form)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.profile.refresh_from_db() self.profile.refresh_from_db()
self.assertFalse(self.profile.reports_allowed) self.assertFalse(self.profile.reports_allowed)
self.assertEqual(self.profile.reports, "off")
self.assertIsNone(self.profile.next_report_date) self.assertIsNone(self.profile.next_report_date)
def test_it_sets_next_nag_date_when_setting_hourly_nag_period(self): def test_it_sets_next_nag_date_when_setting_hourly_nag_period(self):
@ -40,7 +44,7 @@ class NotificationsTestCase(BaseTestCase):
self.client.login(username="alice@example.org", password="password") self.client.login(username="alice@example.org", password="password")
form = {"nag_period": "3600"} form = {"reports": "off", "nag_period": "3600"}
r = self.client.post("/accounts/profile/notifications/", form) r = self.client.post("/accounts/profile/notifications/", form)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
@ -54,7 +58,7 @@ class NotificationsTestCase(BaseTestCase):
self.client.login(username="alice@example.org", password="password") self.client.login(username="alice@example.org", password="password")
form = {"nag_period": "3600"} form = {"reports": "off", "nag_period": "3600"}
r = self.client.post("/accounts/profile/notifications/", form) r = self.client.post("/accounts/profile/notifications/", form)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
@ -68,7 +72,7 @@ class NotificationsTestCase(BaseTestCase):
self.client.login(username="alice@example.org", password="password") self.client.login(username="alice@example.org", password="password")
form = {"nag_period": "1234"} form = {"reports": "off", "nag_period": "1234"}
r = self.client.post("/accounts/profile/notifications/", form) r = self.client.post("/accounts/profile/notifications/", form)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)

View File

@ -22,6 +22,7 @@ class UnsubscribeReportsTestCase(BaseTestCase):
self.profile.refresh_from_db() self.profile.refresh_from_db()
self.assertFalse(self.profile.reports_allowed) self.assertFalse(self.profile.reports_allowed)
self.assertEqual(self.profile.reports, "off")
self.assertIsNone(self.profile.next_report_date) self.assertIsNone(self.profile.next_report_date)
self.assertEqual(self.profile.nag_period.total_seconds(), 0) self.assertEqual(self.profile.nag_period.total_seconds(), 0)

View File

@ -447,8 +447,9 @@ def notifications(request):
if request.method == "POST": if request.method == "POST":
form = forms.ReportSettingsForm(request.POST) form = forms.ReportSettingsForm(request.POST)
if form.is_valid(): if form.is_valid():
if profile.reports_allowed != form.cleaned_data["reports_allowed"]: if profile.reports != form.cleaned_data["reports"]:
profile.reports_allowed = form.cleaned_data["reports_allowed"] profile.reports = form.cleaned_data["reports"]
profile.reports_allowed = profile.reports == "monthly"
if profile.reports_allowed: if profile.reports_allowed:
profile.next_report_date = choose_next_report_date() profile.next_report_date = choose_next_report_date()
else: else:
@ -542,6 +543,7 @@ def unsubscribe_reports(request, signed_username):
user = User.objects.get(username=username) user = User.objects.get(username=username)
profile = Profile.objects.for_user(user) profile = Profile.objects.for_user(user)
profile.reports = "off"
profile.reports_allowed = False profile.reports_allowed = False
profile.next_report_date = None profile.next_report_date = None
profile.nag_period = td() profile.nag_period = td()

View File

@ -31,14 +31,24 @@
{% csrf_token %} {% csrf_token %}
<h2>Email Reports</h2> <h2>Email Reports</h2>
<p>Send me monthly emails about:</p> <p>Send me periodic emails reports:</p>
<label class="checkbox-container"> <label class="radio-container">
<input <input
name="reports_allowed" type="radio"
type="checkbox" name="reports"
{% if profile.reports_allowed %} checked {% endif %}> value="off"
<span class="checkmark"></span> {% if profile.reports == "off" %} checked {% endif %}>
The status of checks in all teams I belong to <span class="radiomark"></span>
Do not send me email reports
</label>
<label class="radio-container">
<input
type="radio"
name="reports"
value="monthly"
{% if profile.reports == "monthly" %} checked {% endif %}>
<span class="radiomark"></span>
Monthly on 1st of every month
</label> </label>
<br> <br>
@ -81,10 +91,7 @@
{% endif %} {% endif %}
</p> </p>
<br /> <br />
<button <button
name="update_reports_allowed"
type="submit" type="submit"
class="btn btn-default pull-right">Save Changes</button> class="btn btn-default pull-right">Save Changes</button>
</form> </form>