@ -27,45 +27,6 @@ class ProfileTestCase(BaseTestCase): | |||
expected_subject = "Set password on %s" % settings.SITE_NAME | |||
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): | |||
check = Check(project=self.project, name="Test Check") | |||
check.last_ping = now() | |||
@ -132,59 +93,6 @@ class ProfileTestCase(BaseTestCase): | |||
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): | |||
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") | |||
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): | |||
self.sub = Subscription(user=self.alice) | |||
@ -1,12 +1,13 @@ | |||
from django.contrib import admin | |||
from django.urls import include, path | |||
from hc.accounts.views import login as hc_login | |||
from hc.accounts import views as accounts_views | |||
urlpatterns = [ | |||
path('admin/login/', hc_login), | |||
path('admin/login/', accounts_views.login), | |||
path('admin/', admin.site.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.front.urls')), | |||
path('', include('hc.payments.urls')) | |||
@ -7,7 +7,10 @@ | |||
{% block content %} | |||
<div class="row"> | |||
<div class="col-sm-12"> | |||
<h1 class="settings-title">Settings</h1> | |||
<h1 class="settings-title"> | |||
Settings | |||
<small>{{ request.user.email }}</small> | |||
</h1> | |||
</div> | |||
{% if messages %} | |||
<div class="col-sm-12"> | |||
@ -57,141 +60,6 @@ | |||
</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-body settings-block"> | |||
{% csrf_token %} | |||
@ -210,136 +78,6 @@ | |||
</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 class="modal-dialog"> | |||
<form id="close-account-form" method="post" action="{% url 'hc-close' %}"> | |||
@ -367,11 +105,3 @@ | |||
</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/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 %} | |||
{% 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 %} | |||
Log in to {% site_name %} | |||
{% endif %} |