forked from GithubBackups/healthchecks
Project model. cc: #183
This commit is contained in:
parent
b4635c69e7
commit
1c69cf7f89
@ -9,6 +9,8 @@ All notable changes to this project will be documented in this file.
|
||||
- Database schema: add Ping.kind field
|
||||
- Database schema: remove Ping.start and Ping.fail fields
|
||||
- Add "Email Settings..." dialog and "Subject Must Contain" setting
|
||||
- Database schema: add the Project model
|
||||
|
||||
|
||||
|
||||
## 1.4.0 - 2018-12-25
|
||||
|
||||
@ -5,7 +5,7 @@ from django.db.models import Count
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils.safestring import mark_safe
|
||||
from hc.accounts.models import Profile
|
||||
from hc.accounts.models import Profile, Project
|
||||
|
||||
|
||||
class Fieldset:
|
||||
@ -85,6 +85,15 @@ class ProfileAdmin(admin.ModelAdmin):
|
||||
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):
|
||||
actions = ["send_report"]
|
||||
list_display = ('id', 'email', 'date_joined', 'last_login', 'engagement',
|
||||
|
||||
@ -16,4 +16,8 @@ class TeamAccessMiddleware(object):
|
||||
request.profile = Profile.objects.for_user(request.user)
|
||||
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)
|
||||
|
||||
38
hc/accounts/migrations/0017_auto_20190112_1426.py
Normal file
38
hc/accounts/migrations/0017_auto_20190112_1426.py
Normal 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
hc/accounts/migrations/0018_auto_20190112_1426.py
Normal file
37
hc/accounts/migrations/0018_auto_20190112_1426.py
Normal 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),
|
||||
]
|
||||
@ -1,6 +1,7 @@
|
||||
from base64 import urlsafe_b64encode
|
||||
import os
|
||||
from datetime import timedelta
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from django.conf import settings
|
||||
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_readonly = models.CharField(max_length=128, blank=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)
|
||||
sms_limit = 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
|
||||
|
||||
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
|
||||
# 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"))
|
||||
|
||||
|
||||
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):
|
||||
team = models.ForeignKey(Profile, models.CASCADE)
|
||||
user = models.ForeignKey(User, models.CASCADE, related_name="memberships")
|
||||
project = models.ForeignKey(Project, models.CASCADE, null=True)
|
||||
|
||||
@ -27,6 +27,7 @@ class CloseAccountTestCase(BaseTestCase):
|
||||
# Bob's current team should now be None
|
||||
self.bobs_profile.refresh_from_db()
|
||||
self.assertIsNone(self.bobs_profile.current_team)
|
||||
self.assertIsNone(self.bobs_profile.current_project)
|
||||
|
||||
# Check should be gone
|
||||
self.assertFalse(Check.objects.exists())
|
||||
|
||||
@ -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("frank@example.org" in member_emails)
|
||||
frank_found = False
|
||||
for member in members.all():
|
||||
self.assertEqual(member.project, self.project)
|
||||
if member.user.email == "frank@example.org":
|
||||
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="alice@example.org", 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="bob@example.org", 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="alice@example.org", password="password")
|
||||
|
||||
@ -2,7 +2,8 @@ from django.contrib.auth.models import User
|
||||
from django.core import mail
|
||||
from django.test import TestCase
|
||||
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
|
||||
|
||||
|
||||
@ -15,16 +16,25 @@ class SignupTestCase(TestCase):
|
||||
self.assertContains(r, "Account created")
|
||||
|
||||
# An user should have been created
|
||||
self.assertEqual(User.objects.count(), 1)
|
||||
user = User.objects.get()
|
||||
|
||||
# And email sent
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
subject = "Log in to %s" % settings.SITE_NAME
|
||||
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
|
||||
check = Check.objects.get()
|
||||
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)
|
||||
def test_it_obeys_registration_open(self):
|
||||
|
||||
@ -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="charlie@example.org", password="password")
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ from hc.accounts.forms import (ChangeEmailForm, EmailPasswordForm,
|
||||
ReportSettingsForm, SetPasswordForm,
|
||||
TeamNameForm, AvailableEmailForm,
|
||||
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.lib.badges import get_badge_url
|
||||
from hc.payments.models import Subscription
|
||||
@ -49,14 +49,19 @@ def _make_user(email):
|
||||
user.set_unusable_password()
|
||||
user.save()
|
||||
|
||||
# Ensure a profile gets created
|
||||
Profile.objects.for_user(user)
|
||||
project = Project(owner=user)
|
||||
project.save()
|
||||
|
||||
check = Check(user=user)
|
||||
# Ensure a profile gets created
|
||||
profile = Profile.objects.for_user(user)
|
||||
profile.current_project = project
|
||||
profile.save()
|
||||
|
||||
check = Check(user=user, project=project)
|
||||
check.name = "My First Check"
|
||||
check.save()
|
||||
|
||||
channel = Channel(user=user)
|
||||
channel = Channel(user=user, project=project)
|
||||
channel.kind = "email"
|
||||
channel.value = email
|
||||
channel.email_verified = True
|
||||
@ -72,7 +77,10 @@ def _ensure_own_team(request):
|
||||
|
||||
if request.team != request.profile:
|
||||
request.team = request.profile
|
||||
request.project = request.user.project_set.first()
|
||||
|
||||
request.profile.current_team = request.profile
|
||||
request.profile.current_project = request.project
|
||||
request.profile.save()
|
||||
|
||||
|
||||
@ -200,6 +208,12 @@ def profile(request):
|
||||
return redirect("hc-link-sent")
|
||||
elif "create_api_keys" in request.POST:
|
||||
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["api_keys_created"] = True
|
||||
ctx["api_status"] = "success"
|
||||
@ -208,6 +222,12 @@ def profile(request):
|
||||
profile.api_key = ""
|
||||
profile.api_key_readonly = ""
|
||||
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_status"] = "info"
|
||||
elif "show_api_keys" in request.POST:
|
||||
@ -236,6 +256,7 @@ def profile(request):
|
||||
email = form.cleaned_data["email"]
|
||||
farewell_user = User.objects.get(email=email)
|
||||
farewell_user.profile.current_team = None
|
||||
farewell_user.profile.current_project = None
|
||||
farewell_user.profile.save()
|
||||
|
||||
Member.objects.filter(team=profile,
|
||||
@ -248,6 +269,11 @@ def profile(request):
|
||||
if form.is_valid():
|
||||
profile.team_name = form.cleaned_data["team_name"]
|
||||
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_status"] = "success"
|
||||
|
||||
@ -427,6 +453,7 @@ def switch_team(request, target_username):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
request.profile.current_team = target_team
|
||||
request.profile.current_project = target_team.user.project_set.first()
|
||||
request.profile.save()
|
||||
|
||||
return redirect("hc-checks")
|
||||
|
||||
@ -24,6 +24,7 @@ def authorize(f):
|
||||
|
||||
try:
|
||||
request.user = User.objects.get(profile__api_key=api_key)
|
||||
request.project = request.user.project_set.first()
|
||||
except User.DoesNotExist:
|
||||
return error("wrong api key", 401)
|
||||
|
||||
@ -46,6 +47,7 @@ def authorize_read(f):
|
||||
read_key_match = Q(profile__api_key_readonly=api_key)
|
||||
try:
|
||||
request.user = User.objects.get(write_key_match | read_key_match)
|
||||
request.project = request.user.project_set.first()
|
||||
except User.DoesNotExist:
|
||||
return error("wrong api key", 401)
|
||||
|
||||
|
||||
25
hc/api/migrations/0054_auto_20190112_1427.py
Normal file
25
hc/api/migrations/0054_auto_20190112_1427.py
Normal 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
hc/api/migrations/0055_auto_20190112_1427.py
Normal file
23
hc/api/migrations/0055_auto_20190112_1427.py
Normal 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),
|
||||
]
|
||||
@ -12,6 +12,7 @@ from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from hc.accounts.models import Project
|
||||
from hc.api import transports
|
||||
from hc.lib import emails
|
||||
import requests
|
||||
@ -67,6 +68,7 @@ class Check(models.Model):
|
||||
code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
|
||||
desc = models.TextField(blank=True)
|
||||
user = models.ForeignKey(User, models.CASCADE)
|
||||
project = models.ForeignKey(Project, models.CASCADE, null=True)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
kind = models.CharField(max_length=10, default="simple",
|
||||
choices=CHECK_KINDS)
|
||||
@ -262,6 +264,7 @@ class Channel(models.Model):
|
||||
name = models.CharField(max_length=100, blank=True)
|
||||
code = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
|
||||
user = models.ForeignKey(User, models.CASCADE)
|
||||
project = models.ForeignKey(Project, models.CASCADE, null=True,)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
kind = models.CharField(max_length=20, choices=CHANNEL_KINDS)
|
||||
value = models.TextField(blank=True)
|
||||
|
||||
@ -47,6 +47,7 @@ class CreateCheckTestCase(BaseTestCase):
|
||||
self.assertEqual(check.tags, "bar,baz")
|
||||
self.assertEqual(check.timeout.total_seconds(), 3600)
|
||||
self.assertEqual(check.grace.total_seconds(), 60)
|
||||
self.assertEqual(check.project, self.project)
|
||||
|
||||
def test_it_handles_options(self):
|
||||
r = self.client.options(self.URL)
|
||||
|
||||
@ -132,7 +132,7 @@ def create_check(request):
|
||||
if num_checks >= request.user.profile.check_limit:
|
||||
return HttpResponseForbidden()
|
||||
|
||||
check = Check(user=request.user)
|
||||
check = Check(user=request.user, project=request.project)
|
||||
created = True
|
||||
|
||||
_update(check, request.json)
|
||||
|
||||
@ -9,7 +9,19 @@ class AddCheckTestCase(BaseTestCase):
|
||||
self.client.login(username="alice@example.org", 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="alice@example.org", 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/"
|
||||
|
||||
@ -51,6 +51,7 @@ class AddDiscordTestCase(BaseTestCase):
|
||||
|
||||
ch = Channel.objects.get()
|
||||
self.assertEqual(ch.discord_webhook_url, "foo")
|
||||
self.assertEqual(ch.project, self.project)
|
||||
|
||||
# Session should now be clean
|
||||
self.assertFalse("discord" in self.client.session)
|
||||
|
||||
@ -21,6 +21,7 @@ class AddPdTestCase(BaseTestCase):
|
||||
self.assertEqual(c.kind, "email")
|
||||
self.assertEqual(c.value, "alice@example.org")
|
||||
self.assertFalse(c.email_verified)
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
def test_team_access_works(self):
|
||||
form = {"value": "bob@example.org"}
|
||||
|
||||
@ -34,3 +34,4 @@ class AddHipChatTestCase(BaseTestCase):
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.kind, "hipchat")
|
||||
self.assertEqual(c.value, "{}")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
@ -20,6 +20,7 @@ class AddOpsGenieTestCase(BaseTestCase):
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.kind, "opsgenie")
|
||||
self.assertEqual(c.value, "123456")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
def test_it_trims_whitespace(self):
|
||||
form = {"value": " 123456 "}
|
||||
|
||||
@ -20,6 +20,7 @@ class AddPagerTreeTestCase(BaseTestCase):
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.kind, "pagertree")
|
||||
self.assertEqual(c.value, "http://example.org")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
def test_it_rejects_bad_url(self):
|
||||
form = {"value": "not an URL"}
|
||||
|
||||
@ -25,6 +25,7 @@ class AddPdTestCase(BaseTestCase):
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.kind, "pd")
|
||||
self.assertEqual(c.pd_service_key, "123")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
def test_it_validates_code(self):
|
||||
session = self.client.session
|
||||
|
||||
@ -45,6 +45,7 @@ class AddPushbulletTestCase(BaseTestCase):
|
||||
|
||||
ch = Channel.objects.get()
|
||||
self.assertEqual(ch.value, "test-token")
|
||||
self.assertEqual(ch.project, self.project)
|
||||
|
||||
# Session should now be clean
|
||||
self.assertFalse("pushbullet" in self.client.session)
|
||||
|
||||
@ -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="alice@example.org", password="password")
|
||||
|
||||
@ -22,6 +22,7 @@ class AddSlackTestCase(BaseTestCase):
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.kind, "slack")
|
||||
self.assertEqual(c.value, "http://example.org")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
@override_settings(SLACK_CLIENT_ID=None)
|
||||
def test_it_rejects_bad_url(self):
|
||||
|
||||
@ -54,6 +54,7 @@ class AddSlackBtnTestCase(BaseTestCase):
|
||||
self.assertEqual(ch.slack_team, "foo")
|
||||
self.assertEqual(ch.slack_channel, "bar")
|
||||
self.assertEqual(ch.slack_webhook_url, "http://example.org")
|
||||
self.assertEqual(ch.project, self.project)
|
||||
|
||||
# Session should now be clean
|
||||
self.assertFalse("slack" in self.client.session)
|
||||
|
||||
@ -32,6 +32,7 @@ class AddSmsTestCase(BaseTestCase):
|
||||
self.assertEqual(c.kind, "sms")
|
||||
self.assertEqual(c.sms_number, "+1234567890")
|
||||
self.assertEqual(c.name, "My Phone")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
def test_it_rejects_bad_number(self):
|
||||
form = {"value": "not a phone number address"}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import json
|
||||
|
||||
from django.core import signing
|
||||
from hc.api.models import Channel
|
||||
from hc.test import BaseTestCase
|
||||
@ -33,6 +31,7 @@ class AddTelegramTestCase(BaseTestCase):
|
||||
self.assertEqual(c.telegram_id, 123)
|
||||
self.assertEqual(c.telegram_type, "group")
|
||||
self.assertEqual(c.telegram_name, "My Group")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
@patch("hc.api.transports.requests.request")
|
||||
def test_it_sends_invite(self, mock_get):
|
||||
|
||||
@ -20,6 +20,7 @@ class AddVictorOpsTestCase(BaseTestCase):
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.kind, "victorops")
|
||||
self.assertEqual(c.value, "http://example.org")
|
||||
self.assertEqual(c.project, self.project)
|
||||
|
||||
def test_it_rejects_bad_url(self):
|
||||
form = {"value": "not an URL"}
|
||||
|
||||
@ -19,6 +19,7 @@ class AddWebhookTestCase(BaseTestCase):
|
||||
|
||||
c = Channel.objects.get()
|
||||
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):
|
||||
form = {"url_down": "http://foo.com", "url_up": "https://bar.com"}
|
||||
|
||||
@ -249,7 +249,7 @@ def add_check(request):
|
||||
if num_checks >= request.team.check_limit:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
check = Check(user=request.team.user)
|
||||
check = Check(user=request.team.user, project=request.project)
|
||||
check.save()
|
||||
|
||||
check.assign_all_channels()
|
||||
@ -589,6 +589,7 @@ def add_email(request):
|
||||
form = AddEmailForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(user=request.team.user, kind="email")
|
||||
channel.project = request.project
|
||||
channel.value = form.cleaned_data["value"]
|
||||
channel.save()
|
||||
|
||||
@ -608,6 +609,7 @@ def add_webhook(request):
|
||||
form = AddWebhookForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(user=request.team.user, kind="webhook")
|
||||
channel.project = request.project
|
||||
channel.value = form.get_value()
|
||||
channel.save()
|
||||
|
||||
@ -658,9 +660,8 @@ def add_pd(request, state=None):
|
||||
messages.warning(request, "PagerDuty setup was cancelled")
|
||||
return redirect("hc-channels")
|
||||
|
||||
channel = Channel()
|
||||
channel = Channel(kind="pd", project=request.project)
|
||||
channel.user = request.team.user
|
||||
channel.kind = "pd"
|
||||
channel.value = json.dumps({
|
||||
"service_key": request.GET.get("service_key"),
|
||||
"account": request.GET.get("account")
|
||||
@ -687,6 +688,7 @@ def add_pagertree(request):
|
||||
form = AddUrlForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(user=request.team.user, kind="pagertree")
|
||||
channel.project = request.project
|
||||
channel.value = form.cleaned_data["value"]
|
||||
channel.save()
|
||||
|
||||
@ -707,6 +709,7 @@ def add_slack(request):
|
||||
form = AddUrlForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(user=request.team.user, kind="slack")
|
||||
channel.project = request.project
|
||||
channel.value = form.cleaned_data["value"]
|
||||
channel.save()
|
||||
|
||||
@ -741,9 +744,8 @@ def add_slack_btn(request):
|
||||
|
||||
doc = result.json()
|
||||
if doc.get("ok"):
|
||||
channel = Channel()
|
||||
channel = Channel(kind="slack", project=request.project)
|
||||
channel.user = request.team.user
|
||||
channel.kind = "slack"
|
||||
channel.value = result.text
|
||||
channel.save()
|
||||
channel.assign_all_checks()
|
||||
@ -765,7 +767,7 @@ def add_hipchat(request):
|
||||
messages.warning(request, "Something went wrong!")
|
||||
return redirect("hc-channels")
|
||||
|
||||
channel = Channel(kind="hipchat")
|
||||
channel = Channel(kind="hipchat", project=request.project)
|
||||
channel.user = request.team.user
|
||||
channel.value = response.text
|
||||
channel.save()
|
||||
@ -810,7 +812,7 @@ def add_pushbullet(request):
|
||||
|
||||
doc = result.json()
|
||||
if "access_token" in doc:
|
||||
channel = Channel(kind="pushbullet")
|
||||
channel = Channel(kind="pushbullet", project=request.project)
|
||||
channel.user = request.team.user
|
||||
channel.value = doc["access_token"]
|
||||
channel.save()
|
||||
@ -858,7 +860,7 @@ def add_discord(request):
|
||||
|
||||
doc = result.json()
|
||||
if "access_token" in doc:
|
||||
channel = Channel(kind="discord")
|
||||
channel = Channel(kind="discord", project=request.project)
|
||||
channel.user = request.team.user
|
||||
channel.value = result.text
|
||||
channel.save()
|
||||
@ -933,6 +935,7 @@ def add_pushover(request):
|
||||
|
||||
# Subscription
|
||||
channel = Channel(user=request.team.user, kind="po")
|
||||
channel.project = request.project
|
||||
channel.value = "%s|%s|%s" % (key, prio, prio_up)
|
||||
channel.save()
|
||||
channel.assign_all_checks()
|
||||
@ -955,6 +958,7 @@ def add_opsgenie(request):
|
||||
form = AddOpsGenieForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(user=request.team.user, kind="opsgenie")
|
||||
channel.project = request.project
|
||||
channel.value = form.cleaned_data["value"]
|
||||
channel.save()
|
||||
|
||||
@ -973,6 +977,7 @@ def add_victorops(request):
|
||||
form = AddUrlForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(user=request.team.user, kind="victorops")
|
||||
channel.project = request.project
|
||||
channel.value = form.cleaned_data["value"]
|
||||
channel.save()
|
||||
|
||||
@ -1021,6 +1026,7 @@ def add_telegram(request):
|
||||
|
||||
if request.method == "POST":
|
||||
channel = Channel(user=request.team.user, kind="telegram")
|
||||
channel.project = request.project
|
||||
channel.value = json.dumps({
|
||||
"id": chat_id,
|
||||
"type": chat_type,
|
||||
@ -1051,6 +1057,7 @@ def add_sms(request):
|
||||
form = AddSmsForm(request.POST)
|
||||
if form.is_valid():
|
||||
channel = Channel(user=request.team.user, kind="sms")
|
||||
channel.project = request.project
|
||||
channel.name = form.cleaned_data["label"]
|
||||
channel.value = json.dumps({
|
||||
"value": form.cleaned_data["value"]
|
||||
|
||||
10
hc/test.py
10
hc/test.py
@ -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="charlie@example.org")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user