forked from GithubBackups/healthchecks
Member.rw flag. Read-only users cannot edit check's name/desc/tags or schedule
This commit is contained in:
parent
84cc33412a
commit
00790dc33c
18
hc/accounts/migrations/0033_member_rw.py
Normal file
18
hc/accounts/migrations/0033_member_rw.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.1 on 2020-08-24 16:09
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0032_auto_20200819_0757'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='member',
|
||||||
|
name='rw',
|
||||||
|
field=models.BooleanField(default=True),
|
||||||
|
),
|
||||||
|
]
|
@ -379,6 +379,7 @@ class Member(models.Model):
|
|||||||
user = models.ForeignKey(User, models.CASCADE, related_name="memberships")
|
user = models.ForeignKey(User, models.CASCADE, related_name="memberships")
|
||||||
project = models.ForeignKey(Project, models.CASCADE)
|
project = models.ForeignKey(Project, models.CASCADE)
|
||||||
transfer_request_date = models.DateTimeField(null=True, blank=True)
|
transfer_request_date = models.DateTimeField(null=True, blank=True)
|
||||||
|
rw = models.BooleanField(default=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
|
@ -45,3 +45,14 @@ class DetailsTestCase(BaseTestCase):
|
|||||||
self.client.login(username="alice@example.org", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get(self.url + "?new")
|
r = self.client.get(self.url + "?new")
|
||||||
self.assertContains(r, "Your new check is ready!", status_code=200)
|
self.assertContains(r, "Your new check is ready!", status_code=200)
|
||||||
|
|
||||||
|
def test_it_hides_actions_from_readonly_users(self):
|
||||||
|
self.bobs_membership.rw = False
|
||||||
|
self.bobs_membership.save()
|
||||||
|
|
||||||
|
self.client.login(username="bob@example.org", password="password")
|
||||||
|
r = self.client.get(self.url)
|
||||||
|
|
||||||
|
self.assertNotContains(r, "edit-name", status_code=200)
|
||||||
|
self.assertNotContains(r, "edit-desc")
|
||||||
|
self.assertNotContains(r, "Change Schedule")
|
||||||
|
@ -41,6 +41,16 @@ class UpdateNameTestCase(BaseTestCase):
|
|||||||
r = self.client.post(self.url, data=payload)
|
r = self.client.post(self.url, data=payload)
|
||||||
self.assertEqual(r.status_code, 404)
|
self.assertEqual(r.status_code, 404)
|
||||||
|
|
||||||
|
def test_it_requires_rw_access(self):
|
||||||
|
self.bobs_membership.rw = False
|
||||||
|
self.bobs_membership.save()
|
||||||
|
|
||||||
|
payload = {"name": "Charlie Sent This"}
|
||||||
|
|
||||||
|
self.client.login(username="bob@example.org", password="password")
|
||||||
|
r = self.client.post(self.url, data=payload)
|
||||||
|
self.assertEqual(r.status_code, 403)
|
||||||
|
|
||||||
def test_it_handles_bad_uuid(self):
|
def test_it_handles_bad_uuid(self):
|
||||||
url = "/checks/not-uuid/name/"
|
url = "/checks/not-uuid/name/"
|
||||||
payload = {"name": "Alice Was Here"}
|
payload = {"name": "Alice Was Here"}
|
||||||
|
@ -180,3 +180,13 @@ class UpdateTimeoutTestCase(BaseTestCase):
|
|||||||
self.client.login(username="bob@example.org", password="password")
|
self.client.login(username="bob@example.org", password="password")
|
||||||
r = self.client.post(self.url, data=payload)
|
r = self.client.post(self.url, data=payload)
|
||||||
self.assertRedirects(r, self.redirect_url)
|
self.assertRedirects(r, self.redirect_url)
|
||||||
|
|
||||||
|
def test_it_requires_rw_access(self):
|
||||||
|
self.bobs_membership.rw = False
|
||||||
|
self.bobs_membership.save()
|
||||||
|
|
||||||
|
payload = {"kind": "simple", "timeout": 3600, "grace": 60}
|
||||||
|
|
||||||
|
self.client.login(username="bob@example.org", password="password")
|
||||||
|
r = self.client.post(self.url, data=payload)
|
||||||
|
self.assertEqual(r.status_code, 403)
|
||||||
|
@ -24,7 +24,7 @@ from django.urls import reverse
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.views.decorators.http import require_POST
|
from django.views.decorators.http import require_POST
|
||||||
from hc.accounts.models import Project
|
from hc.accounts.models import Project, Member
|
||||||
from hc.api.models import (
|
from hc.api.models import (
|
||||||
DEFAULT_GRACE,
|
DEFAULT_GRACE,
|
||||||
DEFAULT_TIMEOUT,
|
DEFAULT_TIMEOUT,
|
||||||
@ -85,15 +85,15 @@ def _get_check_for_user(request, code):
|
|||||||
|
|
||||||
assert request.user.is_authenticated
|
assert request.user.is_authenticated
|
||||||
|
|
||||||
q = Check.objects
|
check = get_object_or_404(Check.objects.select_related("project"), code=code)
|
||||||
if not request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
project_ids = request.profile.projects().values("id")
|
return check, True
|
||||||
q = q.filter(project_id__in=project_ids)
|
|
||||||
|
|
||||||
try:
|
if request.user.id == check.project.owner_id:
|
||||||
return q.get(code=code)
|
return check, True
|
||||||
except Check.DoesNotExist:
|
|
||||||
raise Http404("not found")
|
membership = get_object_or_404(Member, project=check.project, user=request.user)
|
||||||
|
return check, membership.rw
|
||||||
|
|
||||||
|
|
||||||
def _get_channel_for_user(request, code):
|
def _get_channel_for_user(request, code):
|
||||||
@ -113,17 +113,17 @@ def _get_channel_for_user(request, code):
|
|||||||
|
|
||||||
|
|
||||||
def _get_project_for_user(request, project_code):
|
def _get_project_for_user(request, project_code):
|
||||||
""" Return true if current user has access to the specified account. """
|
""" Check access, return (project, rw) tuple. """
|
||||||
|
|
||||||
|
project = get_object_or_404(Project, code=project_code)
|
||||||
if request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
q = Project.objects
|
return project, True
|
||||||
else:
|
|
||||||
q = request.profile.projects()
|
|
||||||
|
|
||||||
try:
|
if request.user.id == project.owner_id:
|
||||||
return q.get(code=project_code)
|
return project, True
|
||||||
except Project.DoesNotExist:
|
|
||||||
raise Http404("not found")
|
membership = get_object_or_404(Member, project=project, user=request.user)
|
||||||
|
return project, membership.rw
|
||||||
|
|
||||||
|
|
||||||
def _refresh_last_active_date(profile):
|
def _refresh_last_active_date(profile):
|
||||||
@ -138,7 +138,7 @@ def _refresh_last_active_date(profile):
|
|||||||
@login_required
|
@login_required
|
||||||
def my_checks(request, code):
|
def my_checks(request, code):
|
||||||
_refresh_last_active_date(request.profile)
|
_refresh_last_active_date(request.profile)
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.GET.get("sort") in VALID_SORT_VALUES:
|
if request.GET.get("sort") in VALID_SORT_VALUES:
|
||||||
request.profile.sort = request.GET["sort"]
|
request.profile.sort = request.GET["sort"]
|
||||||
@ -183,6 +183,7 @@ def my_checks(request, code):
|
|||||||
|
|
||||||
ctx = {
|
ctx = {
|
||||||
"page": "checks",
|
"page": "checks",
|
||||||
|
"rw": rw,
|
||||||
"checks": checks,
|
"checks": checks,
|
||||||
"channels": channels,
|
"channels": channels,
|
||||||
"num_down": num_down,
|
"num_down": num_down,
|
||||||
@ -228,7 +229,7 @@ def status(request, code):
|
|||||||
@login_required
|
@login_required
|
||||||
@require_POST
|
@require_POST
|
||||||
def switch_channel(request, code, channel_code):
|
def switch_channel(request, code, channel_code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
|
||||||
channel = get_object_or_404(Channel, code=channel_code)
|
channel = get_object_or_404(Channel, code=channel_code)
|
||||||
if channel.project_id != check.project_id:
|
if channel.project_id != check.project_id:
|
||||||
@ -321,7 +322,7 @@ def docs_cron(request):
|
|||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def add_check(request, code):
|
def add_check(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if project.num_checks_available() <= 0:
|
if project.num_checks_available() <= 0:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
@ -337,7 +338,10 @@ def add_check(request, code):
|
|||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def update_name(request, code):
|
def update_name(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
if not rw:
|
||||||
|
return HttpResponseForbidden()
|
||||||
|
|
||||||
form = forms.NameTagsForm(request.POST)
|
form = forms.NameTagsForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
check.name = form.cleaned_data["name"]
|
check.name = form.cleaned_data["name"]
|
||||||
@ -354,7 +358,7 @@ def update_name(request, code):
|
|||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def filtering_rules(request, code):
|
def filtering_rules(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
form = forms.FilteringRulesForm(request.POST)
|
form = forms.FilteringRulesForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
check.subject = form.cleaned_data["subject"]
|
check.subject = form.cleaned_data["subject"]
|
||||||
@ -369,7 +373,9 @@ def filtering_rules(request, code):
|
|||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def update_timeout(request, code):
|
def update_timeout(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
if not rw:
|
||||||
|
return HttpResponseForbidden()
|
||||||
|
|
||||||
kind = request.POST.get("kind")
|
kind = request.POST.get("kind")
|
||||||
if kind == "simple":
|
if kind == "simple":
|
||||||
@ -436,7 +442,7 @@ def cron_preview(request):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def ping_details(request, code, n=None):
|
def ping_details(request, code, n=None):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
q = Ping.objects.filter(owner=check)
|
q = Ping.objects.filter(owner=check)
|
||||||
if n:
|
if n:
|
||||||
q = q.filter(n=n)
|
q = q.filter(n=n)
|
||||||
@ -454,7 +460,7 @@ def ping_details(request, code, n=None):
|
|||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def pause(request, code):
|
def pause(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
|
||||||
check.status = "paused"
|
check.status = "paused"
|
||||||
check.last_start = None
|
check.last_start = None
|
||||||
@ -471,7 +477,7 @@ def pause(request, code):
|
|||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def resume(request, code):
|
def resume(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
|
||||||
check.status = "new"
|
check.status = "new"
|
||||||
check.last_start = None
|
check.last_start = None
|
||||||
@ -485,7 +491,7 @@ def resume(request, code):
|
|||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def remove_check(request, code):
|
def remove_check(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
project = check.project
|
project = check.project
|
||||||
check.delete()
|
check.delete()
|
||||||
return redirect("hc-checks", project.code)
|
return redirect("hc-checks", project.code)
|
||||||
@ -518,7 +524,7 @@ def _get_events(check, limit):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def log(request, code):
|
def log(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
|
||||||
limit = check.project.owner_profile.ping_log_limit
|
limit = check.project.owner_profile.ping_log_limit
|
||||||
ctx = {
|
ctx = {
|
||||||
@ -535,7 +541,7 @@ def log(request, code):
|
|||||||
@login_required
|
@login_required
|
||||||
def details(request, code):
|
def details(request, code):
|
||||||
_refresh_last_active_date(request.profile)
|
_refresh_last_active_date(request.profile)
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
|
||||||
channels = Channel.objects.filter(project=check.project)
|
channels = Channel.objects.filter(project=check.project)
|
||||||
channels = list(channels.order_by("created"))
|
channels = list(channels.order_by("created"))
|
||||||
@ -549,6 +555,7 @@ def details(request, code):
|
|||||||
"page": "details",
|
"page": "details",
|
||||||
"project": check.project,
|
"project": check.project,
|
||||||
"check": check,
|
"check": check,
|
||||||
|
"rw": rw,
|
||||||
"channels": channels,
|
"channels": channels,
|
||||||
"enabled_channels": list(check.channel_set.all()),
|
"enabled_channels": list(check.channel_set.all()),
|
||||||
"timezones": pytz.all_timezones,
|
"timezones": pytz.all_timezones,
|
||||||
@ -563,10 +570,10 @@ def details(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def transfer(request, code):
|
def transfer(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
target_project = _get_project_for_user(request, request.POST["project"])
|
target_project, rw = _get_project_for_user(request, request.POST["project"])
|
||||||
if target_project.num_checks_available() <= 0:
|
if target_project.num_checks_available() <= 0:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
@ -584,7 +591,7 @@ def transfer(request, code):
|
|||||||
@require_POST
|
@require_POST
|
||||||
@login_required
|
@login_required
|
||||||
def copy(request, code):
|
def copy(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
|
||||||
if check.project.num_checks_available() <= 0:
|
if check.project.num_checks_available() <= 0:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
@ -609,7 +616,7 @@ def copy(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def status_single(request, code):
|
def status_single(request, code):
|
||||||
check = _get_check_for_user(request, code)
|
check, rw = _get_check_for_user(request, code)
|
||||||
|
|
||||||
status = check.get_status()
|
status = check.get_status()
|
||||||
events = _get_events(check, 20)
|
events = _get_events(check, 20)
|
||||||
@ -633,7 +640,7 @@ def status_single(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def badges(request, code):
|
def badges(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
tags = set()
|
tags = set()
|
||||||
for check in Check.objects.filter(project=project):
|
for check in Check.objects.filter(project=project):
|
||||||
@ -665,7 +672,7 @@ def badges(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def channels(request, code):
|
def channels(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
code = request.POST["channel"]
|
code = request.POST["channel"]
|
||||||
@ -830,7 +837,7 @@ def remove_channel(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_email(request, code):
|
def add_email(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddEmailForm(request.POST)
|
form = forms.AddEmailForm(request.POST)
|
||||||
@ -875,7 +882,7 @@ def add_email(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_webhook(request, code):
|
def add_webhook(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.WebhookForm(request.POST)
|
form = forms.WebhookForm(request.POST)
|
||||||
@ -937,7 +944,7 @@ def edit_webhook(request, code):
|
|||||||
@require_setting("SHELL_ENABLED")
|
@require_setting("SHELL_ENABLED")
|
||||||
@login_required
|
@login_required
|
||||||
def add_shell(request, code):
|
def add_shell(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddShellForm(request.POST)
|
form = forms.AddShellForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@ -960,7 +967,7 @@ def add_shell(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_pd(request, code):
|
def add_pd(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddPdForm(request.POST)
|
form = forms.AddPdForm(request.POST)
|
||||||
@ -987,7 +994,7 @@ def pdc_help(request):
|
|||||||
@require_setting("PD_VENDOR_KEY")
|
@require_setting("PD_VENDOR_KEY")
|
||||||
@login_required
|
@login_required
|
||||||
def add_pdc(request, code):
|
def add_pdc(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
state = token_urlsafe()
|
state = token_urlsafe()
|
||||||
callback = settings.SITE_ROOT + reverse(
|
callback = settings.SITE_ROOT + reverse(
|
||||||
@ -1008,7 +1015,7 @@ def add_pdc_complete(request, code, state):
|
|||||||
if "pd" not in request.session:
|
if "pd" not in request.session:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
session_state = request.session.pop("pd")
|
session_state = request.session.pop("pd")
|
||||||
if session_state != state:
|
if session_state != state:
|
||||||
@ -1033,7 +1040,7 @@ def add_pdc_complete(request, code, state):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_pagertree(request, code):
|
def add_pagertree(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddUrlForm(request.POST)
|
form = forms.AddUrlForm(request.POST)
|
||||||
@ -1053,7 +1060,7 @@ def add_pagertree(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_slack(request, code):
|
def add_slack(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddUrlForm(request.POST)
|
form = forms.AddUrlForm(request.POST)
|
||||||
@ -1084,7 +1091,7 @@ def slack_help(request):
|
|||||||
@require_setting("SLACK_CLIENT_ID")
|
@require_setting("SLACK_CLIENT_ID")
|
||||||
@login_required
|
@login_required
|
||||||
def add_slack_btn(request, code):
|
def add_slack_btn(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
state = token_urlsafe()
|
state = token_urlsafe()
|
||||||
authorize_url = "https://slack.com/oauth/v2/authorize?" + urlencode(
|
authorize_url = "https://slack.com/oauth/v2/authorize?" + urlencode(
|
||||||
@ -1112,7 +1119,7 @@ def add_slack_complete(request):
|
|||||||
return HttpResponseForbidden()
|
return HttpResponseForbidden()
|
||||||
|
|
||||||
state, code = request.session.pop("add_slack")
|
state, code = request.session.pop("add_slack")
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if request.GET.get("error") == "access_denied":
|
if request.GET.get("error") == "access_denied":
|
||||||
messages.warning(request, "Slack setup was cancelled.")
|
messages.warning(request, "Slack setup was cancelled.")
|
||||||
return redirect("hc-p-channels", project.code)
|
return redirect("hc-p-channels", project.code)
|
||||||
@ -1145,7 +1152,7 @@ def add_slack_complete(request):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_mattermost(request, code):
|
def add_mattermost(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddUrlForm(request.POST)
|
form = forms.AddUrlForm(request.POST)
|
||||||
@ -1166,7 +1173,7 @@ def add_mattermost(request, code):
|
|||||||
@require_setting("PUSHBULLET_CLIENT_ID")
|
@require_setting("PUSHBULLET_CLIENT_ID")
|
||||||
@login_required
|
@login_required
|
||||||
def add_pushbullet(request, code):
|
def add_pushbullet(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
redirect_uri = settings.SITE_ROOT + reverse("hc-add-pushbullet-complete")
|
redirect_uri = settings.SITE_ROOT + reverse("hc-add-pushbullet-complete")
|
||||||
|
|
||||||
state = token_urlsafe()
|
state = token_urlsafe()
|
||||||
@ -1196,7 +1203,7 @@ def add_pushbullet_complete(request):
|
|||||||
return HttpResponseForbidden()
|
return HttpResponseForbidden()
|
||||||
|
|
||||||
state, code = request.session.pop("add_pushbullet")
|
state, code = request.session.pop("add_pushbullet")
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.GET.get("error") == "access_denied":
|
if request.GET.get("error") == "access_denied":
|
||||||
messages.warning(request, "Pushbullet setup was cancelled.")
|
messages.warning(request, "Pushbullet setup was cancelled.")
|
||||||
@ -1231,7 +1238,7 @@ def add_pushbullet_complete(request):
|
|||||||
@require_setting("DISCORD_CLIENT_ID")
|
@require_setting("DISCORD_CLIENT_ID")
|
||||||
@login_required
|
@login_required
|
||||||
def add_discord(request, code):
|
def add_discord(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
redirect_uri = settings.SITE_ROOT + reverse("hc-add-discord-complete")
|
redirect_uri = settings.SITE_ROOT + reverse("hc-add-discord-complete")
|
||||||
state = token_urlsafe()
|
state = token_urlsafe()
|
||||||
auth_url = "https://discordapp.com/api/oauth2/authorize?" + urlencode(
|
auth_url = "https://discordapp.com/api/oauth2/authorize?" + urlencode(
|
||||||
@ -1257,7 +1264,7 @@ def add_discord_complete(request):
|
|||||||
return HttpResponseForbidden()
|
return HttpResponseForbidden()
|
||||||
|
|
||||||
state, code = request.session.pop("add_discord")
|
state, code = request.session.pop("add_discord")
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.GET.get("error") == "access_denied":
|
if request.GET.get("error") == "access_denied":
|
||||||
messages.warning(request, "Discord setup was cancelled.")
|
messages.warning(request, "Discord setup was cancelled.")
|
||||||
@ -1300,7 +1307,7 @@ def pushover_help(request):
|
|||||||
@require_setting("PUSHOVER_API_TOKEN")
|
@require_setting("PUSHOVER_API_TOKEN")
|
||||||
@login_required
|
@login_required
|
||||||
def add_pushover(request, code):
|
def add_pushover(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
state = token_urlsafe()
|
state = token_urlsafe()
|
||||||
@ -1365,7 +1372,7 @@ def add_pushover(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_opsgenie(request, code):
|
def add_opsgenie(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddOpsGenieForm(request.POST)
|
form = forms.AddOpsGenieForm(request.POST)
|
||||||
@ -1386,7 +1393,7 @@ def add_opsgenie(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_victorops(request, code):
|
def add_victorops(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddUrlForm(request.POST)
|
form = forms.AddUrlForm(request.POST)
|
||||||
@ -1406,7 +1413,7 @@ def add_victorops(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_zulip(request, code):
|
def add_zulip(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddZulipForm(request.POST)
|
form = forms.AddZulipForm(request.POST)
|
||||||
@ -1474,7 +1481,7 @@ def add_telegram(request):
|
|||||||
return render(request, "bad_link.html")
|
return render(request, "bad_link.html")
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
project = _get_project_for_user(request, request.POST.get("project"))
|
project, rw = _get_project_for_user(request, request.POST.get("project"))
|
||||||
channel = Channel(project=project, kind="telegram")
|
channel = Channel(project=project, kind="telegram")
|
||||||
channel.value = json.dumps(
|
channel.value = json.dumps(
|
||||||
{"id": chat_id, "type": chat_type, "name": chat_name}
|
{"id": chat_id, "type": chat_type, "name": chat_name}
|
||||||
@ -1500,7 +1507,7 @@ def add_telegram(request):
|
|||||||
@require_setting("TWILIO_AUTH")
|
@require_setting("TWILIO_AUTH")
|
||||||
@login_required
|
@login_required
|
||||||
def add_sms(request, code):
|
def add_sms(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddSmsForm(request.POST)
|
form = forms.AddSmsForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@ -1526,7 +1533,7 @@ def add_sms(request, code):
|
|||||||
@require_setting("TWILIO_AUTH")
|
@require_setting("TWILIO_AUTH")
|
||||||
@login_required
|
@login_required
|
||||||
def add_call(request, code):
|
def add_call(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddSmsForm(request.POST)
|
form = forms.AddSmsForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@ -1552,7 +1559,7 @@ def add_call(request, code):
|
|||||||
@require_setting("TWILIO_USE_WHATSAPP")
|
@require_setting("TWILIO_USE_WHATSAPP")
|
||||||
@login_required
|
@login_required
|
||||||
def add_whatsapp(request, code):
|
def add_whatsapp(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddSmsForm(request.POST)
|
form = forms.AddSmsForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@ -1584,7 +1591,7 @@ def add_whatsapp(request, code):
|
|||||||
@require_setting("TRELLO_APP_KEY")
|
@require_setting("TRELLO_APP_KEY")
|
||||||
@login_required
|
@login_required
|
||||||
def add_trello(request, code):
|
def add_trello(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
channel = Channel(project=project, kind="trello")
|
channel = Channel(project=project, kind="trello")
|
||||||
channel.value = request.POST["settings"]
|
channel.value = request.POST["settings"]
|
||||||
@ -1617,7 +1624,7 @@ def add_trello(request, code):
|
|||||||
@require_setting("MATRIX_ACCESS_TOKEN")
|
@require_setting("MATRIX_ACCESS_TOKEN")
|
||||||
@login_required
|
@login_required
|
||||||
def add_matrix(request, code):
|
def add_matrix(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddMatrixForm(request.POST)
|
form = forms.AddMatrixForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@ -1649,7 +1656,7 @@ def add_matrix(request, code):
|
|||||||
@require_setting("APPRISE_ENABLED")
|
@require_setting("APPRISE_ENABLED")
|
||||||
@login_required
|
@login_required
|
||||||
def add_apprise(request, code):
|
def add_apprise(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddAppriseForm(request.POST)
|
form = forms.AddAppriseForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@ -1690,7 +1697,7 @@ def trello_settings(request):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_msteams(request, code):
|
def add_msteams(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddUrlForm(request.POST)
|
form = forms.AddUrlForm(request.POST)
|
||||||
@ -1710,7 +1717,7 @@ def add_msteams(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_prometheus(request, code):
|
def add_prometheus(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
ctx = {"page": "channels", "project": project}
|
ctx = {"page": "channels", "project": project}
|
||||||
return render(request, "integrations/add_prometheus.html", ctx)
|
return render(request, "integrations/add_prometheus.html", ctx)
|
||||||
|
|
||||||
@ -1763,7 +1770,7 @@ def metrics(request, code, key):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_spike(request, code):
|
def add_spike(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddUrlForm(request.POST)
|
form = forms.AddUrlForm(request.POST)
|
||||||
@ -1783,7 +1790,7 @@ def add_spike(request, code):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def add_linenotify(request, code):
|
def add_linenotify(request, code):
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = forms.AddLineNotifyForm(request.POST)
|
form = forms.AddLineNotifyForm(request.POST)
|
||||||
|
@ -20,7 +20,7 @@ def pricing(request, code=None):
|
|||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
project = _get_project_for_user(request, code)
|
project, rw = _get_project_for_user(request, code)
|
||||||
if project.owner != request.user:
|
if project.owner != request.user:
|
||||||
ctx = {"page": "pricing", "project": project}
|
ctx = {"page": "pricing", "project": project}
|
||||||
return render(request, "payments/pricing_not_owner.html", ctx)
|
return render(request, "payments/pricing_not_owner.html", ctx)
|
||||||
|
@ -40,9 +40,9 @@
|
|||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#checks-table tr:hover .my-checks-name,
|
#checks-table.rw tr:hover .my-checks-name,
|
||||||
#checks-table tr:hover .integrations,
|
#checks-table.rw tr:hover .integrations,
|
||||||
#checks-table tr:hover .timeout-grace,
|
#checks-table.rw tr:hover .timeout-grace,
|
||||||
#checks-table tr:hover .last-ping {
|
#checks-table tr:hover .last-ping {
|
||||||
border: 1px dotted #AAA;
|
border: 1px dotted #AAA;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
$(function () {
|
$(function () {
|
||||||
var base = document.getElementById("base-url").getAttribute("href").slice(0, -1);
|
var base = document.getElementById("base-url").getAttribute("href").slice(0, -1);
|
||||||
|
|
||||||
$(".my-checks-name").click(function() {
|
$(".rw .my-checks-name").click(function() {
|
||||||
var code = $(this).closest("tr.checks-row").attr("id");
|
var code = $(this).closest("tr.checks-row").attr("id");
|
||||||
var url = base + "/checks/" + code + "/name/";
|
var url = base + "/checks/" + code + "/name/";
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ $(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".integrations").on("click", "span", function() {
|
$(".rw .integrations").on("click", "span", function() {
|
||||||
var isOff = $(this).toggleClass("off").hasClass("off");
|
var isOff = $(this).toggleClass("off").hasClass("off");
|
||||||
var token = $('input[name=csrfmiddlewaretoken]').val();
|
var token = $('input[name=csrfmiddlewaretoken]').val();
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ $(function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var statusUrl = document.getElementById("edit-timeout").dataset.statusUrl;
|
var statusUrl = document.getElementById("events").dataset.statusUrl;
|
||||||
var lastStatusText = "";
|
var lastStatusText = "";
|
||||||
var lastUpdated = "";
|
var lastUpdated = "";
|
||||||
adaptiveSetInterval(function() {
|
adaptiveSetInterval(function() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
$(function () {
|
$(function () {
|
||||||
var base = document.getElementById("base-url").getAttribute("href").slice(0, -1);
|
var base = document.getElementById("base-url").getAttribute("href").slice(0, -1);
|
||||||
|
|
||||||
$(".timeout-grace").click(function() {
|
$(".rw .timeout-grace").click(function() {
|
||||||
var code = $(this).closest("tr.checks-row").attr("id");
|
var code = $(this).closest("tr.checks-row").attr("id");
|
||||||
if (!code) {
|
if (!code) {
|
||||||
code = this.dataset.code;
|
code = this.dataset.code;
|
||||||
|
@ -41,7 +41,9 @@
|
|||||||
<div id="details-head" class="col-sm-12">
|
<div id="details-head" class="col-sm-12">
|
||||||
<h1>
|
<h1>
|
||||||
{{ check.name_then_code }}
|
{{ check.name_then_code }}
|
||||||
|
{% if rw %}
|
||||||
<small><a id="edit-name" href="#">(edit…)</a></small>
|
<small><a id="edit-name" href="#">(edit…)</a></small>
|
||||||
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
{% for tag in check.tags_list %}
|
{% for tag in check.tags_list %}
|
||||||
<span class="label label-tag">{{ tag }}</span>
|
<span class="label label-tag">{{ tag }}</span>
|
||||||
@ -49,6 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-5">
|
<div class="col-sm-5">
|
||||||
|
{% if rw %}
|
||||||
<div class="details-block">
|
<div class="details-block">
|
||||||
<h2>Description</h2>
|
<h2>Description</h2>
|
||||||
{% if check.desc %}
|
{% if check.desc %}
|
||||||
@ -62,6 +65,12 @@
|
|||||||
<small><a id="edit-desc" href="#">Add description…</a></small>
|
<small><a id="edit-desc" href="#">Add description…</a></small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% elif check.desc %}
|
||||||
|
<div class="details-block">
|
||||||
|
<h2>Description</h2>
|
||||||
|
{{ check.desc|linebreaks|urlize }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div id="how-to-ping" class="details-block">
|
<div id="how-to-ping" class="details-block">
|
||||||
<h2>How To Ping</h2>
|
<h2>How To Ping</h2>
|
||||||
@ -173,7 +182,8 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="text-right">
|
{% if rw %}
|
||||||
|
<div class="text-right rw">
|
||||||
<button
|
<button
|
||||||
id="edit-timeout"
|
id="edit-timeout"
|
||||||
class="btn btn-sm btn-default timeout-grace"
|
class="btn btn-sm btn-default timeout-grace"
|
||||||
@ -186,6 +196,7 @@
|
|||||||
data-tz="{{ check.tz }}">
|
data-tz="{{ check.tz }}">
|
||||||
Change Schedule…</button>
|
Change Schedule…</button>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="details-block">
|
<div class="details-block">
|
||||||
@ -248,7 +259,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="events" class="col-sm-7">
|
<div id="events" class="col-sm-7" data-status-url="{% url 'hc-status-single' check.code %}">
|
||||||
<h2>
|
<h2>
|
||||||
Log
|
Log
|
||||||
<small class="hidden-xs">Click on individual items for details</small>
|
<small class="hidden-xs">Click on individual items for details</small>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% load hc_extras static %}
|
{% load hc_extras static %}
|
||||||
<table
|
<table
|
||||||
id="checks-table"
|
id="checks-table"
|
||||||
class="table"
|
class="table {% if rw %}rw{% endif%}"
|
||||||
data-list-url="{% url 'hc-checks' project.code %}"
|
data-list-url="{% url 'hc-checks' project.code %}"
|
||||||
data-status-url="{% url 'hc-status' project.code %}">
|
data-status-url="{% url 'hc-status' project.code %}">
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -128,7 +128,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||||
<button id="update-cron-submit" type="submit" class="btn btn-primary">
|
<button id="update-cron-submit" type="submit" class="btn btn-primary" {% if not rw %}disabled{% endif %}>
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user