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")
|
||||
project = models.ForeignKey(Project, models.CASCADE)
|
||||
transfer_request_date = models.DateTimeField(null=True, blank=True)
|
||||
rw = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
constraints = [
|
||||
|
@ -45,3 +45,14 @@ class DetailsTestCase(BaseTestCase):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url + "?new")
|
||||
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)
|
||||
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):
|
||||
url = "/checks/not-uuid/name/"
|
||||
payload = {"name": "Alice Was Here"}
|
||||
|
@ -180,3 +180,13 @@ class UpdateTimeoutTestCase(BaseTestCase):
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
r = self.client.post(self.url, data=payload)
|
||||
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.views.decorators.csrf import csrf_exempt
|
||||
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 (
|
||||
DEFAULT_GRACE,
|
||||
DEFAULT_TIMEOUT,
|
||||
@ -85,15 +85,15 @@ def _get_check_for_user(request, code):
|
||||
|
||||
assert request.user.is_authenticated
|
||||
|
||||
q = Check.objects
|
||||
if not request.user.is_superuser:
|
||||
project_ids = request.profile.projects().values("id")
|
||||
q = q.filter(project_id__in=project_ids)
|
||||
check = get_object_or_404(Check.objects.select_related("project"), code=code)
|
||||
if request.user.is_superuser:
|
||||
return check, True
|
||||
|
||||
try:
|
||||
return q.get(code=code)
|
||||
except Check.DoesNotExist:
|
||||
raise Http404("not found")
|
||||
if request.user.id == check.project.owner_id:
|
||||
return check, True
|
||||
|
||||
membership = get_object_or_404(Member, project=check.project, user=request.user)
|
||||
return check, membership.rw
|
||||
|
||||
|
||||
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):
|
||||
""" 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:
|
||||
q = Project.objects
|
||||
else:
|
||||
q = request.profile.projects()
|
||||
return project, True
|
||||
|
||||
try:
|
||||
return q.get(code=project_code)
|
||||
except Project.DoesNotExist:
|
||||
raise Http404("not found")
|
||||
if request.user.id == project.owner_id:
|
||||
return project, True
|
||||
|
||||
membership = get_object_or_404(Member, project=project, user=request.user)
|
||||
return project, membership.rw
|
||||
|
||||
|
||||
def _refresh_last_active_date(profile):
|
||||
@ -138,7 +138,7 @@ def _refresh_last_active_date(profile):
|
||||
@login_required
|
||||
def my_checks(request, code):
|
||||
_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:
|
||||
request.profile.sort = request.GET["sort"]
|
||||
@ -183,6 +183,7 @@ def my_checks(request, code):
|
||||
|
||||
ctx = {
|
||||
"page": "checks",
|
||||
"rw": rw,
|
||||
"checks": checks,
|
||||
"channels": channels,
|
||||
"num_down": num_down,
|
||||
@ -228,7 +229,7 @@ def status(request, code):
|
||||
@login_required
|
||||
@require_POST
|
||||
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)
|
||||
if channel.project_id != check.project_id:
|
||||
@ -321,7 +322,7 @@ def docs_cron(request):
|
||||
@require_POST
|
||||
@login_required
|
||||
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:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
@ -337,7 +338,10 @@ def add_check(request, code):
|
||||
@require_POST
|
||||
@login_required
|
||||
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)
|
||||
if form.is_valid():
|
||||
check.name = form.cleaned_data["name"]
|
||||
@ -354,7 +358,7 @@ def update_name(request, code):
|
||||
@require_POST
|
||||
@login_required
|
||||
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)
|
||||
if form.is_valid():
|
||||
check.subject = form.cleaned_data["subject"]
|
||||
@ -369,7 +373,9 @@ def filtering_rules(request, code):
|
||||
@require_POST
|
||||
@login_required
|
||||
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")
|
||||
if kind == "simple":
|
||||
@ -436,7 +442,7 @@ def cron_preview(request):
|
||||
|
||||
@login_required
|
||||
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)
|
||||
if n:
|
||||
q = q.filter(n=n)
|
||||
@ -454,7 +460,7 @@ def ping_details(request, code, n=None):
|
||||
@require_POST
|
||||
@login_required
|
||||
def pause(request, code):
|
||||
check = _get_check_for_user(request, code)
|
||||
check, rw = _get_check_for_user(request, code)
|
||||
|
||||
check.status = "paused"
|
||||
check.last_start = None
|
||||
@ -471,7 +477,7 @@ def pause(request, code):
|
||||
@require_POST
|
||||
@login_required
|
||||
def resume(request, code):
|
||||
check = _get_check_for_user(request, code)
|
||||
check, rw = _get_check_for_user(request, code)
|
||||
|
||||
check.status = "new"
|
||||
check.last_start = None
|
||||
@ -485,7 +491,7 @@ def resume(request, code):
|
||||
@require_POST
|
||||
@login_required
|
||||
def remove_check(request, code):
|
||||
check = _get_check_for_user(request, code)
|
||||
check, rw = _get_check_for_user(request, code)
|
||||
project = check.project
|
||||
check.delete()
|
||||
return redirect("hc-checks", project.code)
|
||||
@ -518,7 +524,7 @@ def _get_events(check, limit):
|
||||
|
||||
@login_required
|
||||
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
|
||||
ctx = {
|
||||
@ -535,7 +541,7 @@ def log(request, code):
|
||||
@login_required
|
||||
def details(request, code):
|
||||
_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 = list(channels.order_by("created"))
|
||||
@ -549,6 +555,7 @@ def details(request, code):
|
||||
"page": "details",
|
||||
"project": check.project,
|
||||
"check": check,
|
||||
"rw": rw,
|
||||
"channels": channels,
|
||||
"enabled_channels": list(check.channel_set.all()),
|
||||
"timezones": pytz.all_timezones,
|
||||
@ -563,10 +570,10 @@ def details(request, code):
|
||||
|
||||
@login_required
|
||||
def transfer(request, code):
|
||||
check = _get_check_for_user(request, code)
|
||||
check, rw = _get_check_for_user(request, code)
|
||||
|
||||
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:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
@ -584,7 +591,7 @@ def transfer(request, code):
|
||||
@require_POST
|
||||
@login_required
|
||||
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:
|
||||
return HttpResponseBadRequest()
|
||||
@ -609,7 +616,7 @@ def copy(request, code):
|
||||
|
||||
@login_required
|
||||
def status_single(request, code):
|
||||
check = _get_check_for_user(request, code)
|
||||
check, rw = _get_check_for_user(request, code)
|
||||
|
||||
status = check.get_status()
|
||||
events = _get_events(check, 20)
|
||||
@ -633,7 +640,7 @@ def status_single(request, code):
|
||||
|
||||
@login_required
|
||||
def badges(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
tags = set()
|
||||
for check in Check.objects.filter(project=project):
|
||||
@ -665,7 +672,7 @@ def badges(request, code):
|
||||
|
||||
@login_required
|
||||
def channels(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
code = request.POST["channel"]
|
||||
@ -830,7 +837,7 @@ def remove_channel(request, code):
|
||||
|
||||
@login_required
|
||||
def add_email(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddEmailForm(request.POST)
|
||||
@ -875,7 +882,7 @@ def add_email(request, code):
|
||||
|
||||
@login_required
|
||||
def add_webhook(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.WebhookForm(request.POST)
|
||||
@ -937,7 +944,7 @@ def edit_webhook(request, code):
|
||||
@require_setting("SHELL_ENABLED")
|
||||
@login_required
|
||||
def add_shell(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
if request.method == "POST":
|
||||
form = forms.AddShellForm(request.POST)
|
||||
if form.is_valid():
|
||||
@ -960,7 +967,7 @@ def add_shell(request, code):
|
||||
|
||||
@login_required
|
||||
def add_pd(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddPdForm(request.POST)
|
||||
@ -987,7 +994,7 @@ def pdc_help(request):
|
||||
@require_setting("PD_VENDOR_KEY")
|
||||
@login_required
|
||||
def add_pdc(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
state = token_urlsafe()
|
||||
callback = settings.SITE_ROOT + reverse(
|
||||
@ -1008,7 +1015,7 @@ def add_pdc_complete(request, code, state):
|
||||
if "pd" not in request.session:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
session_state = request.session.pop("pd")
|
||||
if session_state != state:
|
||||
@ -1033,7 +1040,7 @@ def add_pdc_complete(request, code, state):
|
||||
|
||||
@login_required
|
||||
def add_pagertree(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddUrlForm(request.POST)
|
||||
@ -1053,7 +1060,7 @@ def add_pagertree(request, code):
|
||||
|
||||
@login_required
|
||||
def add_slack(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddUrlForm(request.POST)
|
||||
@ -1084,7 +1091,7 @@ def slack_help(request):
|
||||
@require_setting("SLACK_CLIENT_ID")
|
||||
@login_required
|
||||
def add_slack_btn(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
state = token_urlsafe()
|
||||
authorize_url = "https://slack.com/oauth/v2/authorize?" + urlencode(
|
||||
@ -1112,7 +1119,7 @@ def add_slack_complete(request):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
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":
|
||||
messages.warning(request, "Slack setup was cancelled.")
|
||||
return redirect("hc-p-channels", project.code)
|
||||
@ -1145,7 +1152,7 @@ def add_slack_complete(request):
|
||||
|
||||
@login_required
|
||||
def add_mattermost(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddUrlForm(request.POST)
|
||||
@ -1166,7 +1173,7 @@ def add_mattermost(request, code):
|
||||
@require_setting("PUSHBULLET_CLIENT_ID")
|
||||
@login_required
|
||||
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")
|
||||
|
||||
state = token_urlsafe()
|
||||
@ -1196,7 +1203,7 @@ def add_pushbullet_complete(request):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
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":
|
||||
messages.warning(request, "Pushbullet setup was cancelled.")
|
||||
@ -1231,7 +1238,7 @@ def add_pushbullet_complete(request):
|
||||
@require_setting("DISCORD_CLIENT_ID")
|
||||
@login_required
|
||||
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")
|
||||
state = token_urlsafe()
|
||||
auth_url = "https://discordapp.com/api/oauth2/authorize?" + urlencode(
|
||||
@ -1257,7 +1264,7 @@ def add_discord_complete(request):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
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":
|
||||
messages.warning(request, "Discord setup was cancelled.")
|
||||
@ -1300,7 +1307,7 @@ def pushover_help(request):
|
||||
@require_setting("PUSHOVER_API_TOKEN")
|
||||
@login_required
|
||||
def add_pushover(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
state = token_urlsafe()
|
||||
@ -1365,7 +1372,7 @@ def add_pushover(request, code):
|
||||
|
||||
@login_required
|
||||
def add_opsgenie(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddOpsGenieForm(request.POST)
|
||||
@ -1386,7 +1393,7 @@ def add_opsgenie(request, code):
|
||||
|
||||
@login_required
|
||||
def add_victorops(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddUrlForm(request.POST)
|
||||
@ -1406,7 +1413,7 @@ def add_victorops(request, code):
|
||||
|
||||
@login_required
|
||||
def add_zulip(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddZulipForm(request.POST)
|
||||
@ -1474,7 +1481,7 @@ def add_telegram(request):
|
||||
return render(request, "bad_link.html")
|
||||
|
||||
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.value = json.dumps(
|
||||
{"id": chat_id, "type": chat_type, "name": chat_name}
|
||||
@ -1500,7 +1507,7 @@ def add_telegram(request):
|
||||
@require_setting("TWILIO_AUTH")
|
||||
@login_required
|
||||
def add_sms(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
if request.method == "POST":
|
||||
form = forms.AddSmsForm(request.POST)
|
||||
if form.is_valid():
|
||||
@ -1526,7 +1533,7 @@ def add_sms(request, code):
|
||||
@require_setting("TWILIO_AUTH")
|
||||
@login_required
|
||||
def add_call(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
if request.method == "POST":
|
||||
form = forms.AddSmsForm(request.POST)
|
||||
if form.is_valid():
|
||||
@ -1552,7 +1559,7 @@ def add_call(request, code):
|
||||
@require_setting("TWILIO_USE_WHATSAPP")
|
||||
@login_required
|
||||
def add_whatsapp(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
if request.method == "POST":
|
||||
form = forms.AddSmsForm(request.POST)
|
||||
if form.is_valid():
|
||||
@ -1584,7 +1591,7 @@ def add_whatsapp(request, code):
|
||||
@require_setting("TRELLO_APP_KEY")
|
||||
@login_required
|
||||
def add_trello(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
if request.method == "POST":
|
||||
channel = Channel(project=project, kind="trello")
|
||||
channel.value = request.POST["settings"]
|
||||
@ -1617,7 +1624,7 @@ def add_trello(request, code):
|
||||
@require_setting("MATRIX_ACCESS_TOKEN")
|
||||
@login_required
|
||||
def add_matrix(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
if request.method == "POST":
|
||||
form = forms.AddMatrixForm(request.POST)
|
||||
if form.is_valid():
|
||||
@ -1649,7 +1656,7 @@ def add_matrix(request, code):
|
||||
@require_setting("APPRISE_ENABLED")
|
||||
@login_required
|
||||
def add_apprise(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
if request.method == "POST":
|
||||
form = forms.AddAppriseForm(request.POST)
|
||||
if form.is_valid():
|
||||
@ -1690,7 +1697,7 @@ def trello_settings(request):
|
||||
|
||||
@login_required
|
||||
def add_msteams(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddUrlForm(request.POST)
|
||||
@ -1710,7 +1717,7 @@ def add_msteams(request, code):
|
||||
|
||||
@login_required
|
||||
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}
|
||||
return render(request, "integrations/add_prometheus.html", ctx)
|
||||
|
||||
@ -1763,7 +1770,7 @@ def metrics(request, code, key):
|
||||
|
||||
@login_required
|
||||
def add_spike(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddUrlForm(request.POST)
|
||||
@ -1783,7 +1790,7 @@ def add_spike(request, code):
|
||||
|
||||
@login_required
|
||||
def add_linenotify(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
|
||||
if request.method == "POST":
|
||||
form = forms.AddLineNotifyForm(request.POST)
|
||||
|
@ -20,7 +20,7 @@ def pricing(request, code=None):
|
||||
if not request.user.is_authenticated:
|
||||
raise Http404()
|
||||
|
||||
project = _get_project_for_user(request, code)
|
||||
project, rw = _get_project_for_user(request, code)
|
||||
if project.owner != request.user:
|
||||
ctx = {"page": "pricing", "project": project}
|
||||
return render(request, "payments/pricing_not_owner.html", ctx)
|
||||
|
@ -40,9 +40,9 @@
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#checks-table tr:hover .my-checks-name,
|
||||
#checks-table tr:hover .integrations,
|
||||
#checks-table tr:hover .timeout-grace,
|
||||
#checks-table.rw tr:hover .my-checks-name,
|
||||
#checks-table.rw tr:hover .integrations,
|
||||
#checks-table.rw tr:hover .timeout-grace,
|
||||
#checks-table tr:hover .last-ping {
|
||||
border: 1px dotted #AAA;
|
||||
cursor: pointer;
|
||||
|
@ -1,7 +1,7 @@
|
||||
$(function () {
|
||||
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 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 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 lastUpdated = "";
|
||||
adaptiveSetInterval(function() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
$(function () {
|
||||
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");
|
||||
if (!code) {
|
||||
code = this.dataset.code;
|
||||
|
@ -41,7 +41,9 @@
|
||||
<div id="details-head" class="col-sm-12">
|
||||
<h1>
|
||||
{{ check.name_then_code }}
|
||||
{% if rw %}
|
||||
<small><a id="edit-name" href="#">(edit…)</a></small>
|
||||
{% endif %}
|
||||
</h1>
|
||||
{% for tag in check.tags_list %}
|
||||
<span class="label label-tag">{{ tag }}</span>
|
||||
@ -49,6 +51,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-sm-5">
|
||||
{% if rw %}
|
||||
<div class="details-block">
|
||||
<h2>Description</h2>
|
||||
{% if check.desc %}
|
||||
@ -62,6 +65,12 @@
|
||||
<small><a id="edit-desc" href="#">Add description…</a></small>
|
||||
{% endif %}
|
||||
</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">
|
||||
<h2>How To Ping</h2>
|
||||
@ -173,7 +182,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="text-right">
|
||||
{% if rw %}
|
||||
<div class="text-right rw">
|
||||
<button
|
||||
id="edit-timeout"
|
||||
class="btn btn-sm btn-default timeout-grace"
|
||||
@ -186,6 +196,7 @@
|
||||
data-tz="{{ check.tz }}">
|
||||
Change Schedule…</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="details-block">
|
||||
@ -248,7 +259,7 @@
|
||||
|
||||
</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>
|
||||
Log
|
||||
<small class="hidden-xs">Click on individual items for details</small>
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% load hc_extras static %}
|
||||
<table
|
||||
id="checks-table"
|
||||
class="table"
|
||||
class="table {% if rw %}rw{% endif%}"
|
||||
data-list-url="{% url 'hc-checks' project.code %}"
|
||||
data-status-url="{% url 'hc-status' project.code %}">
|
||||
<tr>
|
||||
|
@ -128,7 +128,7 @@
|
||||
</div>
|
||||
|
||||
<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
|
||||
</button>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user