@ -0,0 +1,38 @@ | |||
# Generated by Django 2.1.5 on 2019-01-12 14:26 | |||
from django.conf import settings | |||
from django.db import migrations, models | |||
import django.db.models.deletion | |||
import uuid | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |||
('accounts', '0016_remove_profile_bill_to'), | |||
] | |||
operations = [ | |||
migrations.CreateModel( | |||
name='Project', | |||
fields=[ | |||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||
('code', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), | |||
('name', models.CharField(blank=True, max_length=200)), | |||
('api_key', models.CharField(blank=True, max_length=128)), | |||
('api_key_readonly', models.CharField(blank=True, max_length=128)), | |||
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | |||
], | |||
), | |||
migrations.AddField( | |||
model_name='member', | |||
name='project', | |||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), | |||
), | |||
migrations.AddField( | |||
model_name='profile', | |||
name='current_project', | |||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.Project'), | |||
), | |||
] |
@ -0,0 +1,37 @@ | |||
# Generated by Django 2.1.5 on 2019-01-11 14:49 | |||
from django.db import migrations | |||
def create_projects(apps, schema_editor): | |||
Profile = apps.get_model("accounts", "Profile") | |||
Project = apps.get_model("accounts", "Project") | |||
Member = apps.get_model("accounts", "Member") | |||
for profile in Profile.objects.all(): | |||
project = Project() | |||
project.name = profile.team_name | |||
project.owner_id = profile.user_id | |||
project.api_key = profile.api_key | |||
project.api_key_readonly = profile.api_key_readonly | |||
project.save() | |||
profile.current_project = project | |||
profile.save() | |||
Member.objects.filter(team=profile).update(project=project) | |||
for profile in Profile.objects.all(): | |||
if profile.current_team_id: | |||
profile.current_project = profile.current_team.current_project | |||
profile.save() | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('accounts', '0017_auto_20190112_1426'), | |||
] | |||
operations = [ | |||
migrations.RunPython(create_projects, migrations.RunPython.noop), | |||
] |
@ -39,6 +39,9 @@ class ProfileTestCase(BaseTestCase): | |||
self.assertTrue(len(api_key) > 10) | |||
self.assertFalse("b'" in api_key) | |||
self.project.refresh_from_db() | |||
self.assertEqual(self.project.api_key, api_key) | |||
def test_it_revokes_api_key(self): | |||
self.profile.api_key_readonly = "R" * 32 | |||
self.profile.save() | |||
@ -53,6 +56,9 @@ class ProfileTestCase(BaseTestCase): | |||
self.assertEqual(self.profile.api_key, "") | |||
self.assertEqual(self.profile.api_key_readonly, "") | |||
self.project.refresh_from_db() | |||
self.assertEqual(self.project.api_key, "") | |||
def test_it_sends_report(self): | |||
check = Check(name="Test Check", user=self.alice) | |||
check.last_ping = now() | |||
@ -126,12 +132,16 @@ class ProfileTestCase(BaseTestCase): | |||
r = self.client.post("/accounts/profile/", form) | |||
self.assertEqual(r.status_code, 200) | |||
member_emails = set() | |||
for member in self.profile.member_set.all(): | |||
member_emails.add(member.user.email) | |||
members = self.profile.member_set.all() | |||
self.assertEqual(members.count(), 2) | |||
self.assertEqual(len(member_emails), 2) | |||
self.assertTrue("[email protected]" in member_emails) | |||
frank_found = False | |||
for member in members.all(): | |||
self.assertEqual(member.project, self.project) | |||
if member.user.email == "[email protected]": | |||
frank_found = True | |||
self.assertTrue(frank_found) | |||
# And an email should have been sent | |||
subj = ('You have been invited to join' | |||
@ -159,6 +169,7 @@ class ProfileTestCase(BaseTestCase): | |||
self.bobs_profile.refresh_from_db() | |||
self.assertEqual(self.bobs_profile.current_team, None) | |||
self.assertEqual(self.bobs_profile.current_project, None) | |||
def test_it_sets_team_name(self): | |||
self.client.login(username="[email protected]", password="password") | |||
@ -170,6 +181,9 @@ class ProfileTestCase(BaseTestCase): | |||
self.profile.refresh_from_db() | |||
self.assertEqual(self.profile.team_name, "Alpha Team") | |||
self.project.refresh_from_db() | |||
self.assertEqual(self.project.name, "Alpha Team") | |||
def test_it_switches_to_own_team(self): | |||
self.client.login(username="[email protected]", password="password") | |||
@ -179,6 +193,7 @@ class ProfileTestCase(BaseTestCase): | |||
# to user's default team. | |||
self.bobs_profile.refresh_from_db() | |||
self.assertEqual(self.bobs_profile.current_team, self.bobs_profile) | |||
self.assertEqual(self.bobs_profile.current_project, None) | |||
def test_it_sends_change_email_link(self): | |||
self.client.login(username="[email protected]", password="password") | |||
@ -5,6 +5,9 @@ from hc.api.models import Check | |||
class SwitchTeamTestCase(BaseTestCase): | |||
def test_it_switches(self): | |||
self.bobs_profile.current_project = None | |||
self.bobs_profile.save() | |||
c = Check(user=self.alice, name="This belongs to Alice") | |||
c.save() | |||
@ -15,6 +18,9 @@ class SwitchTeamTestCase(BaseTestCase): | |||
self.assertContains(r, "This belongs to Alice") | |||
self.bobs_profile.refresh_from_db() | |||
self.assertEqual(self.bobs_profile.current_project, self.project) | |||
def test_it_checks_team_membership(self): | |||
self.client.login(username="[email protected]", password="password") | |||
@ -0,0 +1,25 @@ | |||
# Generated by Django 2.1.5 on 2019-01-12 14:27 | |||
from django.db import migrations, models | |||
import django.db.models.deletion | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('accounts', '0018_auto_20190112_1426'), | |||
('api', '0053_check_subject'), | |||
] | |||
operations = [ | |||
migrations.AddField( | |||
model_name='channel', | |||
name='project', | |||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), | |||
), | |||
migrations.AddField( | |||
model_name='check', | |||
name='project', | |||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), | |||
), | |||
] |
@ -0,0 +1,23 @@ | |||
# Generated by Django 2.1.5 on 2019-01-12 14:27 | |||
from django.db import migrations | |||
def fill_project_id(apps, schema_editor): | |||
Project = apps.get_model("accounts", "Project") | |||
Check = apps.get_model("api", "Check") | |||
Channel = apps.get_model("api", "Channel") | |||
for project in Project.objects.all(): | |||
Check.objects.filter(user_id=project.owner_id).update(project=project) | |||
Channel.objects.filter(user_id=project.owner_id).update(project=project) | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('api', '0054_auto_20190112_1427'), | |||
] | |||
operations = [ | |||
migrations.RunPython(fill_project_id, migrations.RunPython.noop), | |||
] |
@ -9,7 +9,19 @@ class AddCheckTestCase(BaseTestCase): | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.post(url) | |||
self.assertRedirects(r, "/checks/") | |||
assert Check.objects.count() == 1 | |||
check = Check.objects.get() | |||
self.assertEqual(check.project, self.project) | |||
def test_it_handles_unset_current_project(self): | |||
self.profile.current_project = None | |||
self.profile.save() | |||
url = "/checks/add/" | |||
self.client.login(username="[email protected]", password="password") | |||
r = self.client.post(url) | |||
self.assertRedirects(r, "/checks/") | |||
check = Check.objects.get() | |||
self.assertEqual(check.project, self.project) | |||
def test_team_access_works(self): | |||
url = "/checks/add/" | |||
@ -21,6 +21,7 @@ class AddPdTestCase(BaseTestCase): | |||
self.assertEqual(c.kind, "email") | |||
self.assertEqual(c.value, "[email protected]") | |||
self.assertFalse(c.email_verified) | |||
self.assertEqual(c.project, self.project) | |||
def test_team_access_works(self): | |||
form = {"value": "[email protected]"} | |||
@ -43,9 +43,9 @@ class AddPushoverTestCase(BaseTestCase): | |||
r = self.client.get("/integrations/add_pushover/?%s" % params) | |||
self.assertEqual(r.status_code, 302) | |||
channels = list(Channel.objects.all()) | |||
assert len(channels) == 1 | |||
assert channels[0].value == "a|0|-1" | |||
channel = Channel.objects.get() | |||
self.assertEqual(channel.value, "a|0|-1") | |||
self.assertEqual(channel.project, self.project) | |||
def test_it_validates_priority(self): | |||
self.client.login(username="[email protected]", password="password") | |||
@ -1,7 +1,7 @@ | |||
from django.contrib.auth.models import User | |||
from django.test import TestCase | |||
from hc.accounts.models import Member, Profile | |||
from hc.accounts.models import Member, Profile, Project | |||
class BaseTestCase(TestCase): | |||
@ -14,8 +14,12 @@ class BaseTestCase(TestCase): | |||
self.alice.set_password("password") | |||
self.alice.save() | |||
self.project = Project(owner=self.alice, api_key="X" * 32) | |||
self.project.save() | |||
self.profile = Profile(user=self.alice, api_key="X" * 32) | |||
self.profile.sms_limit = 50 | |||
self.profile.current_project = self.project | |||
self.profile.save() | |||
# Bob is on Alice's team and should have access to her stuff | |||
@ -25,9 +29,11 @@ class BaseTestCase(TestCase): | |||
self.bobs_profile = Profile(user=self.bob) | |||
self.bobs_profile.current_team = self.profile | |||
self.bobs_profile.current_project = self.project | |||
self.bobs_profile.save() | |||
Member.objects.create(team=self.profile, user=self.bob) | |||
Member.objects.create(team=self.profile, user=self.bob, | |||
project=self.project) | |||
# Charlie should have no access to Alice's stuff | |||
self.charlie = User(username="charlie", email="[email protected]") | |||