Browse Source

Project model. cc: #183

pull/214/head
Pēteris Caune 6 years ago
parent
commit
1c69cf7f89
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
34 changed files with 283 additions and 32 deletions
  1. +2
    -0
      CHANGELOG.md
  2. +10
    -1
      hc/accounts/admin.py
  3. +4
    -0
      hc/accounts/middleware.py
  4. +38
    -0
      hc/accounts/migrations/0017_auto_20190112_1426.py
  5. +37
    -0
      hc/accounts/migrations/0018_auto_20190112_1426.py
  6. +15
    -3
      hc/accounts/models.py
  7. +1
    -0
      hc/accounts/tests/test_close_account.py
  8. +20
    -5
      hc/accounts/tests/test_profile.py
  9. +12
    -2
      hc/accounts/tests/test_signup.py
  10. +6
    -0
      hc/accounts/tests/test_switch_team.py
  11. +31
    -4
      hc/accounts/views.py
  12. +2
    -0
      hc/api/decorators.py
  13. +25
    -0
      hc/api/migrations/0054_auto_20190112_1427.py
  14. +23
    -0
      hc/api/migrations/0055_auto_20190112_1427.py
  15. +3
    -0
      hc/api/models.py
  16. +1
    -0
      hc/api/tests/test_create_check.py
  17. +1
    -1
      hc/api/views.py
  18. +13
    -1
      hc/front/tests/test_add_check.py
  19. +1
    -0
      hc/front/tests/test_add_discord.py
  20. +1
    -0
      hc/front/tests/test_add_email.py
  21. +1
    -0
      hc/front/tests/test_add_hipchat.py
  22. +1
    -0
      hc/front/tests/test_add_opsgenie.py
  23. +1
    -0
      hc/front/tests/test_add_pagertree.py
  24. +1
    -0
      hc/front/tests/test_add_pd.py
  25. +1
    -0
      hc/front/tests/test_add_pushbullet.py
  26. +3
    -3
      hc/front/tests/test_add_pushover.py
  27. +1
    -0
      hc/front/tests/test_add_slack.py
  28. +1
    -0
      hc/front/tests/test_add_slack_btn.py
  29. +1
    -0
      hc/front/tests/test_add_sms.py
  30. +1
    -2
      hc/front/tests/test_add_telegram.py
  31. +1
    -0
      hc/front/tests/test_add_victorops.py
  32. +1
    -0
      hc/front/tests/test_add_webhook.py
  33. +15
    -8
      hc/front/views.py
  34. +8
    -2
      hc/test.py

+ 2
- 0
CHANGELOG.md View File

@ -9,6 +9,8 @@ All notable changes to this project will be documented in this file.
- Database schema: add Ping.kind field - Database schema: add Ping.kind field
- Database schema: remove Ping.start and Ping.fail fields - Database schema: remove Ping.start and Ping.fail fields
- Add "Email Settings..." dialog and "Subject Must Contain" setting - Add "Email Settings..." dialog and "Subject Must Contain" setting
- Database schema: add the Project model
## 1.4.0 - 2018-12-25 ## 1.4.0 - 2018-12-25


+ 10
- 1
hc/accounts/admin.py View File

@ -5,7 +5,7 @@ from django.db.models import Count
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.urls import reverse from django.urls import reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from hc.accounts.models import Profile
from hc.accounts.models import Profile, Project
class Fieldset: class Fieldset:
@ -85,6 +85,15 @@ class ProfileAdmin(admin.ModelAdmin):
return obj.user.email return obj.user.email
@admin.register(Project)
class ProjectAdmin(admin.ModelAdmin):
list_select_related = ("owner", )
list_display = ("id", "name", "email")
def email(self, obj):
return obj.owner.email
class HcUserAdmin(UserAdmin): class HcUserAdmin(UserAdmin):
actions = ["send_report"] actions = ["send_report"]
list_display = ('id', 'email', 'date_joined', 'last_login', 'engagement', list_display = ('id', 'email', 'date_joined', 'last_login', 'engagement',


+ 4
- 0
hc/accounts/middleware.py View File

@ -16,4 +16,8 @@ class TeamAccessMiddleware(object):
request.profile = Profile.objects.for_user(request.user) request.profile = Profile.objects.for_user(request.user)
request.team = request.profile.team() request.team = request.profile.team()
request.project = request.profile.current_project
if request.project is None:
request.project = request.team.user.project_set.first()
return self.get_response(request) return self.get_response(request)

+ 38
- 0
hc/accounts/migrations/0017_auto_20190112_1426.py View File

@ -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'),
),
]

+ 37
- 0
hc/accounts/migrations/0018_auto_20190112_1426.py View File

@ -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),
]

+ 15
- 3
hc/accounts/models.py View File

@ -1,6 +1,7 @@
from base64 import urlsafe_b64encode from base64 import urlsafe_b64encode
import os
from datetime import timedelta from datetime import timedelta
import os
import uuid
from django.conf import settings from django.conf import settings
from django.contrib.auth.hashers import check_password, make_password from django.contrib.auth.hashers import check_password, make_password
@ -54,6 +55,7 @@ class Profile(models.Model):
api_key = models.CharField(max_length=128, blank=True) api_key = models.CharField(max_length=128, blank=True)
api_key_readonly = models.CharField(max_length=128, blank=True) api_key_readonly = models.CharField(max_length=128, blank=True)
current_team = models.ForeignKey("self", models.SET_NULL, null=True) current_team = models.ForeignKey("self", models.SET_NULL, null=True)
current_project = models.ForeignKey("Project", models.SET_NULL, null=True)
last_sms_date = models.DateTimeField(null=True, blank=True) last_sms_date = models.DateTimeField(null=True, blank=True)
sms_limit = models.IntegerField(default=0) sms_limit = models.IntegerField(default=0)
sms_sent = models.IntegerField(default=0) sms_sent = models.IntegerField(default=0)
@ -185,8 +187,9 @@ class Profile(models.Model):
return self.member_set.count() < self.team_limit return self.member_set.count() < self.team_limit
def invite(self, user): def invite(self, user):
member = Member(team=self, user=user)
member.save()
for project in self.user.project_set.all():
member = Member(team=self, user=user, project=project)
member.save()
# Switch the invited user over to the new team so they # Switch the invited user over to the new team so they
# notice the new team on next visit: # notice the new team on next visit:
@ -231,6 +234,15 @@ class Profile(models.Model):
q.update(next_nag_date=timezone.now() + models.F("nag_period")) q.update(next_nag_date=timezone.now() + models.F("nag_period"))
class Project(models.Model):
code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
name = models.CharField(max_length=200, blank=True)
owner = models.ForeignKey(User, models.CASCADE)
api_key = models.CharField(max_length=128, blank=True)
api_key_readonly = models.CharField(max_length=128, blank=True)
class Member(models.Model): class Member(models.Model):
team = models.ForeignKey(Profile, models.CASCADE) team = models.ForeignKey(Profile, models.CASCADE)
user = models.ForeignKey(User, models.CASCADE, related_name="memberships") user = models.ForeignKey(User, models.CASCADE, related_name="memberships")
project = models.ForeignKey(Project, models.CASCADE, null=True)

+ 1
- 0
hc/accounts/tests/test_close_account.py View File

@ -27,6 +27,7 @@ class CloseAccountTestCase(BaseTestCase):
# Bob's current team should now be None # Bob's current team should now be None
self.bobs_profile.refresh_from_db() self.bobs_profile.refresh_from_db()
self.assertIsNone(self.bobs_profile.current_team) self.assertIsNone(self.bobs_profile.current_team)
self.assertIsNone(self.bobs_profile.current_project)
# Check should be gone # Check should be gone
self.assertFalse(Check.objects.exists()) self.assertFalse(Check.objects.exists())


+ 20
- 5
hc/accounts/tests/test_profile.py View File

@ -39,6 +39,9 @@ class ProfileTestCase(BaseTestCase):
self.assertTrue(len(api_key) > 10) self.assertTrue(len(api_key) > 10)
self.assertFalse("b'" in api_key) 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): def test_it_revokes_api_key(self):
self.profile.api_key_readonly = "R" * 32 self.profile.api_key_readonly = "R" * 32
self.profile.save() self.profile.save()
@ -53,6 +56,9 @@ class ProfileTestCase(BaseTestCase):
self.assertEqual(self.profile.api_key, "") self.assertEqual(self.profile.api_key, "")
self.assertEqual(self.profile.api_key_readonly, "") self.assertEqual(self.profile.api_key_readonly, "")
self.project.refresh_from_db()
self.assertEqual(self.project.api_key, "")
def test_it_sends_report(self): def test_it_sends_report(self):
check = Check(name="Test Check", user=self.alice) check = Check(name="Test Check", user=self.alice)
check.last_ping = now() check.last_ping = now()
@ -126,12 +132,16 @@ class ProfileTestCase(BaseTestCase):
r = self.client.post("/accounts/profile/", form) r = self.client.post("/accounts/profile/", form)
self.assertEqual(r.status_code, 200) 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 # And an email should have been sent
subj = ('You have been invited to join' subj = ('You have been invited to join'
@ -159,6 +169,7 @@ class ProfileTestCase(BaseTestCase):
self.bobs_profile.refresh_from_db() self.bobs_profile.refresh_from_db()
self.assertEqual(self.bobs_profile.current_team, None) self.assertEqual(self.bobs_profile.current_team, None)
self.assertEqual(self.bobs_profile.current_project, None)
def test_it_sets_team_name(self): def test_it_sets_team_name(self):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
@ -170,6 +181,9 @@ class ProfileTestCase(BaseTestCase):
self.profile.refresh_from_db() self.profile.refresh_from_db()
self.assertEqual(self.profile.team_name, "Alpha Team") 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): def test_it_switches_to_own_team(self):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
@ -179,6 +193,7 @@ class ProfileTestCase(BaseTestCase):
# to user's default team. # to user's default team.
self.bobs_profile.refresh_from_db() self.bobs_profile.refresh_from_db()
self.assertEqual(self.bobs_profile.current_team, self.bobs_profile) 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): def test_it_sends_change_email_link(self):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")


+ 12
- 2
hc/accounts/tests/test_signup.py View File

@ -2,7 +2,8 @@ from django.contrib.auth.models import User
from django.core import mail from django.core import mail
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from hc.api.models import Check
from hc.accounts.models import Project
from hc.api.models import Channel, Check
from django.conf import settings from django.conf import settings
@ -15,16 +16,25 @@ class SignupTestCase(TestCase):
self.assertContains(r, "Account created") self.assertContains(r, "Account created")
# An user should have been created # An user should have been created
self.assertEqual(User.objects.count(), 1)
user = User.objects.get()
# And email sent # And email sent
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
subject = "Log in to %s" % settings.SITE_NAME subject = "Log in to %s" % settings.SITE_NAME
self.assertEqual(mail.outbox[0].subject, subject) self.assertEqual(mail.outbox[0].subject, subject)
# A project should have been created
project = Project.objects.get()
self.assertEqual(project.owner, user)
# And check should be associated with the new user # And check should be associated with the new user
check = Check.objects.get() check = Check.objects.get()
self.assertEqual(check.name, "My First Check") self.assertEqual(check.name, "My First Check")
self.assertEqual(check.project, project)
# A channel should have been created
channel = Channel.objects.get()
self.assertEqual(channel.project, project)
@override_settings(REGISTRATION_OPEN=False) @override_settings(REGISTRATION_OPEN=False)
def test_it_obeys_registration_open(self): def test_it_obeys_registration_open(self):


+ 6
- 0
hc/accounts/tests/test_switch_team.py View File

@ -5,6 +5,9 @@ from hc.api.models import Check
class SwitchTeamTestCase(BaseTestCase): class SwitchTeamTestCase(BaseTestCase):
def test_it_switches(self): 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 = Check(user=self.alice, name="This belongs to Alice")
c.save() c.save()
@ -15,6 +18,9 @@ class SwitchTeamTestCase(BaseTestCase):
self.assertContains(r, "This belongs to Alice") 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): def test_it_checks_team_membership(self):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")


+ 31
- 4
hc/accounts/views.py View File

@ -21,7 +21,7 @@ from hc.accounts.forms import (ChangeEmailForm, EmailPasswordForm,
ReportSettingsForm, SetPasswordForm, ReportSettingsForm, SetPasswordForm,
TeamNameForm, AvailableEmailForm, TeamNameForm, AvailableEmailForm,
ExistingEmailForm) ExistingEmailForm)
from hc.accounts.models import Profile, Member
from hc.accounts.models import Profile, Project, Member
from hc.api.models import Channel, Check from hc.api.models import Channel, Check
from hc.lib.badges import get_badge_url from hc.lib.badges import get_badge_url
from hc.payments.models import Subscription from hc.payments.models import Subscription
@ -49,14 +49,19 @@ def _make_user(email):
user.set_unusable_password() user.set_unusable_password()
user.save() user.save()
project = Project(owner=user)
project.save()
# Ensure a profile gets created # Ensure a profile gets created
Profile.objects.for_user(user)
profile = Profile.objects.for_user(user)
profile.current_project = project
profile.save()
check = Check(user=user)
check = Check(user=user, project=project)
check.name = "My First Check" check.name = "My First Check"
check.save() check.save()
channel = Channel(user=user)
channel = Channel(user=user, project=project)
channel.kind = "email" channel.kind = "email"
channel.value = email channel.value = email
channel.email_verified = True channel.email_verified = True
@ -72,7 +77,10 @@ def _ensure_own_team(request):
if request.team != request.profile: if request.team != request.profile:
request.team = request.profile request.team = request.profile
request.project = request.user.project_set.first()
request.profile.current_team = request.profile request.profile.current_team = request.profile
request.profile.current_project = request.project
request.profile.save() request.profile.save()
@ -200,6 +208,12 @@ def profile(request):
return redirect("hc-link-sent") return redirect("hc-link-sent")
elif "create_api_keys" in request.POST: elif "create_api_keys" in request.POST:
profile.set_api_keys() profile.set_api_keys()
for project in request.user.project_set.all():
project.api_key = profile.api_key
project.api_key_readonly = profile.api_key_readonly
project.save()
ctx["show_api_keys"] = True ctx["show_api_keys"] = True
ctx["api_keys_created"] = True ctx["api_keys_created"] = True
ctx["api_status"] = "success" ctx["api_status"] = "success"
@ -208,6 +222,12 @@ def profile(request):
profile.api_key = "" profile.api_key = ""
profile.api_key_readonly = "" profile.api_key_readonly = ""
profile.save() profile.save()
for project in request.user.project_set.all():
project.api_key = ""
project.api_key_readonly = ""
project.save()
ctx["api_keys_revoked"] = True ctx["api_keys_revoked"] = True
ctx["api_status"] = "info" ctx["api_status"] = "info"
elif "show_api_keys" in request.POST: elif "show_api_keys" in request.POST:
@ -236,6 +256,7 @@ def profile(request):
email = form.cleaned_data["email"] email = form.cleaned_data["email"]
farewell_user = User.objects.get(email=email) farewell_user = User.objects.get(email=email)
farewell_user.profile.current_team = None farewell_user.profile.current_team = None
farewell_user.profile.current_project = None
farewell_user.profile.save() farewell_user.profile.save()
Member.objects.filter(team=profile, Member.objects.filter(team=profile,
@ -248,6 +269,11 @@ def profile(request):
if form.is_valid(): if form.is_valid():
profile.team_name = form.cleaned_data["team_name"] profile.team_name = form.cleaned_data["team_name"]
profile.save() profile.save()
for project in request.user.project_set.all():
project.name = form.cleaned_data["team_name"]
project.save()
ctx["team_name_updated"] = True ctx["team_name_updated"] = True
ctx["team_status"] = "success" ctx["team_status"] = "success"
@ -427,6 +453,7 @@ def switch_team(request, target_username):
return HttpResponseForbidden() return HttpResponseForbidden()
request.profile.current_team = target_team request.profile.current_team = target_team
request.profile.current_project = target_team.user.project_set.first()
request.profile.save() request.profile.save()
return redirect("hc-checks") return redirect("hc-checks")


+ 2
- 0
hc/api/decorators.py View File

@ -24,6 +24,7 @@ def authorize(f):
try: try:
request.user = User.objects.get(profile__api_key=api_key) request.user = User.objects.get(profile__api_key=api_key)
request.project = request.user.project_set.first()
except User.DoesNotExist: except User.DoesNotExist:
return error("wrong api key", 401) return error("wrong api key", 401)
@ -46,6 +47,7 @@ def authorize_read(f):
read_key_match = Q(profile__api_key_readonly=api_key) read_key_match = Q(profile__api_key_readonly=api_key)
try: try:
request.user = User.objects.get(write_key_match | read_key_match) request.user = User.objects.get(write_key_match | read_key_match)
request.project = request.user.project_set.first()
except User.DoesNotExist: except User.DoesNotExist:
return error("wrong api key", 401) return error("wrong api key", 401)


+ 25
- 0
hc/api/migrations/0054_auto_20190112_1427.py View File

@ -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'),
),
]

+ 23
- 0
hc/api/migrations/0055_auto_20190112_1427.py View File

@ -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),
]

+ 3
- 0
hc/api/models.py View File

@ -12,6 +12,7 @@ from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from hc.accounts.models import Project
from hc.api import transports from hc.api import transports
from hc.lib import emails from hc.lib import emails
import requests import requests
@ -67,6 +68,7 @@ class Check(models.Model):
code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
desc = models.TextField(blank=True) desc = models.TextField(blank=True)
user = models.ForeignKey(User, models.CASCADE) user = models.ForeignKey(User, models.CASCADE)
project = models.ForeignKey(Project, models.CASCADE, null=True)
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
kind = models.CharField(max_length=10, default="simple", kind = models.CharField(max_length=10, default="simple",
choices=CHECK_KINDS) choices=CHECK_KINDS)
@ -262,6 +264,7 @@ class Channel(models.Model):
name = models.CharField(max_length=100, blank=True) name = models.CharField(max_length=100, blank=True)
code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
user = models.ForeignKey(User, models.CASCADE) user = models.ForeignKey(User, models.CASCADE)
project = models.ForeignKey(Project, models.CASCADE, null=True,)
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
kind = models.CharField(max_length=20, choices=CHANNEL_KINDS) kind = models.CharField(max_length=20, choices=CHANNEL_KINDS)
value = models.TextField(blank=True) value = models.TextField(blank=True)


+ 1
- 0
hc/api/tests/test_create_check.py View File

@ -47,6 +47,7 @@ class CreateCheckTestCase(BaseTestCase):
self.assertEqual(check.tags, "bar,baz") self.assertEqual(check.tags, "bar,baz")
self.assertEqual(check.timeout.total_seconds(), 3600) self.assertEqual(check.timeout.total_seconds(), 3600)
self.assertEqual(check.grace.total_seconds(), 60) self.assertEqual(check.grace.total_seconds(), 60)
self.assertEqual(check.project, self.project)
def test_it_handles_options(self): def test_it_handles_options(self):
r = self.client.options(self.URL) r = self.client.options(self.URL)


+ 1
- 1
hc/api/views.py View File

@ -132,7 +132,7 @@ def create_check(request):
if num_checks >= request.user.profile.check_limit: if num_checks >= request.user.profile.check_limit:
return HttpResponseForbidden() return HttpResponseForbidden()
check = Check(user=request.user)
check = Check(user=request.user, project=request.project)
created = True created = True
_update(check, request.json) _update(check, request.json)


+ 13
- 1
hc/front/tests/test_add_check.py View File

@ -9,7 +9,19 @@ class AddCheckTestCase(BaseTestCase):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
r = self.client.post(url) r = self.client.post(url)
self.assertRedirects(r, "/checks/") 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): def test_team_access_works(self):
url = "/checks/add/" url = "/checks/add/"


+ 1
- 0
hc/front/tests/test_add_discord.py View File

@ -51,6 +51,7 @@ class AddDiscordTestCase(BaseTestCase):
ch = Channel.objects.get() ch = Channel.objects.get()
self.assertEqual(ch.discord_webhook_url, "foo") self.assertEqual(ch.discord_webhook_url, "foo")
self.assertEqual(ch.project, self.project)
# Session should now be clean # Session should now be clean
self.assertFalse("discord" in self.client.session) self.assertFalse("discord" in self.client.session)


+ 1
- 0
hc/front/tests/test_add_email.py View File

@ -21,6 +21,7 @@ class AddPdTestCase(BaseTestCase):
self.assertEqual(c.kind, "email") self.assertEqual(c.kind, "email")
self.assertEqual(c.value, "[email protected]") self.assertEqual(c.value, "[email protected]")
self.assertFalse(c.email_verified) self.assertFalse(c.email_verified)
self.assertEqual(c.project, self.project)
def test_team_access_works(self): def test_team_access_works(self):
form = {"value": "[email protected]"} form = {"value": "[email protected]"}


+ 1
- 0
hc/front/tests/test_add_hipchat.py View File

@ -34,3 +34,4 @@ class AddHipChatTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.kind, "hipchat") self.assertEqual(c.kind, "hipchat")
self.assertEqual(c.value, "{}") self.assertEqual(c.value, "{}")
self.assertEqual(c.project, self.project)

+ 1
- 0
hc/front/tests/test_add_opsgenie.py View File

@ -20,6 +20,7 @@ class AddOpsGenieTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.kind, "opsgenie") self.assertEqual(c.kind, "opsgenie")
self.assertEqual(c.value, "123456") self.assertEqual(c.value, "123456")
self.assertEqual(c.project, self.project)
def test_it_trims_whitespace(self): def test_it_trims_whitespace(self):
form = {"value": " 123456 "} form = {"value": " 123456 "}


+ 1
- 0
hc/front/tests/test_add_pagertree.py View File

@ -20,6 +20,7 @@ class AddPagerTreeTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.kind, "pagertree") self.assertEqual(c.kind, "pagertree")
self.assertEqual(c.value, "http://example.org") self.assertEqual(c.value, "http://example.org")
self.assertEqual(c.project, self.project)
def test_it_rejects_bad_url(self): def test_it_rejects_bad_url(self):
form = {"value": "not an URL"} form = {"value": "not an URL"}


+ 1
- 0
hc/front/tests/test_add_pd.py View File

@ -25,6 +25,7 @@ class AddPdTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.kind, "pd") self.assertEqual(c.kind, "pd")
self.assertEqual(c.pd_service_key, "123") self.assertEqual(c.pd_service_key, "123")
self.assertEqual(c.project, self.project)
def test_it_validates_code(self): def test_it_validates_code(self):
session = self.client.session session = self.client.session


+ 1
- 0
hc/front/tests/test_add_pushbullet.py View File

@ -45,6 +45,7 @@ class AddPushbulletTestCase(BaseTestCase):
ch = Channel.objects.get() ch = Channel.objects.get()
self.assertEqual(ch.value, "test-token") self.assertEqual(ch.value, "test-token")
self.assertEqual(ch.project, self.project)
# Session should now be clean # Session should now be clean
self.assertFalse("pushbullet" in self.client.session) self.assertFalse("pushbullet" in self.client.session)


+ 3
- 3
hc/front/tests/test_add_pushover.py View File

@ -43,9 +43,9 @@ class AddPushoverTestCase(BaseTestCase):
r = self.client.get("/integrations/add_pushover/?%s" % params) r = self.client.get("/integrations/add_pushover/?%s" % params)
self.assertEqual(r.status_code, 302) 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): def test_it_validates_priority(self):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")


+ 1
- 0
hc/front/tests/test_add_slack.py View File

@ -22,6 +22,7 @@ class AddSlackTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.kind, "slack") self.assertEqual(c.kind, "slack")
self.assertEqual(c.value, "http://example.org") self.assertEqual(c.value, "http://example.org")
self.assertEqual(c.project, self.project)
@override_settings(SLACK_CLIENT_ID=None) @override_settings(SLACK_CLIENT_ID=None)
def test_it_rejects_bad_url(self): def test_it_rejects_bad_url(self):


+ 1
- 0
hc/front/tests/test_add_slack_btn.py View File

@ -54,6 +54,7 @@ class AddSlackBtnTestCase(BaseTestCase):
self.assertEqual(ch.slack_team, "foo") self.assertEqual(ch.slack_team, "foo")
self.assertEqual(ch.slack_channel, "bar") self.assertEqual(ch.slack_channel, "bar")
self.assertEqual(ch.slack_webhook_url, "http://example.org") self.assertEqual(ch.slack_webhook_url, "http://example.org")
self.assertEqual(ch.project, self.project)
# Session should now be clean # Session should now be clean
self.assertFalse("slack" in self.client.session) self.assertFalse("slack" in self.client.session)


+ 1
- 0
hc/front/tests/test_add_sms.py View File

@ -32,6 +32,7 @@ class AddSmsTestCase(BaseTestCase):
self.assertEqual(c.kind, "sms") self.assertEqual(c.kind, "sms")
self.assertEqual(c.sms_number, "+1234567890") self.assertEqual(c.sms_number, "+1234567890")
self.assertEqual(c.name, "My Phone") self.assertEqual(c.name, "My Phone")
self.assertEqual(c.project, self.project)
def test_it_rejects_bad_number(self): def test_it_rejects_bad_number(self):
form = {"value": "not a phone number address"} form = {"value": "not a phone number address"}


+ 1
- 2
hc/front/tests/test_add_telegram.py View File

@ -1,5 +1,3 @@
import json
from django.core import signing from django.core import signing
from hc.api.models import Channel from hc.api.models import Channel
from hc.test import BaseTestCase from hc.test import BaseTestCase
@ -33,6 +31,7 @@ class AddTelegramTestCase(BaseTestCase):
self.assertEqual(c.telegram_id, 123) self.assertEqual(c.telegram_id, 123)
self.assertEqual(c.telegram_type, "group") self.assertEqual(c.telegram_type, "group")
self.assertEqual(c.telegram_name, "My Group") self.assertEqual(c.telegram_name, "My Group")
self.assertEqual(c.project, self.project)
@patch("hc.api.transports.requests.request") @patch("hc.api.transports.requests.request")
def test_it_sends_invite(self, mock_get): def test_it_sends_invite(self, mock_get):


+ 1
- 0
hc/front/tests/test_add_victorops.py View File

@ -20,6 +20,7 @@ class AddVictorOpsTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.kind, "victorops") self.assertEqual(c.kind, "victorops")
self.assertEqual(c.value, "http://example.org") self.assertEqual(c.value, "http://example.org")
self.assertEqual(c.project, self.project)
def test_it_rejects_bad_url(self): def test_it_rejects_bad_url(self):
form = {"value": "not an URL"} form = {"value": "not an URL"}


+ 1
- 0
hc/front/tests/test_add_webhook.py View File

@ -19,6 +19,7 @@ class AddWebhookTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.value, '{"headers": {}, "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}') self.assertEqual(c.value, '{"headers": {}, "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}')
self.assertEqual(c.project, self.project)
def test_it_adds_webhook_using_team_access(self): def test_it_adds_webhook_using_team_access(self):
form = {"url_down": "http://foo.com", "url_up": "https://bar.com"} form = {"url_down": "http://foo.com", "url_up": "https://bar.com"}


+ 15
- 8
hc/front/views.py View File

@ -249,7 +249,7 @@ def add_check(request):
if num_checks >= request.team.check_limit: if num_checks >= request.team.check_limit:
return HttpResponseBadRequest() return HttpResponseBadRequest()
check = Check(user=request.team.user)
check = Check(user=request.team.user, project=request.project)
check.save() check.save()
check.assign_all_channels() check.assign_all_channels()
@ -589,6 +589,7 @@ def add_email(request):
form = AddEmailForm(request.POST) form = AddEmailForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(user=request.team.user, kind="email") channel = Channel(user=request.team.user, kind="email")
channel.project = request.project
channel.value = form.cleaned_data["value"] channel.value = form.cleaned_data["value"]
channel.save() channel.save()
@ -608,6 +609,7 @@ def add_webhook(request):
form = AddWebhookForm(request.POST) form = AddWebhookForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(user=request.team.user, kind="webhook") channel = Channel(user=request.team.user, kind="webhook")
channel.project = request.project
channel.value = form.get_value() channel.value = form.get_value()
channel.save() channel.save()
@ -658,9 +660,8 @@ def add_pd(request, state=None):
messages.warning(request, "PagerDuty setup was cancelled") messages.warning(request, "PagerDuty setup was cancelled")
return redirect("hc-channels") return redirect("hc-channels")
channel = Channel()
channel = Channel(kind="pd", project=request.project)
channel.user = request.team.user channel.user = request.team.user
channel.kind = "pd"
channel.value = json.dumps({ channel.value = json.dumps({
"service_key": request.GET.get("service_key"), "service_key": request.GET.get("service_key"),
"account": request.GET.get("account") "account": request.GET.get("account")
@ -687,6 +688,7 @@ def add_pagertree(request):
form = AddUrlForm(request.POST) form = AddUrlForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(user=request.team.user, kind="pagertree") channel = Channel(user=request.team.user, kind="pagertree")
channel.project = request.project
channel.value = form.cleaned_data["value"] channel.value = form.cleaned_data["value"]
channel.save() channel.save()
@ -707,6 +709,7 @@ def add_slack(request):
form = AddUrlForm(request.POST) form = AddUrlForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(user=request.team.user, kind="slack") channel = Channel(user=request.team.user, kind="slack")
channel.project = request.project
channel.value = form.cleaned_data["value"] channel.value = form.cleaned_data["value"]
channel.save() channel.save()
@ -741,9 +744,8 @@ def add_slack_btn(request):
doc = result.json() doc = result.json()
if doc.get("ok"): if doc.get("ok"):
channel = Channel()
channel = Channel(kind="slack", project=request.project)
channel.user = request.team.user channel.user = request.team.user
channel.kind = "slack"
channel.value = result.text channel.value = result.text
channel.save() channel.save()
channel.assign_all_checks() channel.assign_all_checks()
@ -765,7 +767,7 @@ def add_hipchat(request):
messages.warning(request, "Something went wrong!") messages.warning(request, "Something went wrong!")
return redirect("hc-channels") return redirect("hc-channels")
channel = Channel(kind="hipchat")
channel = Channel(kind="hipchat", project=request.project)
channel.user = request.team.user channel.user = request.team.user
channel.value = response.text channel.value = response.text
channel.save() channel.save()
@ -810,7 +812,7 @@ def add_pushbullet(request):
doc = result.json() doc = result.json()
if "access_token" in doc: if "access_token" in doc:
channel = Channel(kind="pushbullet")
channel = Channel(kind="pushbullet", project=request.project)
channel.user = request.team.user channel.user = request.team.user
channel.value = doc["access_token"] channel.value = doc["access_token"]
channel.save() channel.save()
@ -858,7 +860,7 @@ def add_discord(request):
doc = result.json() doc = result.json()
if "access_token" in doc: if "access_token" in doc:
channel = Channel(kind="discord")
channel = Channel(kind="discord", project=request.project)
channel.user = request.team.user channel.user = request.team.user
channel.value = result.text channel.value = result.text
channel.save() channel.save()
@ -933,6 +935,7 @@ def add_pushover(request):
# Subscription # Subscription
channel = Channel(user=request.team.user, kind="po") channel = Channel(user=request.team.user, kind="po")
channel.project = request.project
channel.value = "%s|%s|%s" % (key, prio, prio_up) channel.value = "%s|%s|%s" % (key, prio, prio_up)
channel.save() channel.save()
channel.assign_all_checks() channel.assign_all_checks()
@ -955,6 +958,7 @@ def add_opsgenie(request):
form = AddOpsGenieForm(request.POST) form = AddOpsGenieForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(user=request.team.user, kind="opsgenie") channel = Channel(user=request.team.user, kind="opsgenie")
channel.project = request.project
channel.value = form.cleaned_data["value"] channel.value = form.cleaned_data["value"]
channel.save() channel.save()
@ -973,6 +977,7 @@ def add_victorops(request):
form = AddUrlForm(request.POST) form = AddUrlForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(user=request.team.user, kind="victorops") channel = Channel(user=request.team.user, kind="victorops")
channel.project = request.project
channel.value = form.cleaned_data["value"] channel.value = form.cleaned_data["value"]
channel.save() channel.save()
@ -1021,6 +1026,7 @@ def add_telegram(request):
if request.method == "POST": if request.method == "POST":
channel = Channel(user=request.team.user, kind="telegram") channel = Channel(user=request.team.user, kind="telegram")
channel.project = request.project
channel.value = json.dumps({ channel.value = json.dumps({
"id": chat_id, "id": chat_id,
"type": chat_type, "type": chat_type,
@ -1051,6 +1057,7 @@ def add_sms(request):
form = AddSmsForm(request.POST) form = AddSmsForm(request.POST)
if form.is_valid(): if form.is_valid():
channel = Channel(user=request.team.user, kind="sms") channel = Channel(user=request.team.user, kind="sms")
channel.project = request.project
channel.name = form.cleaned_data["label"] channel.name = form.cleaned_data["label"]
channel.value = json.dumps({ channel.value = json.dumps({
"value": form.cleaned_data["value"] "value": form.cleaned_data["value"]


+ 8
- 2
hc/test.py View File

@ -1,7 +1,7 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase
from hc.accounts.models import Member, Profile
from hc.accounts.models import Member, Profile, Project
class BaseTestCase(TestCase): class BaseTestCase(TestCase):
@ -14,8 +14,12 @@ class BaseTestCase(TestCase):
self.alice.set_password("password") self.alice.set_password("password")
self.alice.save() 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 = Profile(user=self.alice, api_key="X" * 32)
self.profile.sms_limit = 50 self.profile.sms_limit = 50
self.profile.current_project = self.project
self.profile.save() self.profile.save()
# Bob is on Alice's team and should have access to her stuff # 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 = Profile(user=self.bob)
self.bobs_profile.current_team = self.profile self.bobs_profile.current_team = self.profile
self.bobs_profile.current_project = self.project
self.bobs_profile.save() 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 # Charlie should have no access to Alice's stuff
self.charlie = User(username="charlie", email="[email protected]") self.charlie = User(username="charlie", email="[email protected]")


Loading…
Cancel
Save