@ -27,45 +27,6 @@ class ProfileTestCase(BaseTestCase): | |||||
expected_subject = "Set password on %s" % settings.SITE_NAME | expected_subject = "Set password on %s" % settings.SITE_NAME | ||||
self.assertEqual(mail.outbox[0].subject, expected_subject) | self.assertEqual(mail.outbox[0].subject, expected_subject) | ||||
def test_it_shows_api_keys(self): | |||||
self.project.api_key_readonly = "R" * 32 | |||||
self.project.save() | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"show_api_keys": "1"} | |||||
r = self.client.post("/accounts/profile/", form) | |||||
self.assertEqual(r.status_code, 200) | |||||
self.assertContains(r, "X" * 32) | |||||
self.assertContains(r, "R" * 32) | |||||
def test_it_creates_api_key(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"create_api_keys": "1"} | |||||
r = self.client.post("/accounts/profile/", form) | |||||
self.assertEqual(r.status_code, 200) | |||||
self.project.refresh_from_db() | |||||
api_key = self.project.api_key | |||||
self.assertTrue(len(api_key) > 10) | |||||
self.assertFalse("b'" in api_key) | |||||
def test_it_revokes_api_key(self): | |||||
self.project.api_key_readonly = "R" * 32 | |||||
self.project.save() | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"revoke_api_keys": "1"} | |||||
r = self.client.post("/accounts/profile/", form) | |||||
assert r.status_code == 200 | |||||
self.project.refresh_from_db() | |||||
self.assertEqual(self.project.api_key, "") | |||||
self.assertEqual(self.project.api_key_readonly, "") | |||||
def test_it_sends_report(self): | def test_it_sends_report(self): | ||||
check = Check(project=self.project, name="Test Check") | check = Check(project=self.project, name="Test Check") | ||||
check.last_ping = now() | check.last_ping = now() | ||||
@ -132,59 +93,6 @@ class ProfileTestCase(BaseTestCase): | |||||
self.assertEqual(len(mail.outbox), 0) | self.assertEqual(len(mail.outbox), 0) | ||||
def test_it_adds_team_member(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"invite_team_member": "1", "email": "[email protected]"} | |||||
r = self.client.post("/accounts/profile/", form) | |||||
self.assertEqual(r.status_code, 200) | |||||
members = self.project.member_set.all() | |||||
self.assertEqual(members.count(), 2) | |||||
member = Member.objects.get(project=self.project, | |||||
user__email="[email protected]") | |||||
profile = member.user.profile | |||||
self.assertEqual(profile.current_project, self.project) | |||||
# And an email should have been sent | |||||
subj = ('You have been invited to join' | |||||
' [email protected] on %s' % settings.SITE_NAME) | |||||
self.assertEqual(mail.outbox[0].subject, subj) | |||||
def test_it_checks_team_size(self): | |||||
self.profile.team_limit = 0 | |||||
self.profile.save() | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"invite_team_member": "1", "email": "[email protected]"} | |||||
r = self.client.post("/accounts/profile/", form) | |||||
self.assertEqual(r.status_code, 403) | |||||
def test_it_removes_team_member(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"remove_team_member": "1", "email": "[email protected]"} | |||||
r = self.client.post("/accounts/profile/", form) | |||||
self.assertEqual(r.status_code, 200) | |||||
self.assertEqual(Member.objects.count(), 0) | |||||
self.bobs_profile.refresh_from_db() | |||||
self.assertEqual(self.bobs_profile.current_project, None) | |||||
def test_it_sets_team_name(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"set_team_name": "1", "team_name": "Alpha Team"} | |||||
r = self.client.post("/accounts/profile/", form) | |||||
self.assertEqual(r.status_code, 200) | |||||
self.project.refresh_from_db() | |||||
self.assertEqual(self.project.name, "Alpha Team") | |||||
def test_it_switches_to_own_team(self): | def test_it_switches_to_own_team(self): | ||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
@ -0,0 +1,104 @@ | |||||
from django.core import mail | |||||
from django.conf import settings | |||||
from hc.test import BaseTestCase | |||||
from hc.accounts.models import Member | |||||
class ProfileTestCase(BaseTestCase): | |||||
def setUp(self): | |||||
super(ProfileTestCase, self).setUp() | |||||
self.url = "/projects/%s/settings/" % self.project.code | |||||
def test_it_shows_api_keys(self): | |||||
self.project.api_key_readonly = "R" * 32 | |||||
self.project.save() | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"show_api_keys": "1"} | |||||
r = self.client.post(self.url, form) | |||||
self.assertEqual(r.status_code, 200) | |||||
self.assertContains(r, "X" * 32) | |||||
self.assertContains(r, "R" * 32) | |||||
def test_it_creates_api_key(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"create_api_keys": "1"} | |||||
r = self.client.post(self.url, form) | |||||
self.assertEqual(r.status_code, 200) | |||||
self.project.refresh_from_db() | |||||
api_key = self.project.api_key | |||||
self.assertTrue(len(api_key) > 10) | |||||
self.assertFalse("b'" in api_key) | |||||
def test_it_revokes_api_key(self): | |||||
self.project.api_key_readonly = "R" * 32 | |||||
self.project.save() | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"revoke_api_keys": "1"} | |||||
r = self.client.post(self.url, form) | |||||
assert r.status_code == 200 | |||||
self.project.refresh_from_db() | |||||
self.assertEqual(self.project.api_key, "") | |||||
self.assertEqual(self.project.api_key_readonly, "") | |||||
def test_it_adds_team_member(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"invite_team_member": "1", "email": "[email protected]"} | |||||
r = self.client.post(self.url, form) | |||||
self.assertEqual(r.status_code, 200) | |||||
members = self.project.member_set.all() | |||||
self.assertEqual(members.count(), 2) | |||||
member = Member.objects.get(project=self.project, | |||||
user__email="[email protected]") | |||||
profile = member.user.profile | |||||
self.assertEqual(profile.current_project, self.project) | |||||
# And an email should have been sent | |||||
subj = ('You have been invited to join' | |||||
' [email protected] on %s' % settings.SITE_NAME) | |||||
self.assertEqual(mail.outbox[0].subject, subj) | |||||
def test_it_checks_team_size(self): | |||||
self.profile.team_limit = 0 | |||||
self.profile.save() | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"invite_team_member": "1", "email": "[email protected]"} | |||||
r = self.client.post(self.url, form) | |||||
self.assertEqual(r.status_code, 403) | |||||
def test_it_removes_team_member(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"remove_team_member": "1", "email": "[email protected]"} | |||||
r = self.client.post(self.url, form) | |||||
self.assertEqual(r.status_code, 200) | |||||
self.assertEqual(Member.objects.count(), 0) | |||||
self.bobs_profile.refresh_from_db() | |||||
self.assertEqual(self.bobs_profile.current_project, None) | |||||
def test_it_sets_project_name(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"set_project_name": "1", "name": "Alpha Team"} | |||||
r = self.client.post(self.url, form) | |||||
self.assertEqual(r.status_code, 200) | |||||
self.project.refresh_from_db() | |||||
self.assertEqual(self.project.name, "Alpha Team") |
@ -34,7 +34,7 @@ class PricingTestCase(BaseTestCase): | |||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
r = self.client.get("/pricing/") | r = self.client.get("/pricing/") | ||||
self.assertContains(r, "To manage this team") | |||||
self.assertContains(r, "To manage billing for this project") | |||||
def test_it_shows_active_plan(self): | def test_it_shows_active_plan(self): | ||||
self.sub = Subscription(user=self.alice) | self.sub = Subscription(user=self.alice) | ||||
@ -1,12 +1,13 @@ | |||||
from django.contrib import admin | from django.contrib import admin | ||||
from django.urls import include, path | from django.urls import include, path | ||||
from hc.accounts.views import login as hc_login | |||||
from hc.accounts import views as accounts_views | |||||
urlpatterns = [ | urlpatterns = [ | ||||
path('admin/login/', hc_login), | |||||
path('admin/login/', accounts_views.login), | |||||
path('admin/', admin.site.urls), | path('admin/', admin.site.urls), | ||||
path('accounts/', include('hc.accounts.urls')), | path('accounts/', include('hc.accounts.urls')), | ||||
path('projects/<uuid:code>/settings/', accounts_views.project, name="hc-project-settings"), | |||||
path('', include('hc.api.urls')), | path('', include('hc.api.urls')), | ||||
path('', include('hc.front.urls')), | path('', include('hc.front.urls')), | ||||
path('', include('hc.payments.urls')) | path('', include('hc.payments.urls')) | ||||
@ -7,7 +7,10 @@ | |||||
{% block content %} | {% block content %} | ||||
<div class="row"> | <div class="row"> | ||||
<div class="col-sm-12"> | <div class="col-sm-12"> | ||||
<h1 class="settings-title">Settings</h1> | |||||
<h1 class="settings-title"> | |||||
Settings | |||||
<small>{{ request.user.email }}</small> | |||||
</h1> | |||||
</div> | </div> | ||||
{% if messages %} | {% if messages %} | ||||
<div class="col-sm-12"> | <div class="col-sm-12"> | ||||
@ -57,141 +60,6 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="panel panel-{{ api_status }}"> | |||||
<div class="panel-body settings-block"> | |||||
<h2>API Access</h2> | |||||
{% if project.api_key %} | |||||
{% if show_api_keys %} | |||||
<p> | |||||
API key: <br /> | |||||
<code>{{ project.api_key }}</code> | |||||
</p> | |||||
{% if project.api_key_readonly %} | |||||
<p> | |||||
API key (read-only): <br /> | |||||
<code>{{ project.api_key_readonly }}</code> | |||||
</p> | |||||
{% endif %} | |||||
<button | |||||
data-toggle="modal" | |||||
data-target="#revoke-api-key-modal" | |||||
class="btn btn-danger pull-right">Revoke</button> | |||||
{% else %} | |||||
<form method="post"> | |||||
<span class="icon-ok"></span> | |||||
API access is enabled. | |||||
{% csrf_token %} | |||||
<button | |||||
type="submit" | |||||
name="show_api_keys" | |||||
class="btn btn-default pull-right">Show API keys</button> | |||||
</form> | |||||
{% endif %} | |||||
{% else %} | |||||
<span class="icon-cancel"></span> | |||||
API access is disabled. | |||||
<form method="post"> | |||||
{% csrf_token %} | |||||
<button | |||||
type="submit" | |||||
name="create_api_keys" | |||||
class="btn btn-default pull-right">Create API keys</button> | |||||
</form> | |||||
{% endif %} | |||||
</div> | |||||
{% if api_keys_created %} | |||||
<div class="panel-footer"> | |||||
API keys created | |||||
</div> | |||||
{% endif %} | |||||
{% if api_keys_revoked %} | |||||
<div class="panel-footer"> | |||||
API keys revoked | |||||
</div> | |||||
{% endif %} | |||||
</div> | |||||
<div class="panel panel-{{ team_status }}"> | |||||
<div class="panel-body settings-block"> | |||||
<h2>Team Access</h2> | |||||
{% if profile.member_count %} | |||||
<table class="table"> | |||||
<tr> | |||||
<td>{{ profile.user.email }}</td> | |||||
<td>Owner</td> | |||||
<td></td> | |||||
</tr> | |||||
{% for member in profile.members %} | |||||
<tr> | |||||
<td>{{ member.user.email }} </td> | |||||
<td>Member</td> | |||||
<td> | |||||
<a | |||||
href="#" | |||||
data-email="{{ member.user.email }}" | |||||
class="pull-right member-remove">Remove</a> | |||||
</td> | |||||
</tr> | |||||
{% endfor %} | |||||
</table> | |||||
{% else %} | |||||
<p> | |||||
<strong>Invite team members to your account.</strong> | |||||
</p> | |||||
<p> | |||||
Share access to your checks and configured integrations | |||||
without having to share a login. | |||||
</p> | |||||
{% endif %} | |||||
<br /> | |||||
{% if not profile.can_invite %} | |||||
<div class="alert alert-info"> | |||||
<strong>Team size limit reached.</strong> | |||||
To invite more members to your team, please | |||||
<a href="{% url 'hc-pricing' %}">upgrade your account!</a> | |||||
</div> | |||||
{% endif %} | |||||
<a | |||||
href="#" | |||||
class="btn btn-default" | |||||
data-toggle="modal" | |||||
data-target="#set-team-name-modal">Set Team Name</a> | |||||
{% if profile.can_invite %} | |||||
<a | |||||
href="#" | |||||
class="btn btn-primary pull-right" | |||||
data-toggle="modal" | |||||
data-target="#invite-team-member-modal">Invite a Team Member</a> | |||||
{% endif %} | |||||
</div> | |||||
{% if team_member_invited %} | |||||
<div class="panel-footer"> | |||||
{{ team_member_invited }} invited to team | |||||
</div> | |||||
{% endif %} | |||||
{% if team_member_removed %} | |||||
<div class="panel-footer"> | |||||
{{ team_member_removed }} removed from team | |||||
</div> | |||||
{% endif %} | |||||
{% if team_name_updated %} | |||||
<div class="panel-footer"> | |||||
Team name updated | |||||
</div> | |||||
{% endif %} | |||||
</div> | |||||
<div class="panel panel-default"> | <div class="panel panel-default"> | ||||
<div class="panel-body settings-block"> | <div class="panel-body settings-block"> | ||||
{% csrf_token %} | {% csrf_token %} | ||||
@ -210,136 +78,6 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div id="revoke-api-key-modal" class="modal"> | |||||
<div class="modal-dialog"> | |||||
<form id="revoke-api-key-form" method="post"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4 class="remove-check-title">Revoke API Keys?</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<p>You are about to revoke your current API keys.</p> | |||||
<p>Afterwards, you can create new API keys, but there will | |||||
be <strong>no way of getting the current API | |||||
keys back</strong>. | |||||
</p> | |||||
<p>Are you sure?</p> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||||
<button | |||||
type="submit" | |||||
name="revoke_api_keys" | |||||
class="btn btn-danger">Revoke API Keys</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<div id="remove-team-member-modal" class="modal"> | |||||
<div class="modal-dialog"> | |||||
<form id="remove-team-member-form" method="post"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4 class="remove-check-title">Remove Team Member</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<p>You are about to remove <span id="rtm-email"></span> from the team.</p> | |||||
<p>Are you sure?</p> | |||||
<input | |||||
type="hidden" | |||||
name="email" | |||||
id="remove-team-member-email" /> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||||
<button | |||||
type="submit" | |||||
name="remove_team_member" | |||||
class="btn btn-danger">Remove Member from Team</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<div id="invite-team-member-modal" class="modal"> | |||||
<div class="modal-dialog"> | |||||
<form method="post" class="form-horizontal"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4 class="remove-check-title">Invite a Team Member</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<ul> | |||||
<li>Team Members can create and manage Checks and Integrations</li> | |||||
<li>Only the team owner (you) can view and edit billing settings</li> | |||||
</ul> | |||||
<div class="form-group"> | |||||
<label for="itm-email" class="col-sm-2 control-label">Email</label> | |||||
<div class="col-sm-9"> | |||||
<input | |||||
type="email" | |||||
class="form-control" | |||||
id="itm-email" | |||||
name="email" | |||||
placeholder="[email protected]"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||||
<button | |||||
type="submit" | |||||
name="invite_team_member" | |||||
class="btn btn-primary">Send Invite</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<div id="set-team-name-modal" class="modal"> | |||||
<div class="modal-dialog"> | |||||
<form method="post" class="form-horizontal"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4 class="remove-check-title">Set Team Name</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<div class="form-group"> | |||||
<label for="team-name" class="col-sm-4 control-label">Team Name</label> | |||||
<div class="col-sm-7"> | |||||
<input | |||||
type="text" | |||||
class="form-control" | |||||
id="team-name" | |||||
name="team_name" | |||||
value="{{ project }}"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||||
<button | |||||
type="submit" | |||||
name="set_team_name" | |||||
class="btn btn-primary">Set Team Name</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<div id="close-account-modal" class="modal"> | <div id="close-account-modal" class="modal"> | ||||
<div class="modal-dialog"> | <div class="modal-dialog"> | ||||
<form id="close-account-form" method="post" action="{% url 'hc-close' %}"> | <form id="close-account-form" method="post" action="{% url 'hc-close' %}"> | ||||
@ -367,11 +105,3 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
{% endblock %} | {% 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/profile.js' %}"></script> | |||||
{% endcompress %} | |||||
{% endblock %} |
@ -0,0 +1,292 @@ | |||||
{% extends "base.html" %} | |||||
{% load compress static hc_extras %} | |||||
{% block title %}Project Settings - {{ project }}{% endblock %} | |||||
{% block content %} | |||||
<div class="row"> | |||||
<div class="col-sm-9 col-md-6"> | |||||
<h1 class="settings-title">Project Settings</h1> | |||||
{% for message in messages %} | |||||
<p class="alert alert-{{ message.tags }}">{{ message }}</p> | |||||
{% endfor %} | |||||
<div class="panel panel-{{ project_name_status }}"> | |||||
<div class="panel-body settings-block"> | |||||
<h2>Project Name</h2> | |||||
{{ project }} | |||||
<a | |||||
href="#" | |||||
class="btn btn-default pull-right" | |||||
data-toggle="modal" | |||||
data-target="#set-project-name-modal">Change Project Name</a> | |||||
</div> | |||||
{% if project_name_updated %} | |||||
<div class="panel-footer"> | |||||
Project name updated | |||||
</div> | |||||
{% endif %} | |||||
</div> | |||||
<div class="panel panel-{{ api_status }}"> | |||||
<div class="panel-body settings-block"> | |||||
<h2>API Access</h2> | |||||
{% if project.api_key %} | |||||
{% if show_api_keys %} | |||||
<p> | |||||
API key: <br /> | |||||
<code>{{ project.api_key }}</code> | |||||
</p> | |||||
{% if project.api_key_readonly %} | |||||
<p> | |||||
API key (read-only): <br /> | |||||
<code>{{ project.api_key_readonly }}</code> | |||||
</p> | |||||
{% endif %} | |||||
<button | |||||
data-toggle="modal" | |||||
data-target="#revoke-api-key-modal" | |||||
class="btn btn-danger pull-right">Revoke</button> | |||||
{% else %} | |||||
<form method="post"> | |||||
<span class="icon-ok"></span> | |||||
API access is enabled. | |||||
{% csrf_token %} | |||||
<button | |||||
type="submit" | |||||
name="show_api_keys" | |||||
class="btn btn-default pull-right">Show API keys</button> | |||||
</form> | |||||
{% endif %} | |||||
{% else %} | |||||
<span class="icon-cancel"></span> | |||||
API access is disabled. | |||||
<form method="post"> | |||||
{% csrf_token %} | |||||
<button | |||||
type="submit" | |||||
name="create_api_keys" | |||||
class="btn btn-default pull-right">Create API keys</button> | |||||
</form> | |||||
{% endif %} | |||||
</div> | |||||
{% if api_keys_created %} | |||||
<div class="panel-footer"> | |||||
API keys created | |||||
</div> | |||||
{% endif %} | |||||
{% if api_keys_revoked %} | |||||
<div class="panel-footer"> | |||||
API keys revoked | |||||
</div> | |||||
{% endif %} | |||||
</div> | |||||
<div class="panel panel-{{ team_status }}"> | |||||
<div class="panel-body settings-block"> | |||||
<h2>Team Access</h2> | |||||
{% if num_members %} | |||||
<table class="table"> | |||||
<tr> | |||||
<td>{{ project.owner.email }}</td> | |||||
<td>Owner</td> | |||||
<td></td> | |||||
</tr> | |||||
{% for member in project.member_set.all %} | |||||
<tr> | |||||
<td>{{ member.user.email }} </td> | |||||
<td>Member</td> | |||||
<td> | |||||
<a | |||||
href="#" | |||||
data-email="{{ member.user.email }}" | |||||
class="pull-right member-remove">Remove</a> | |||||
</td> | |||||
</tr> | |||||
{% endfor %} | |||||
</table> | |||||
{% else %} | |||||
<p> | |||||
<strong>Invite team members to your project.</strong> | |||||
Share access to your checks and configured integrations | |||||
without having to share login details. | |||||
</p> | |||||
{% endif %} | |||||
<br /> | |||||
{% if project.can_invite %} | |||||
<a | |||||
href="#" | |||||
class="btn btn-primary pull-right" | |||||
data-toggle="modal" | |||||
data-target="#invite-team-member-modal">Invite a Team Member</a> | |||||
{% else %} | |||||
<div class="alert alert-info"> | |||||
<strong>Team size limit reached.</strong> | |||||
To invite more members, please | |||||
<a href="{% url 'hc-pricing' %}">upgrade your account!</a> | |||||
</div> | |||||
{% endif %} | |||||
</div> | |||||
{% if team_member_invited %} | |||||
<div class="panel-footer"> | |||||
{{ team_member_invited }} invited to team | |||||
</div> | |||||
{% endif %} | |||||
{% if team_member_removed %} | |||||
<div class="panel-footer"> | |||||
{{ team_member_removed }} removed from team | |||||
</div> | |||||
{% endif %} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div id="revoke-api-key-modal" class="modal"> | |||||
<div class="modal-dialog"> | |||||
<form id="revoke-api-key-form" method="post"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4 class="remove-check-title">Revoke API Keys?</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<p>You are about to revoke your current API keys.</p> | |||||
<p>Afterwards, you can create new API keys, but there will | |||||
be <strong>no way of getting the current API | |||||
keys back</strong>. | |||||
</p> | |||||
<p>Are you sure?</p> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||||
<button | |||||
type="submit" | |||||
name="revoke_api_keys" | |||||
class="btn btn-danger">Revoke API Keys</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<div id="remove-team-member-modal" class="modal"> | |||||
<div class="modal-dialog"> | |||||
<form id="remove-team-member-form" method="post"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4 class="remove-check-title">Remove Team Member</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<p>You are about to remove <strong id="rtm-email"></strong> from the project.</p> | |||||
<p>Are you sure?</p> | |||||
<input | |||||
type="hidden" | |||||
name="email" | |||||
id="remove-team-member-email" /> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||||
<button | |||||
type="submit" | |||||
name="remove_team_member" | |||||
class="btn btn-danger">Remove Member from Project</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<div id="invite-team-member-modal" class="modal"> | |||||
<div class="modal-dialog"> | |||||
<form method="post" class="form-horizontal"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4 class="remove-check-title">Invite a Team Member</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<ul> | |||||
<li>Team Members can create and manage Checks and Integrations</li> | |||||
<li>Only the project owner (you) can view and edit billing settings</li> | |||||
</ul> | |||||
<div class="form-group"> | |||||
<label for="itm-email" class="col-sm-2 control-label">Email</label> | |||||
<div class="col-sm-9"> | |||||
<input | |||||
type="email" | |||||
class="form-control" | |||||
id="itm-email" | |||||
name="email" | |||||
placeholder="[email protected]"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||||
<button | |||||
type="submit" | |||||
name="invite_team_member" | |||||
class="btn btn-primary">Send Invite</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<div id="set-project-name-modal" class="modal"> | |||||
<div class="modal-dialog"> | |||||
<form method="post" class="form-horizontal"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4>Change Project Name</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<div class="form-group"> | |||||
<label for="project-name" class="col-sm-4 control-label">Project Name</label> | |||||
<div class="col-sm-7"> | |||||
<input | |||||
type="text" | |||||
class="form-control" | |||||
id="project-name" | |||||
name="name" | |||||
value="{{ project }}"> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||||
<button | |||||
type="submit" | |||||
name="set_project_name" | |||||
class="btn btn-primary">Set Project Name</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</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 %} |
@ -1,6 +1,6 @@ | |||||
{% load hc_extras %} | {% load hc_extras %} | ||||
{% if inviting_profile %} | |||||
You have been invited to join {{ inviting_profile.user.email }} on {% site_name %} | |||||
{% if inviting_project %} | |||||
You have been invited to join {{ inviting_project }} on {% site_name %} | |||||
{% else %} | {% else %} | ||||
Log in to {% site_name %} | Log in to {% site_name %} | ||||
{% endif %} | {% endif %} |