diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dc51816..b4cafbe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - Less verbose output in the `senddeletionnotices` command - Host a read-only dashboard (from github.com/healthchecks/dashboard/) - LINE Notify integration (#412) +- Read-only team members ## Bug Fixes - Handle excessively long email addresses in the signup form diff --git a/hc/accounts/forms.py b/hc/accounts/forms.py index 2f208042..ffba42ae 100644 --- a/hc/accounts/forms.py +++ b/hc/accounts/forms.py @@ -99,6 +99,7 @@ class ChangeEmailForm(forms.Form): class InviteTeamMemberForm(forms.Form): email = LowercaseEmailField(max_length=254) + rw = forms.BooleanField(required=False) class RemoveTeamMemberForm(forms.Form): diff --git a/hc/accounts/models.py b/hc/accounts/models.py index 06f8d053..35b13004 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -318,14 +318,14 @@ class Project(models.Model): used = q.distinct().count() return used < self.owner_profile.team_limit - def invite(self, user): + def invite(self, user, rw): if Member.objects.filter(user=user, project=self).exists(): return False if self.owner_id == user.id: return False - Member.objects.create(user=user, project=self) + Member.objects.create(user=user, project=self, rw=rw) checks_url = reverse("hc-checks", args=[self.code]) user.profile.send_instant_login_link(self, redirect_url=checks_url) return True diff --git a/hc/accounts/tests/test_project.py b/hc/accounts/tests/test_project.py index e8a1cc8b..2c899975 100644 --- a/hc/accounts/tests/test_project.py +++ b/hc/accounts/tests/test_project.py @@ -65,7 +65,7 @@ class ProjectTestCase(BaseTestCase): def test_it_adds_team_member(self): self.client.login(username="alice@example.org", password="password") - form = {"invite_team_member": "1", "email": "frank@example.org"} + form = {"invite_team_member": "1", "email": "frank@example.org", "rw": "1"} r = self.client.post(self.url, form) self.assertEqual(r.status_code, 200) @@ -76,6 +76,9 @@ class ProjectTestCase(BaseTestCase): project=self.project, user__email="frank@example.org" ) + # The read-write flag should be set + self.assertTrue(member.rw) + # The new user should not have their own project self.assertFalse(member.user.project_set.exists()) @@ -86,6 +89,20 @@ class ProjectTestCase(BaseTestCase): ) self.assertHTMLEqual(mail.outbox[0].subject, subj) + def test_it_adds_readonly_team_member(self): + self.client.login(username="alice@example.org", password="password") + + form = {"invite_team_member": "1", "email": "frank@example.org"} + r = self.client.post(self.url, form) + self.assertEqual(r.status_code, 200) + + member = Member.objects.get( + project=self.project, user__email="frank@example.org" + ) + + # The new user should not have their own project + self.assertFalse(member.rw) + def test_it_adds_member_from_another_team(self): # With team limit at zero, we should not be able to invite any new users self.profile.team_limit = 0 diff --git a/hc/accounts/views.py b/hc/accounts/views.py index 0e97fce9..2c690418 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -306,7 +306,7 @@ def project(request, code): except User.DoesNotExist: user = _make_user(email, with_project=False) - if project.invite(user): + if project.invite(user, rw=form.cleaned_data["rw"]): ctx["team_member_invited"] = email ctx["team_status"] = "success" else: diff --git a/templates/accounts/project.html b/templates/accounts/project.html index fb07559f..e10b7092 100644 --- a/templates/accounts/project.html +++ b/templates/accounts/project.html @@ -162,15 +162,21 @@