mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-08 06:30:05 +00:00
"My Projects" page.
This commit is contained in:
parent
4e6fa38ec6
commit
6b0d566922
21 changed files with 205 additions and 153 deletions
hc
accounts
front
static/css
templates
|
@ -163,7 +163,7 @@ class ProjectAdmin(admin.ModelAdmin):
|
|||
|
||||
@mark_safe
|
||||
def switch(self, obj):
|
||||
url = reverse("hc-switch-project", args=[obj.code])
|
||||
url = reverse("hc-checks", args=[obj.code])
|
||||
return "<a href='%s'>Show Checks</a>" % url
|
||||
|
||||
|
||||
|
|
|
@ -9,13 +9,17 @@ class CheckTokenTestCase(BaseTestCase):
|
|||
self.profile.token = make_password("secret-token", "login")
|
||||
self.profile.save()
|
||||
|
||||
self.checks_url = "/projects/%s/checks/" % self.project.code
|
||||
|
||||
def test_it_shows_form(self):
|
||||
r = self.client.get("/accounts/check_token/alice/secret-token/")
|
||||
self.assertContains(r, "You are about to log in")
|
||||
|
||||
def test_it_redirects(self):
|
||||
r = self.client.post("/accounts/check_token/alice/secret-token/")
|
||||
self.assertRedirects(r, "/checks/")
|
||||
r = self.client.post("/accounts/check_token/alice/secret-token/",
|
||||
follow=True)
|
||||
|
||||
self.assertRedirects(r, self.checks_url)
|
||||
|
||||
# After login, token should be blank
|
||||
self.profile.refresh_from_db()
|
||||
|
@ -26,8 +30,10 @@ class CheckTokenTestCase(BaseTestCase):
|
|||
self.client.login(username="alice@example.org", password="password")
|
||||
|
||||
# Login again, when already authenticated
|
||||
r = self.client.post("/accounts/check_token/alice/secret-token/")
|
||||
self.assertRedirects(r, "/checks/")
|
||||
r = self.client.post("/accounts/check_token/alice/secret-token/",
|
||||
follow=True)
|
||||
|
||||
self.assertRedirects(r, self.checks_url)
|
||||
|
||||
def test_it_redirects_bad_login(self):
|
||||
# Login with a bad token
|
||||
|
@ -37,9 +43,11 @@ class CheckTokenTestCase(BaseTestCase):
|
|||
self.assertContains(r, "incorrect or expired")
|
||||
|
||||
def test_it_handles_next_parameter(self):
|
||||
r = self.client.post("/accounts/check_token/alice/secret-token/?next=/integrations/add_slack/")
|
||||
url = "/accounts/check_token/alice/secret-token/?next=/integrations/add_slack/"
|
||||
r = self.client.post(url)
|
||||
self.assertRedirects(r, "/integrations/add_slack/")
|
||||
|
||||
def test_it_ignores_bad_next_parameter(self):
|
||||
r = self.client.post("/accounts/check_token/alice/secret-token/?next=/evil/")
|
||||
self.assertRedirects(r, "/checks/")
|
||||
url = "/accounts/check_token/alice/secret-token/?next=/evil/"
|
||||
r = self.client.post(url, follow=True)
|
||||
self.assertRedirects(r, self.checks_url)
|
||||
|
|
|
@ -6,6 +6,10 @@ from hc.test import BaseTestCase
|
|||
|
||||
class LoginTestCase(BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(LoginTestCase, self).setUp()
|
||||
self.checks_url = "/projects/%s/checks/" % self.project.code
|
||||
|
||||
def test_it_sends_link(self):
|
||||
form = {"identity": "alice@example.org"}
|
||||
|
||||
|
@ -49,8 +53,8 @@ class LoginTestCase(BaseTestCase):
|
|||
"password": "password"
|
||||
}
|
||||
|
||||
r = self.client.post("/accounts/login/", form)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
r = self.client.post("/accounts/login/", form, follow=True)
|
||||
self.assertRedirects(r, self.checks_url)
|
||||
|
||||
def test_it_handles_password_login_with_redirect(self):
|
||||
check = Check.objects.create(project=self.project)
|
||||
|
@ -77,8 +81,8 @@ class LoginTestCase(BaseTestCase):
|
|||
"password": "password"
|
||||
}
|
||||
|
||||
r = self.client.post("/accounts/login/?next=/evil/", form)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
r = self.client.post("/accounts/login/?next=/evil/", form, follow=True)
|
||||
self.assertRedirects(r, self.checks_url)
|
||||
|
||||
def test_it_handles_wrong_password(self):
|
||||
form = {
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
from hc.test import BaseTestCase
|
||||
from hc.api.models import Check
|
||||
|
||||
|
||||
class SwitchTeamTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super(SwitchTeamTestCase, self).setUp()
|
||||
|
||||
self.url = "/accounts/switch_project/%s/" % self.project.code
|
||||
|
||||
def test_it_switches(self):
|
||||
self.bobs_profile.current_project = None
|
||||
self.bobs_profile.save()
|
||||
|
||||
c = Check(project=self.project, name="This belongs to Alice")
|
||||
c.save()
|
||||
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
|
||||
r = self.client.get(self.url, follow=True)
|
||||
|
||||
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")
|
||||
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 403)
|
||||
|
||||
def test_it_switches_to_own_team(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
|
||||
r = self.client.get(self.url, follow=True)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_it_handles_invalid_project_code(self):
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
|
||||
url = "/accounts/switch_project/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/"
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
def test_it_requires_login(self):
|
||||
r = self.client.get(self.url)
|
||||
|
||||
expected_url = "/accounts/login/?next=" + self.url
|
||||
self.assertRedirects(r, expected_url)
|
|
@ -31,7 +31,4 @@ urlpatterns = [
|
|||
path('change_email/<slug:token>/',
|
||||
views.change_email, name="hc-change-email"),
|
||||
|
||||
path('switch_project/<uuid:code>/',
|
||||
views.switch_project, name="hc-switch-project"),
|
||||
|
||||
]
|
||||
|
|
|
@ -16,7 +16,6 @@ from django.utils.timezone import now
|
|||
from django.urls import resolve, Resolver404
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.shortcuts import get_object_or_404
|
||||
from hc.accounts.forms import (ChangeEmailForm, EmailPasswordForm,
|
||||
InviteTeamMemberForm, RemoveTeamMemberForm,
|
||||
ReportSettingsForm, SetPasswordForm,
|
||||
|
@ -81,7 +80,7 @@ def _redirect_after_login(request):
|
|||
if _is_whitelisted(redirect_url):
|
||||
return redirect(redirect_url)
|
||||
|
||||
return redirect("hc-checks")
|
||||
return redirect("hc-index")
|
||||
|
||||
|
||||
def login(request):
|
||||
|
@ -228,7 +227,7 @@ def add_project(request):
|
|||
project.name = form.cleaned_data["name"]
|
||||
project.save()
|
||||
|
||||
return redirect("hc-switch-project", project.code)
|
||||
return redirect("hc-checks", project.code)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -453,32 +452,6 @@ def unsubscribe_reports(request, username):
|
|||
return render(request, "accounts/unsubscribed.html")
|
||||
|
||||
|
||||
@login_required
|
||||
def switch_project(request, code):
|
||||
project = get_object_or_404(Project, code=code)
|
||||
|
||||
# The rules:
|
||||
# Superuser can switch to any team.
|
||||
access_ok = request.user.is_superuser
|
||||
|
||||
# Users can switch to their own projects.
|
||||
if not access_ok and project.owner_id == request.user.id:
|
||||
access_ok = True
|
||||
|
||||
# Users can switch to projects they are members of.
|
||||
if not access_ok:
|
||||
q = project.member_set.filter(user=request.user)
|
||||
access_ok = q.exists()
|
||||
|
||||
if not access_ok:
|
||||
return HttpResponseForbidden()
|
||||
|
||||
request.profile.current_project = project
|
||||
request.profile.save()
|
||||
|
||||
return redirect("hc-checks")
|
||||
|
||||
|
||||
@require_POST
|
||||
@login_required
|
||||
def close(request):
|
||||
|
|
|
@ -3,12 +3,16 @@ from hc.test import BaseTestCase
|
|||
|
||||
|
||||
class AddCheckTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super(AddCheckTestCase, self).setUp()
|
||||
|
||||
self.url = "/projects/%s/checks/add/" % self.project.code
|
||||
self.redirect_url = "/projects/%s/checks/" % self.project.code
|
||||
|
||||
def test_it_works(self):
|
||||
url = "/checks/add/"
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(url)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
r = self.client.post(self.url)
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
check = Check.objects.get()
|
||||
self.assertEqual(check.project, self.project)
|
||||
|
||||
|
@ -16,33 +20,29 @@ class AddCheckTestCase(BaseTestCase):
|
|||
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/")
|
||||
r = self.client.post(self.url)
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
check = Check.objects.get()
|
||||
self.assertEqual(check.project, self.project)
|
||||
|
||||
def test_team_access_works(self):
|
||||
url = "/checks/add/"
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
self.client.post(url)
|
||||
self.client.post(self.url)
|
||||
|
||||
check = Check.objects.get()
|
||||
# Added by bob, but should belong to alice (bob has team access)
|
||||
self.assertEqual(check.project, self.project)
|
||||
|
||||
def test_it_rejects_get(self):
|
||||
url = "/checks/add/"
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(url)
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 405)
|
||||
|
||||
def test_it_obeys_check_limit(self):
|
||||
self.profile.check_limit = 0
|
||||
self.profile.save()
|
||||
|
||||
url = "/checks/add/"
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(url)
|
||||
r = self.client.post(self.url)
|
||||
self.assertEqual(r.status_code, 400)
|
||||
|
|
|
@ -11,19 +11,37 @@ class MyChecksTestCase(BaseTestCase):
|
|||
self.check = Check(project=self.project, name="Alice Was Here")
|
||||
self.check.save()
|
||||
|
||||
self.url = "/projects/%s/checks/" % self.project.code
|
||||
|
||||
def test_it_works(self):
|
||||
for email in ("alice@example.org", "bob@example.org"):
|
||||
self.client.login(username=email, password="password")
|
||||
r = self.client.get("/checks/")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "Alice Was Here", status_code=200)
|
||||
|
||||
def test_it_updates_current_project(self):
|
||||
self.profile.current_project = None
|
||||
self.profile.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
self.profile.refresh_from_db()
|
||||
self.assertEqual(self.profile.current_project, self.project)
|
||||
|
||||
def test_it_checks_access(self):
|
||||
self.client.login(username="charlie@example.org", password="password")
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
def test_it_shows_green_check(self):
|
||||
self.check.last_ping = timezone.now()
|
||||
self.check.status = "up"
|
||||
self.check.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/checks/")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "icon-up")
|
||||
|
||||
def test_it_shows_red_check(self):
|
||||
|
@ -32,7 +50,7 @@ class MyChecksTestCase(BaseTestCase):
|
|||
self.check.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/checks/")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "icon-down")
|
||||
|
||||
def test_it_shows_amber_check(self):
|
||||
|
@ -41,7 +59,7 @@ class MyChecksTestCase(BaseTestCase):
|
|||
self.check.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/checks/")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "icon-grace")
|
||||
|
||||
def test_it_hides_add_check_button(self):
|
||||
|
@ -49,19 +67,19 @@ class MyChecksTestCase(BaseTestCase):
|
|||
self.profile.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/checks/")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "Check limit reached", status_code=200)
|
||||
|
||||
def test_it_saves_sort_field(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
self.client.get("/checks/?sort=name")
|
||||
self.client.get(self.url + "?sort=name")
|
||||
|
||||
self.profile.refresh_from_db()
|
||||
self.assertEqual(self.profile.sort, "name")
|
||||
|
||||
def test_it_ignores_bad_sort_value(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
self.client.get("/checks/?sort=invalid")
|
||||
self.client.get(self.url + "?sort=invalid")
|
||||
|
||||
self.profile.refresh_from_db()
|
||||
self.assertEqual(self.profile.sort, "created")
|
||||
|
@ -73,7 +91,7 @@ class MyChecksTestCase(BaseTestCase):
|
|||
self.check.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/checks/")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, """<div class="btn btn-xs down ">foo</div>""")
|
||||
|
||||
def test_it_shows_grace_badge(self):
|
||||
|
@ -83,7 +101,7 @@ class MyChecksTestCase(BaseTestCase):
|
|||
self.check.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/checks/")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, """<div class="btn btn-xs grace ">foo</div>""")
|
||||
|
||||
def test_it_shows_grace_started_badge(self):
|
||||
|
@ -94,5 +112,5 @@ class MyChecksTestCase(BaseTestCase):
|
|||
self.check.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/checks/")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, """<div class="btn btn-xs grace ">foo</div>""")
|
||||
|
|
|
@ -11,11 +11,12 @@ class PauseTestCase(BaseTestCase):
|
|||
super(PauseTestCase, self).setUp()
|
||||
self.check = Check.objects.create(project=self.project, status="up")
|
||||
self.url = "/checks/%s/pause/" % self.check.code
|
||||
self.redirect_url = "/projects/%s/checks/" % self.project.code
|
||||
|
||||
def test_it_pauses(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
self.assertEqual(self.check.status, "paused")
|
||||
|
@ -31,7 +32,7 @@ class PauseTestCase(BaseTestCase):
|
|||
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
r = self.client.post(self.url)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
||||
def test_it_clears_last_start_alert_after(self):
|
||||
self.check.last_start = now()
|
||||
|
|
|
@ -8,11 +8,12 @@ class RemoveCheckTestCase(BaseTestCase):
|
|||
super(RemoveCheckTestCase, self).setUp()
|
||||
self.check = Check.objects.create(project=self.project)
|
||||
self.remove_url = "/checks/%s/remove/" % self.check.code
|
||||
self.redirect_url = "/projects/%s/checks/" % self.project.code
|
||||
|
||||
def test_it_works(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.remove_url)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
||||
self.assertEqual(Check.objects.count(), 0)
|
||||
|
||||
|
@ -53,4 +54,4 @@ class RemoveCheckTestCase(BaseTestCase):
|
|||
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
r = self.client.post(self.remove_url)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
|
|
@ -9,11 +9,12 @@ class UpdateNameTestCase(BaseTestCase):
|
|||
self.check = Check.objects.create(project=self.project)
|
||||
|
||||
self.url = "/checks/%s/name/" % self.check.code
|
||||
self.redirect_url = "/projects/%s/checks/" % self.project.code
|
||||
|
||||
def test_it_works(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url, data={"name": "Alice Was Here"})
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
self.assertEqual(self.check.name, "Alice Was Here")
|
||||
|
@ -37,7 +38,7 @@ class UpdateNameTestCase(BaseTestCase):
|
|||
# But this should still work:
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
r = self.client.post(self.url, data={"name": "Bob Was Here"})
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
||||
def test_it_checks_ownership(self):
|
||||
payload = {"name": "Charlie Sent This"}
|
||||
|
|
|
@ -14,13 +14,14 @@ class UpdateTimeoutTestCase(BaseTestCase):
|
|||
self.check.save()
|
||||
|
||||
self.url = "/checks/%s/timeout/" % self.check.code
|
||||
self.redirect_url = "/projects/%s/checks/" % self.project.code
|
||||
|
||||
def test_it_works(self):
|
||||
payload = {"kind": "simple", "timeout": 3600, "grace": 60}
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url, data=payload)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
self.assertEqual(self.check.kind, "simple")
|
||||
|
@ -55,7 +56,7 @@ class UpdateTimeoutTestCase(BaseTestCase):
|
|||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url, data=payload)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
||||
self.check.refresh_from_db()
|
||||
self.assertEqual(self.check.kind, "cron")
|
||||
|
@ -184,4 +185,4 @@ class UpdateTimeoutTestCase(BaseTestCase):
|
|||
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
r = self.client.post(self.url, data=payload)
|
||||
self.assertRedirects(r, "/checks/")
|
||||
self.assertRedirects(r, self.redirect_url)
|
||||
|
|
|
@ -48,8 +48,8 @@ channel_urls = [
|
|||
|
||||
urlpatterns = [
|
||||
path('', views.index, name="hc-index"),
|
||||
path('checks/', views.my_checks, name="hc-checks"),
|
||||
path('checks/add/', views.add_check, name="hc-add-check"),
|
||||
path('projects/<uuid:code>/checks/', views.my_checks, name="hc-checks"),
|
||||
path('projects/<uuid:code>/checks/add/', views.add_check, name="hc-add-check"),
|
||||
path('checks/cron_preview/', views.cron_preview),
|
||||
path('projects/<uuid:code>/checks/status/', views.status, name="hc-status"),
|
||||
path('checks/<uuid:code>/', include(check_urls)),
|
||||
|
|
|
@ -17,6 +17,7 @@ from django.utils import timezone
|
|||
from django.utils.crypto import get_random_string
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.decorators.http import require_POST
|
||||
from hc.accounts.models import Project
|
||||
from hc.api.models import (DEFAULT_GRACE, DEFAULT_TIMEOUT, Channel, Check,
|
||||
Ping, Notification)
|
||||
from hc.api.transports import Telegram
|
||||
|
@ -78,30 +79,41 @@ def _get_check_for_user(request, code):
|
|||
raise Http404("not found")
|
||||
|
||||
|
||||
def _has_access(request, project_code):
|
||||
def _get_project_for_user(request, project_code):
|
||||
""" Return true if current user has access to the specified account. """
|
||||
|
||||
if request.user.is_superuser:
|
||||
return True
|
||||
q = Project.objects.all
|
||||
else:
|
||||
q = request.profile.projects()
|
||||
|
||||
projects = request.profile.projects()
|
||||
return projects.filter(code=project_code).exists()
|
||||
try:
|
||||
return q.get(code=project_code)
|
||||
except Project.DoesNotExist:
|
||||
raise Http404("not found")
|
||||
|
||||
|
||||
@login_required
|
||||
def my_checks(request):
|
||||
def my_checks(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
|
||||
if request.GET.get("sort") in VALID_SORT_VALUES:
|
||||
request.profile.sort = request.GET["sort"]
|
||||
request.profile.save()
|
||||
|
||||
checks = list(Check.objects.filter(project=request.project).prefetch_related("channel_set"))
|
||||
if request.profile.current_project_id != project.id:
|
||||
request.profile.current_project = project
|
||||
request.profile.save()
|
||||
|
||||
q = Check.objects.filter(project=project)
|
||||
checks = list(q.prefetch_related("channel_set"))
|
||||
sortchecks(checks, request.profile.sort)
|
||||
|
||||
tags_statuses, num_down = _tags_statuses(checks)
|
||||
pairs = list(tags_statuses.items())
|
||||
pairs.sort(key=lambda pair: pair[0].lower())
|
||||
|
||||
channels = Channel.objects.filter(project=request.project)
|
||||
channels = Channel.objects.filter(project=project)
|
||||
channels = list(channels.order_by("created"))
|
||||
|
||||
hidden_checks = set()
|
||||
|
@ -129,7 +141,8 @@ def my_checks(request):
|
|||
"tags": pairs,
|
||||
"ping_endpoint": settings.PING_ENDPOINT,
|
||||
"timezones": pytz.all_timezones,
|
||||
"num_available": request.project.num_checks_available(),
|
||||
"project": project,
|
||||
"num_available": project.num_checks_available(),
|
||||
"sort": request.profile.sort,
|
||||
"selected_tags": selected_tags,
|
||||
"show_search": True,
|
||||
|
@ -142,8 +155,7 @@ def my_checks(request):
|
|||
|
||||
@login_required
|
||||
def status(request, code):
|
||||
if not _has_access(request, code):
|
||||
raise Http404("not found")
|
||||
_get_project_for_user(request, code)
|
||||
|
||||
checks = list(Check.objects.filter(project__code=code))
|
||||
|
||||
|
@ -183,7 +195,17 @@ def switch_channel(request, code, channel_code):
|
|||
|
||||
def index(request):
|
||||
if request.user.is_authenticated:
|
||||
return redirect("hc-checks")
|
||||
projects = list(request.profile.projects())
|
||||
|
||||
if len(projects) == 1:
|
||||
return redirect("hc-checks", projects[0].code)
|
||||
|
||||
ctx = {
|
||||
"page": "projects",
|
||||
"show_plans": settings.USE_PAYMENTS,
|
||||
"projects": projects
|
||||
}
|
||||
return render(request, "front/projects.html", ctx)
|
||||
|
||||
check = Check()
|
||||
|
||||
|
@ -242,16 +264,17 @@ def docs_resources(request):
|
|||
|
||||
@require_POST
|
||||
@login_required
|
||||
def add_check(request):
|
||||
if request.project.num_checks_available() <= 0:
|
||||
def add_check(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
if project.num_checks_available() <= 0:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
check = Check(project=request.project)
|
||||
check = Check(project=project)
|
||||
check.save()
|
||||
|
||||
check.assign_all_channels()
|
||||
|
||||
return redirect("hc-checks")
|
||||
return redirect("hc-checks", code)
|
||||
|
||||
|
||||
@require_POST
|
||||
|
@ -268,7 +291,7 @@ def update_name(request, code):
|
|||
if "/details/" in request.META.get("HTTP_REFERER", ""):
|
||||
return redirect("hc-details", code)
|
||||
|
||||
return redirect("hc-checks")
|
||||
return redirect("hc-checks", check.project.code)
|
||||
|
||||
|
||||
@require_POST
|
||||
|
@ -313,7 +336,7 @@ def update_timeout(request, code):
|
|||
if "/details/" in request.META.get("HTTP_REFERER", ""):
|
||||
return redirect("hc-details", code)
|
||||
|
||||
return redirect("hc-checks")
|
||||
return redirect("hc-checks", check.project.code)
|
||||
|
||||
|
||||
@require_POST
|
||||
|
@ -369,15 +392,16 @@ def pause(request, code):
|
|||
if "/details/" in request.META.get("HTTP_REFERER", ""):
|
||||
return redirect("hc-details", code)
|
||||
|
||||
return redirect("hc-checks")
|
||||
return redirect("hc-checks", check.project.code)
|
||||
|
||||
|
||||
@require_POST
|
||||
@login_required
|
||||
def remove_check(request, code):
|
||||
check = _get_check_for_user(request, code)
|
||||
project = check.project
|
||||
check.delete()
|
||||
return redirect("hc-checks")
|
||||
return redirect("hc-checks", project.code)
|
||||
|
||||
|
||||
def _get_events(check, limit):
|
||||
|
|
15
static/css/projects.css
Normal file
15
static/css/projects.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
#my-projects a {
|
||||
display: block;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#my-projects a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
#my-projects a:hover .panel {
|
||||
border-color: #0091EA;
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
<div class="name">{{ project }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<a class="num-checks" href="{% url 'hc-switch-project' project.code %}">
|
||||
<a class="num-checks" href="{% url 'hc-checks' project.code %}">
|
||||
{% with project.check_set.count as n %}
|
||||
{{ n }} check{{ n|pluralize }}
|
||||
{% endwith %}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<ul>
|
||||
{% for project in profile.user.project_set.all %}
|
||||
<li><a href="{% url 'hc-switch-project' project.code %}">{{ project }}</a></li>
|
||||
<li><a href="{% url 'hc-checks' project.code %}">{{ project }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
|
@ -43,6 +43,7 @@
|
|||
<link rel="stylesheet" href="{% static 'css/radio.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/billing.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/login.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/projects.css' %}" type="text/css">
|
||||
{% endcompress %}
|
||||
</head>
|
||||
<body class="page-{{ page }}">
|
||||
|
@ -87,9 +88,9 @@
|
|||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul id="nav-main-sections" class="nav navbar-nav">
|
||||
{% if request.user.is_authenticated %}
|
||||
{% if request.user.is_authenticated and request.project %}
|
||||
<li {% if page == 'checks' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-checks' %}">Checks</a>
|
||||
<a href="{% url 'hc-checks' request.project.code %}">Checks</a>
|
||||
</li>
|
||||
|
||||
<li {% if page == 'channels' %} class="active" {% endif %}>
|
||||
|
@ -125,7 +126,7 @@
|
|||
{% for project in request.profile.projects.all %}
|
||||
<li class="dropdown-header">{{ project }}</li>
|
||||
<li>
|
||||
<a href="{% url 'hc-switch-project' project.code %}">Checks</a>
|
||||
<a href="{% url 'hc-checks' project.code %}">Checks</a>
|
||||
</li>
|
||||
{% if project.owner == request.user %}
|
||||
<li>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="{% url 'hc-checks' %}">Checks</a></li>
|
||||
<li><a href="{% url 'hc-checks' check.project.code %}">Checks</a></li>
|
||||
<li>
|
||||
<a href="{% url 'hc-details' check.code %}">
|
||||
{{ check.name_then_code }}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{% if num_available > 0 %}
|
||||
<form method="post" action="{% url 'hc-add-check' %}" class="text-center">
|
||||
<form method="post" action="{% url 'hc-add-check' project.code %}" class="text-center">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="btn btn-primary btn-lg" value="Add Check">
|
||||
</form>
|
||||
|
|
58
templates/front/projects.html
Normal file
58
templates/front/projects.html
Normal file
|
@ -0,0 +1,58 @@
|
|||
{% extends "base.html" %}
|
||||
{% load compress static hc_extras %}
|
||||
|
||||
{% block title %}Project Settings - {{ project }}{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h1 class="settings-title">My Projects</h1>
|
||||
{% for message in messages %}
|
||||
<p class="alert alert-{{ message.tags }}">{{ message }}</p>
|
||||
{% endfor %}
|
||||
|
||||
<div id="my-projects" class="row">
|
||||
{% for project in projects%}
|
||||
<a href="{% url 'hc-checks' project.code %}">
|
||||
<div class="col-sm-6 col-md-4">
|
||||
<div class="panel panel-default project-panel">
|
||||
<div class="panel-body">
|
||||
<h4>{{ project }}</h4>
|
||||
<div>
|
||||
{% with project.check_set.count as n %}
|
||||
{{ n }} check{{ n|pluralize }},
|
||||
{% endwith %}
|
||||
|
||||
{% with project.channel_set.count as n %}
|
||||
{{ n }} integration{{ n|pluralize }}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% if show_plans %}
|
||||
<div class="text-muted">
|
||||
{% if project.owner.subscription %}
|
||||
Plan: {{ project.owner.subscription.plan_name }}
|
||||
{% else %}
|
||||
Plan: Hobbyist
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{% compress js %}
|
||||
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||
<script src="{% static 'js/project.js' %}"></script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
Loading…
Add table
Reference in a new issue