forked from GithubBackups/healthchecks
Users can add passwords to their accounts. Fixes #6
This commit is contained in:
parent
b92b0db087
commit
1dacc8b797
@ -3,8 +3,17 @@ from django.contrib.auth.models import User
|
|||||||
from hc.accounts.models import Profile
|
from hc.accounts.models import Profile
|
||||||
|
|
||||||
|
|
||||||
|
class BasicBackend:
|
||||||
|
|
||||||
|
def get_user(self, user_id):
|
||||||
|
try:
|
||||||
|
return User.objects.get(pk=user_id)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# Authenticate against the token in user's profile.
|
# Authenticate against the token in user's profile.
|
||||||
class ProfileBackend(object):
|
class ProfileBackend(BasicBackend):
|
||||||
|
|
||||||
def authenticate(self, username=None, token=None):
|
def authenticate(self, username=None, token=None):
|
||||||
try:
|
try:
|
||||||
@ -22,3 +31,15 @@ class ProfileBackend(object):
|
|||||||
return User.objects.get(pk=user_id)
|
return User.objects.get(pk=user_id)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class EmailBackend(BasicBackend):
|
||||||
|
|
||||||
|
def authenticate(self, username=None, password=None):
|
||||||
|
try:
|
||||||
|
user = User.objects.get(email=username)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if user.check_password(password):
|
||||||
|
return user
|
||||||
|
@ -8,9 +8,14 @@ class LowercaseEmailField(forms.EmailField):
|
|||||||
return value.lower()
|
return value.lower()
|
||||||
|
|
||||||
|
|
||||||
class EmailForm(forms.Form):
|
class EmailPasswordForm(forms.Form):
|
||||||
email = LowercaseEmailField()
|
email = LowercaseEmailField()
|
||||||
|
password = forms.CharField(required=False)
|
||||||
|
|
||||||
|
|
||||||
class ReportSettingsForm(forms.Form):
|
class ReportSettingsForm(forms.Form):
|
||||||
reports_allowed = forms.BooleanField(required=False)
|
reports_allowed = forms.BooleanField(required=False)
|
||||||
|
|
||||||
|
|
||||||
|
class SetPasswordForm(forms.Form):
|
||||||
|
password = forms.CharField()
|
||||||
|
@ -40,6 +40,15 @@ class Profile(models.Model):
|
|||||||
ctx = {"login_link": settings.SITE_ROOT + path}
|
ctx = {"login_link": settings.SITE_ROOT + path}
|
||||||
emails.login(self.user.email, ctx)
|
emails.login(self.user.email, ctx)
|
||||||
|
|
||||||
|
def send_set_password_link(self):
|
||||||
|
token = str(uuid.uuid4())
|
||||||
|
self.token = make_password(token)
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
path = reverse("hc-set-password", args=[token])
|
||||||
|
ctx = {"set_password_link": settings.SITE_ROOT + path}
|
||||||
|
emails.set_password(self.user.email, ctx)
|
||||||
|
|
||||||
def send_report(self):
|
def send_report(self):
|
||||||
# reset next report date first:
|
# reset next report date first:
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
|
@ -10,7 +10,8 @@ class CheckTokenTestCase(TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(CheckTokenTestCase, self).setUp()
|
super(CheckTokenTestCase, self).setUp()
|
||||||
|
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
self.profile = Profile(user=self.alice)
|
self.profile = Profile(user=self.alice)
|
||||||
@ -21,13 +22,13 @@ class CheckTokenTestCase(TestCase):
|
|||||||
r = self.client.get("/accounts/check_token/alice/secret-token/")
|
r = self.client.get("/accounts/check_token/alice/secret-token/")
|
||||||
self.assertRedirects(r, "/checks/")
|
self.assertRedirects(r, "/checks/")
|
||||||
|
|
||||||
# After login, password should be unusable
|
# After login, token should be blank
|
||||||
self.alice.refresh_from_db()
|
self.profile.refresh_from_db()
|
||||||
assert not self.alice.has_usable_password()
|
self.assertEqual(self.profile.token, "")
|
||||||
|
|
||||||
def test_it_redirects_already_logged_in(self):
|
def test_it_redirects_already_logged_in(self):
|
||||||
# Login
|
# Login
|
||||||
self.client.get("/accounts/check_token/alice/secret-token/")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
|
||||||
# Login again, when already authenticated
|
# Login again, when already authenticated
|
||||||
r = self.client.get("/accounts/check_token/alice/secret-token/")
|
r = self.client.get("/accounts/check_token/alice/secret-token/")
|
||||||
|
@ -7,6 +7,9 @@ urlpatterns = [
|
|||||||
url(r'^login_link_sent/$',
|
url(r'^login_link_sent/$',
|
||||||
views.login_link_sent, name="hc-login-link-sent"),
|
views.login_link_sent, name="hc-login-link-sent"),
|
||||||
|
|
||||||
|
url(r'^set_password_link_sent/$',
|
||||||
|
views.set_password_link_sent, name="hc-set-password-link-sent"),
|
||||||
|
|
||||||
url(r'^check_token/([\w-]+)/([\w-]+)/$',
|
url(r'^check_token/([\w-]+)/([\w-]+)/$',
|
||||||
views.check_token, name="hc-check-token"),
|
views.check_token, name="hc-check-token"),
|
||||||
|
|
||||||
@ -15,4 +18,7 @@ urlpatterns = [
|
|||||||
url(r'^unsubscribe_reports/([\w-]+)/$',
|
url(r'^unsubscribe_reports/([\w-]+)/$',
|
||||||
views.unsubscribe_reports, name="hc-unsubscribe-reports"),
|
views.unsubscribe_reports, name="hc-unsubscribe-reports"),
|
||||||
|
|
||||||
|
url(r'^set_password/([\w-]+)/$',
|
||||||
|
views.set_password, name="hc-set-password"),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
@ -5,11 +5,13 @@ from django.contrib.auth import login as auth_login
|
|||||||
from django.contrib.auth import logout as auth_logout
|
from django.contrib.auth import logout as auth_logout
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.hashers import check_password
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
from django.http import HttpResponseBadRequest
|
from django.http import HttpResponseBadRequest
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
from hc.accounts.forms import EmailForm, ReportSettingsForm
|
from hc.accounts.forms import (EmailPasswordForm, ReportSettingsForm,
|
||||||
|
SetPasswordForm)
|
||||||
from hc.accounts.models import Profile
|
from hc.accounts.models import Profile
|
||||||
from hc.api.models import Channel, Check
|
from hc.api.models import Channel, Check
|
||||||
|
|
||||||
@ -45,25 +47,38 @@ def _associate_demo_check(request, user):
|
|||||||
|
|
||||||
|
|
||||||
def login(request):
|
def login(request):
|
||||||
|
bad_credentials = False
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = EmailForm(request.POST)
|
form = EmailPasswordForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
email = form.cleaned_data["email"]
|
email = form.cleaned_data["email"]
|
||||||
try:
|
password = form.cleaned_data["password"]
|
||||||
user = User.objects.get(email=email)
|
if len(password):
|
||||||
except User.DoesNotExist:
|
user = authenticate(username=email, password=password)
|
||||||
user = _make_user(email)
|
if user is not None and user.is_active:
|
||||||
_associate_demo_check(request, user)
|
auth_login(request, user)
|
||||||
|
return redirect("hc-checks")
|
||||||
|
bad_credentials = True
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
user = User.objects.get(email=email)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
user = _make_user(email)
|
||||||
|
_associate_demo_check(request, user)
|
||||||
|
|
||||||
profile = Profile.objects.for_user(user)
|
profile = Profile.objects.for_user(user)
|
||||||
profile.send_instant_login_link()
|
profile.send_instant_login_link()
|
||||||
return redirect("hc-login-link-sent")
|
return redirect("hc-login-link-sent")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
form = EmailForm()
|
form = EmailPasswordForm()
|
||||||
|
|
||||||
bad_link = request.session.pop("bad_link", None)
|
bad_link = request.session.pop("bad_link", None)
|
||||||
ctx = {"form": form, "bad_link": bad_link}
|
ctx = {
|
||||||
|
"form": form,
|
||||||
|
"bad_credentials": bad_credentials,
|
||||||
|
"bad_link": bad_link
|
||||||
|
}
|
||||||
return render(request, "accounts/login.html", ctx)
|
return render(request, "accounts/login.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
@ -76,6 +91,10 @@ def login_link_sent(request):
|
|||||||
return render(request, "accounts/login_link_sent.html")
|
return render(request, "accounts/login_link_sent.html")
|
||||||
|
|
||||||
|
|
||||||
|
def set_password_link_sent(request):
|
||||||
|
return render(request, "accounts/set_password_link_sent.html")
|
||||||
|
|
||||||
|
|
||||||
def check_token(request, username, token):
|
def check_token(request, username, token):
|
||||||
if request.user.is_authenticated() and request.user.username == username:
|
if request.user.is_authenticated() and request.user.username == username:
|
||||||
# User is already logged in
|
# User is already logged in
|
||||||
@ -102,6 +121,10 @@ def profile(request):
|
|||||||
profile = Profile.objects.for_user(request.user)
|
profile = Profile.objects.for_user(request.user)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
if "set_password" in request.POST:
|
||||||
|
profile.send_set_password_link()
|
||||||
|
return redirect("hc-set-password-link-sent")
|
||||||
|
|
||||||
form = ReportSettingsForm(request.POST)
|
form = ReportSettingsForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
profile.reports_allowed = form.cleaned_data["reports_allowed"]
|
profile.reports_allowed = form.cleaned_data["reports_allowed"]
|
||||||
@ -115,6 +138,36 @@ def profile(request):
|
|||||||
return render(request, "accounts/profile.html", ctx)
|
return render(request, "accounts/profile.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def set_password(request, token):
|
||||||
|
profile = Profile.objects.for_user(request.user)
|
||||||
|
if not check_password(token, profile.token):
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
form = SetPasswordForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
password = form.cleaned_data["password"]
|
||||||
|
request.user.set_password(password)
|
||||||
|
request.user.save()
|
||||||
|
|
||||||
|
profile.token = ""
|
||||||
|
profile.save()
|
||||||
|
|
||||||
|
# Setting a password logs the user out, so here we
|
||||||
|
# log them back in.
|
||||||
|
u = authenticate(username=request.user.email, password=password)
|
||||||
|
auth_login(request, u)
|
||||||
|
|
||||||
|
messages.info(request, "Your password has been set!")
|
||||||
|
return redirect("hc-profile")
|
||||||
|
|
||||||
|
ctx = {
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "accounts/set_password.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
def unsubscribe_reports(request, username):
|
def unsubscribe_reports(request, username):
|
||||||
try:
|
try:
|
||||||
signing.Signer().unsign(request.GET.get("token"))
|
signing.Signer().unsign(request.GET.get("token"))
|
||||||
|
@ -7,7 +7,7 @@ from hc.api.models import Channel
|
|||||||
class AddChannelTestCase(TestCase):
|
class AddChannelTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class AddChannelTestCase(TestCase):
|
|||||||
url = "/integrations/add/"
|
url = "/integrations/add/"
|
||||||
form = {"kind": "email", "value": "alice@example.org"}
|
form = {"kind": "email", "value": "alice@example.org"}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url, form)
|
r = self.client.post(url, form)
|
||||||
|
|
||||||
self.assertRedirects(r, "/integrations/")
|
self.assertRedirects(r, "/integrations/")
|
||||||
@ -30,7 +30,7 @@ class AddChannelTestCase(TestCase):
|
|||||||
url = "/integrations/add/"
|
url = "/integrations/add/"
|
||||||
form = {"kind": "email", "value": " alice@example.org "}
|
form = {"kind": "email", "value": " alice@example.org "}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
self.client.post(url, form)
|
self.client.post(url, form)
|
||||||
|
|
||||||
q = Channel.objects.filter(value="alice@example.org")
|
q = Channel.objects.filter(value="alice@example.org")
|
||||||
@ -40,20 +40,20 @@ class AddChannelTestCase(TestCase):
|
|||||||
url = "/integrations/add/"
|
url = "/integrations/add/"
|
||||||
form = {"kind": "dog", "value": "Lassie"}
|
form = {"kind": "dog", "value": "Lassie"}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url, form)
|
r = self.client.post(url, form)
|
||||||
|
|
||||||
assert r.status_code == 400, r.status_code
|
assert r.status_code == 400, r.status_code
|
||||||
|
|
||||||
def test_instructions_work(self):
|
def test_instructions_work(self):
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
for frag in ("email", "webhook", "pd", "pushover", "slack", "hipchat"):
|
for frag in ("email", "webhook", "pd", "pushover", "slack", "hipchat"):
|
||||||
url = "/integrations/add_%s/" % frag
|
url = "/integrations/add_%s/" % frag
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
self.assertContains(r, "Integration Settings", status_code=200)
|
self.assertContains(r, "Integration Settings", status_code=200)
|
||||||
|
|
||||||
def test_it_adds_pushover_channel(self):
|
def test_it_adds_pushover_channel(self):
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
|
||||||
session = self.client.session
|
session = self.client.session
|
||||||
session["po_nonce"] = "n"
|
session["po_nonce"] = "n"
|
||||||
@ -68,7 +68,7 @@ class AddChannelTestCase(TestCase):
|
|||||||
assert channels[0].value == "a|0"
|
assert channels[0].value == "a|0"
|
||||||
|
|
||||||
def test_it_validates_pushover_priority(self):
|
def test_it_validates_pushover_priority(self):
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
|
||||||
session = self.client.session
|
session = self.client.session
|
||||||
session["po_nonce"] = "n"
|
session["po_nonce"] = "n"
|
||||||
@ -79,7 +79,7 @@ class AddChannelTestCase(TestCase):
|
|||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
|
|
||||||
def test_it_validates_pushover_nonce(self):
|
def test_it_validates_pushover_nonce(self):
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
|
||||||
session = self.client.session
|
session = self.client.session
|
||||||
session["po_nonce"] = "n"
|
session["po_nonce"] = "n"
|
||||||
|
@ -6,13 +6,13 @@ from hc.api.models import Check
|
|||||||
class AddCheckTestCase(TestCase):
|
class AddCheckTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
def test_it_works(self):
|
def test_it_works(self):
|
||||||
url = "/checks/add/"
|
url = "/checks/add/"
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
self.assertRedirects(r, "/checks/")
|
self.assertRedirects(r, "/checks/")
|
||||||
assert Check.objects.count() == 1
|
assert Check.objects.count() == 1
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Channel
|
|||||||
class ChannelChecksTestCase(TestCase):
|
class ChannelChecksTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -17,19 +17,19 @@ class ChannelChecksTestCase(TestCase):
|
|||||||
def test_it_works(self):
|
def test_it_works(self):
|
||||||
url = "/integrations/%s/checks/" % self.channel.code
|
url = "/integrations/%s/checks/" % self.channel.code
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
self.assertContains(r, "alice@example.org", status_code=200)
|
self.assertContains(r, "alice@example.org", status_code=200)
|
||||||
|
|
||||||
def test_it_checks_owner(self):
|
def test_it_checks_owner(self):
|
||||||
mallory = User(username="mallory")
|
mallory = User(username="mallory", email="mallory@example.org")
|
||||||
mallory.set_password("password")
|
mallory.set_password("password")
|
||||||
mallory.save()
|
mallory.save()
|
||||||
|
|
||||||
# channel does not belong to mallory so this should come back
|
# channel does not belong to mallory so this should come back
|
||||||
# with 403 Forbidden:
|
# with 403 Forbidden:
|
||||||
url = "/integrations/%s/checks/" % self.channel.code
|
url = "/integrations/%s/checks/" % self.channel.code
|
||||||
self.client.login(username="mallory", password="password")
|
self.client.login(username="mallory@example.org", password="password")
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
|
||||||
@ -37,6 +37,6 @@ class ChannelChecksTestCase(TestCase):
|
|||||||
# Valid UUID but there is no channel for it:
|
# Valid UUID but there is no channel for it:
|
||||||
url = "/integrations/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/checks/"
|
url = "/integrations/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/checks/"
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Check, Ping
|
|||||||
class LogTestCase(TestCase):
|
class LogTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -19,14 +19,14 @@ class LogTestCase(TestCase):
|
|||||||
def test_it_works(self):
|
def test_it_works(self):
|
||||||
url = "/checks/%s/log/" % self.check.code
|
url = "/checks/%s/log/" % self.check.code
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
self.assertContains(r, "Dates and times are", status_code=200)
|
self.assertContains(r, "Dates and times are", status_code=200)
|
||||||
|
|
||||||
def test_it_handles_bad_uuid(self):
|
def test_it_handles_bad_uuid(self):
|
||||||
url = "/checks/not-uuid/log/"
|
url = "/checks/not-uuid/log/"
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
|
|
||||||
@ -34,16 +34,16 @@ class LogTestCase(TestCase):
|
|||||||
# Valid UUID but there is no check for it:
|
# Valid UUID but there is no check for it:
|
||||||
url = "/checks/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/log/"
|
url = "/checks/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/log/"
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
|
||||||
def test_it_checks_ownership(self):
|
def test_it_checks_ownership(self):
|
||||||
charlie = User(username="charlie")
|
charlie = User(username="charlie", email="charlie@example.org")
|
||||||
charlie.set_password("password")
|
charlie.set_password("password")
|
||||||
charlie.save()
|
charlie.save()
|
||||||
|
|
||||||
url = "/checks/%s/log/" % self.check.code
|
url = "/checks/%s/log/" % self.check.code
|
||||||
self.client.login(username="charlie", password="password")
|
self.client.login(username="charlie@example.org", password="password")
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Check
|
|||||||
class MyChecksTestCase(TestCase):
|
class MyChecksTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -14,6 +14,6 @@ class MyChecksTestCase(TestCase):
|
|||||||
self.check.save()
|
self.check.save()
|
||||||
|
|
||||||
def test_it_works(self):
|
def test_it_works(self):
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get("/checks/")
|
r = self.client.get("/checks/")
|
||||||
self.assertContains(r, "Alice Was Here", status_code=200)
|
self.assertContains(r, "Alice Was Here", status_code=200)
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Channel
|
|||||||
class RemoveChannelTestCase(TestCase):
|
class RemoveChannelTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ class RemoveChannelTestCase(TestCase):
|
|||||||
def test_it_works(self):
|
def test_it_works(self):
|
||||||
url = "/integrations/%s/remove/" % self.channel.code
|
url = "/integrations/%s/remove/" % self.channel.code
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
self.assertRedirects(r, "/integrations/")
|
self.assertRedirects(r, "/integrations/")
|
||||||
|
|
||||||
@ -26,18 +26,18 @@ class RemoveChannelTestCase(TestCase):
|
|||||||
def test_it_handles_bad_uuid(self):
|
def test_it_handles_bad_uuid(self):
|
||||||
url = "/integrations/not-uuid/remove/"
|
url = "/integrations/not-uuid/remove/"
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
|
|
||||||
def test_it_checks_owner(self):
|
def test_it_checks_owner(self):
|
||||||
url = "/integrations/%s/remove/" % self.channel.code
|
url = "/integrations/%s/remove/" % self.channel.code
|
||||||
|
|
||||||
mallory = User(username="mallory")
|
mallory = User(username="mallory", email="mallory@example.org")
|
||||||
mallory.set_password("password")
|
mallory.set_password("password")
|
||||||
mallory.save()
|
mallory.save()
|
||||||
|
|
||||||
self.client.login(username="mallory", password="password")
|
self.client.login(username="mallory@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
|
||||||
@ -45,6 +45,6 @@ class RemoveChannelTestCase(TestCase):
|
|||||||
# Valid UUID but there is no channel for it:
|
# Valid UUID but there is no channel for it:
|
||||||
url = "/integrations/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/remove/"
|
url = "/integrations/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/remove/"
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Check
|
|||||||
class RemoveCheckTestCase(TestCase):
|
class RemoveCheckTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ class RemoveCheckTestCase(TestCase):
|
|||||||
def test_it_works(self):
|
def test_it_works(self):
|
||||||
url = "/checks/%s/remove/" % self.check.code
|
url = "/checks/%s/remove/" % self.check.code
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
self.assertRedirects(r, "/checks/")
|
self.assertRedirects(r, "/checks/")
|
||||||
|
|
||||||
@ -25,18 +25,18 @@ class RemoveCheckTestCase(TestCase):
|
|||||||
def test_it_handles_bad_uuid(self):
|
def test_it_handles_bad_uuid(self):
|
||||||
url = "/checks/not-uuid/remove/"
|
url = "/checks/not-uuid/remove/"
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
|
|
||||||
def test_it_checks_owner(self):
|
def test_it_checks_owner(self):
|
||||||
url = "/checks/%s/remove/" % self.check.code
|
url = "/checks/%s/remove/" % self.check.code
|
||||||
|
|
||||||
mallory = User(username="mallory")
|
mallory = User(username="mallory", email="mallory@example.org")
|
||||||
mallory.set_password("password")
|
mallory.set_password("password")
|
||||||
mallory.save()
|
mallory.save()
|
||||||
|
|
||||||
self.client.login(username="mallory", password="password")
|
self.client.login(username="mallory@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
|
||||||
@ -44,6 +44,6 @@ class RemoveCheckTestCase(TestCase):
|
|||||||
# Valid UUID but there is no check for it:
|
# Valid UUID but there is no check for it:
|
||||||
url = "/checks/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/remove/"
|
url = "/checks/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/remove/"
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url)
|
r = self.client.post(url)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Channel, Check
|
|||||||
class UpdateChannelTestCase(TestCase):
|
class UpdateChannelTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ class UpdateChannelTestCase(TestCase):
|
|||||||
"check-%s" % self.check.code: True
|
"check-%s" % self.check.code: True
|
||||||
}
|
}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post("/integrations/", data=payload)
|
r = self.client.post("/integrations/", data=payload)
|
||||||
self.assertRedirects(r, "/integrations/")
|
self.assertRedirects(r, "/integrations/")
|
||||||
|
|
||||||
@ -33,20 +33,20 @@ class UpdateChannelTestCase(TestCase):
|
|||||||
assert checks[0].code == self.check.code
|
assert checks[0].code == self.check.code
|
||||||
|
|
||||||
def test_it_checks_channel_user(self):
|
def test_it_checks_channel_user(self):
|
||||||
mallory = User(username="mallory")
|
mallory = User(username="mallory", email="mallory@example.org")
|
||||||
mallory.set_password("password")
|
mallory.set_password("password")
|
||||||
mallory.save()
|
mallory.save()
|
||||||
|
|
||||||
payload = {"channel": self.channel.code}
|
payload = {"channel": self.channel.code}
|
||||||
|
|
||||||
self.client.login(username="mallory", password="password")
|
self.client.login(username="mallory@example.org", password="password")
|
||||||
r = self.client.post("/integrations/", data=payload)
|
r = self.client.post("/integrations/", data=payload)
|
||||||
|
|
||||||
# self.channel does not belong to mallory, this should fail--
|
# self.channel does not belong to mallory, this should fail--
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
|
||||||
def test_it_checks_check_user(self):
|
def test_it_checks_check_user(self):
|
||||||
mallory = User(username="mallory")
|
mallory = User(username="mallory", email="mallory@example.org")
|
||||||
mallory.set_password("password")
|
mallory.set_password("password")
|
||||||
mallory.save()
|
mallory.save()
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ class UpdateChannelTestCase(TestCase):
|
|||||||
"channel": mc.code,
|
"channel": mc.code,
|
||||||
"check-%s" % self.check.code: True
|
"check-%s" % self.check.code: True
|
||||||
}
|
}
|
||||||
self.client.login(username="mallory", password="password")
|
self.client.login(username="mallory@example.org", password="password")
|
||||||
r = self.client.post("/integrations/", data=payload)
|
r = self.client.post("/integrations/", data=payload)
|
||||||
|
|
||||||
# mc belongs to mallorym but self.check does not--
|
# mc belongs to mallorym but self.check does not--
|
||||||
@ -68,7 +68,7 @@ class UpdateChannelTestCase(TestCase):
|
|||||||
# Correct UUID but there is no channel for it:
|
# Correct UUID but there is no channel for it:
|
||||||
payload = {"channel": "6837d6ec-fc08-4da5-a67f-08a9ed1ccf62"}
|
payload = {"channel": "6837d6ec-fc08-4da5-a67f-08a9ed1ccf62"}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post("/integrations/", data=payload)
|
r = self.client.post("/integrations/", data=payload)
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
|
|
||||||
@ -79,6 +79,6 @@ class UpdateChannelTestCase(TestCase):
|
|||||||
"check-6837d6ec-fc08-4da5-a67f-08a9ed1ccf62": True
|
"check-6837d6ec-fc08-4da5-a67f-08a9ed1ccf62": True
|
||||||
}
|
}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post("/integrations/", data=payload)
|
r = self.client.post("/integrations/", data=payload)
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Check
|
|||||||
class UpdateNameTestCase(TestCase):
|
class UpdateNameTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ class UpdateNameTestCase(TestCase):
|
|||||||
url = "/checks/%s/name/" % self.check.code
|
url = "/checks/%s/name/" % self.check.code
|
||||||
payload = {"name": "Alice Was Here"}
|
payload = {"name": "Alice Was Here"}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url, data=payload)
|
r = self.client.post(url, data=payload)
|
||||||
self.assertRedirects(r, "/checks/")
|
self.assertRedirects(r, "/checks/")
|
||||||
|
|
||||||
@ -26,14 +26,14 @@ class UpdateNameTestCase(TestCase):
|
|||||||
|
|
||||||
def test_it_checks_ownership(self):
|
def test_it_checks_ownership(self):
|
||||||
|
|
||||||
charlie = User(username="charlie")
|
charlie = User(username="charlie", email="charlie@example.org")
|
||||||
charlie.set_password("password")
|
charlie.set_password("password")
|
||||||
charlie.save()
|
charlie.save()
|
||||||
|
|
||||||
url = "/checks/%s/name/" % self.check.code
|
url = "/checks/%s/name/" % self.check.code
|
||||||
payload = {"name": "Charlie Sent This"}
|
payload = {"name": "Charlie Sent This"}
|
||||||
|
|
||||||
self.client.login(username="charlie", password="password")
|
self.client.login(username="charlie@example.org", password="password")
|
||||||
r = self.client.post(url, data=payload)
|
r = self.client.post(url, data=payload)
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class UpdateNameTestCase(TestCase):
|
|||||||
url = "/checks/not-uuid/name/"
|
url = "/checks/not-uuid/name/"
|
||||||
payload = {"name": "Alice Was Here"}
|
payload = {"name": "Alice Was Here"}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url, data=payload)
|
r = self.client.post(url, data=payload)
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ class UpdateNameTestCase(TestCase):
|
|||||||
url = "/checks/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/name/"
|
url = "/checks/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/name/"
|
||||||
payload = {"name": "Alice Was Here"}
|
payload = {"name": "Alice Was Here"}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url, data=payload)
|
r = self.client.post(url, data=payload)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ class UpdateNameTestCase(TestCase):
|
|||||||
url = "/checks/%s/name/" % self.check.code
|
url = "/checks/%s/name/" % self.check.code
|
||||||
payload = {"tags": " foo bar\r\t \n baz \n"}
|
payload = {"tags": " foo bar\r\t \n baz \n"}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
self.client.post(url, data=payload)
|
self.client.post(url, data=payload)
|
||||||
|
|
||||||
check = Check.objects.get(id=self.check.id)
|
check = Check.objects.get(id=self.check.id)
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Check
|
|||||||
class UpdateTimeoutTestCase(TestCase):
|
class UpdateTimeoutTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ class UpdateTimeoutTestCase(TestCase):
|
|||||||
url = "/checks/%s/timeout/" % self.check.code
|
url = "/checks/%s/timeout/" % self.check.code
|
||||||
payload = {"timeout": 3600, "grace": 60}
|
payload = {"timeout": 3600, "grace": 60}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url, data=payload)
|
r = self.client.post(url, data=payload)
|
||||||
self.assertRedirects(r, "/checks/")
|
self.assertRedirects(r, "/checks/")
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ class UpdateTimeoutTestCase(TestCase):
|
|||||||
url = "/checks/not-uuid/timeout/"
|
url = "/checks/not-uuid/timeout/"
|
||||||
payload = {"timeout": 3600, "grace": 60}
|
payload = {"timeout": 3600, "grace": 60}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url, data=payload)
|
r = self.client.post(url, data=payload)
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
|
|
||||||
@ -38,18 +38,18 @@ class UpdateTimeoutTestCase(TestCase):
|
|||||||
url = "/checks/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/timeout/"
|
url = "/checks/6837d6ec-fc08-4da5-a67f-08a9ed1ccf62/timeout/"
|
||||||
payload = {"timeout": 3600, "grace": 60}
|
payload = {"timeout": 3600, "grace": 60}
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post(url, data=payload)
|
r = self.client.post(url, data=payload)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
|
||||||
def test_it_checks_ownership(self):
|
def test_it_checks_ownership(self):
|
||||||
charlie = User(username="charlie")
|
charlie = User(username="charlie", email="charlie@example.org")
|
||||||
charlie.set_password("password")
|
charlie.set_password("password")
|
||||||
charlie.save()
|
charlie.save()
|
||||||
|
|
||||||
url = "/checks/%s/timeout/" % self.check.code
|
url = "/checks/%s/timeout/" % self.check.code
|
||||||
payload = {"timeout": 3600, "grace": 60}
|
payload = {"timeout": 3600, "grace": 60}
|
||||||
|
|
||||||
self.client.login(username="charlie", password="password")
|
self.client.login(username="charlie@example.org", password="password")
|
||||||
r = self.client.post(url, data=payload)
|
r = self.client.post(url, data=payload)
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
@ -6,7 +6,7 @@ from hc.api.models import Channel
|
|||||||
class VerifyEmailTestCase(TestCase):
|
class VerifyEmailTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
|
@ -6,6 +6,11 @@ def login(to, ctx):
|
|||||||
o.send(to, ctx)
|
o.send(to, ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def set_password(to, ctx):
|
||||||
|
o = InlineCSSTemplateMail("set-password")
|
||||||
|
o.send(to, ctx)
|
||||||
|
|
||||||
|
|
||||||
def alert(to, ctx):
|
def alert(to, ctx):
|
||||||
o = InlineCSSTemplateMail("alert")
|
o = InlineCSSTemplateMail("alert")
|
||||||
o.send(to, ctx)
|
o.send(to, ctx)
|
||||||
|
@ -7,7 +7,7 @@ from mock import Mock, patch
|
|||||||
class BillingTestCase(TestCase):
|
class BillingTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ class BillingTestCase(TestCase):
|
|||||||
m2 = Mock(id="def456", amount=456)
|
m2 = Mock(id="def456", amount=456)
|
||||||
mock_braintree.Transaction.search.return_value = [m1, m2]
|
mock_braintree.Transaction.search.return_value = [m1, m2]
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get("/billing/")
|
r = self.client.get("/billing/")
|
||||||
self.assertContains(r, "123")
|
self.assertContains(r, "123")
|
||||||
self.assertContains(r, "def456")
|
self.assertContains(r, "def456")
|
||||||
|
@ -7,7 +7,7 @@ from mock import patch
|
|||||||
class CancelPlanTestCase(TestCase):
|
class CancelPlanTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ class CancelPlanTestCase(TestCase):
|
|||||||
@patch("hc.payments.views.braintree")
|
@patch("hc.payments.views.braintree")
|
||||||
def test_it_works(self, mock_braintree):
|
def test_it_works(self, mock_braintree):
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.post("/pricing/cancel_plan/")
|
r = self.client.post("/pricing/cancel_plan/")
|
||||||
self.assertRedirects(r, "/pricing/")
|
self.assertRedirects(r, "/pricing/")
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ from mock import patch
|
|||||||
class CreatePlanTestCase(TestCase):
|
class CreatePlanTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ class CreatePlanTestCase(TestCase):
|
|||||||
|
|
||||||
def run_create_plan(self, plan_id="P5"):
|
def run_create_plan(self, plan_id="P5"):
|
||||||
form = {"plan_id": plan_id, "payment_method_nonce": "test-nonce"}
|
form = {"plan_id": plan_id, "payment_method_nonce": "test-nonce"}
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
return self.client.post("/pricing/create_plan/", form, follow=True)
|
return self.client.post("/pricing/create_plan/", form, follow=True)
|
||||||
|
|
||||||
@patch("hc.payments.views.braintree")
|
@patch("hc.payments.views.braintree")
|
||||||
|
@ -7,14 +7,14 @@ from mock import patch
|
|||||||
class GetClientTokenTestCase(TestCase):
|
class GetClientTokenTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@patch("hc.payments.views.braintree")
|
@patch("hc.payments.views.braintree")
|
||||||
def test_it_works(self, mock_braintree):
|
def test_it_works(self, mock_braintree):
|
||||||
mock_braintree.ClientToken.generate.return_value = "test-token"
|
mock_braintree.ClientToken.generate.return_value = "test-token"
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
|
||||||
r = self.client.get("/pricing/get_client_token/")
|
r = self.client.get("/pricing/get_client_token/")
|
||||||
self.assertContains(r, "test-token", status_code=200)
|
self.assertContains(r, "test-token", status_code=200)
|
||||||
|
@ -7,7 +7,7 @@ from mock import Mock, patch
|
|||||||
class InvoiceTestCase(TestCase):
|
class InvoiceTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ class InvoiceTestCase(TestCase):
|
|||||||
tx.created_at = None
|
tx.created_at = None
|
||||||
mock_braintree.Transaction.find.return_value = tx
|
mock_braintree.Transaction.find.return_value = tx
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get("/invoice/abc123/")
|
r = self.client.get("/invoice/abc123/")
|
||||||
self.assertContains(r, "ABC123") # tx.id in uppercase
|
self.assertContains(r, "ABC123") # tx.id in uppercase
|
||||||
|
|
||||||
@ -38,6 +38,6 @@ class InvoiceTestCase(TestCase):
|
|||||||
tx.created_at = None
|
tx.created_at = None
|
||||||
mock_braintree.Transaction.find.return_value = tx
|
mock_braintree.Transaction.find.return_value = tx
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
r = self.client.get("/invoice/abc123/")
|
r = self.client.get("/invoice/abc123/")
|
||||||
self.assertEqual(r.status_code, 403)
|
self.assertEqual(r.status_code, 403)
|
||||||
|
@ -6,7 +6,7 @@ from hc.payments.models import Subscription
|
|||||||
class PricingTestCase(TestCase):
|
class PricingTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.alice = User(username="alice")
|
self.alice = User(username="alice", email="alice@example.org")
|
||||||
self.alice.set_password("password")
|
self.alice.set_password("password")
|
||||||
self.alice.save()
|
self.alice.save()
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class PricingTestCase(TestCase):
|
|||||||
assert Subscription.objects.count() == 0
|
assert Subscription.objects.count() == 0
|
||||||
|
|
||||||
def test_authenticated(self):
|
def test_authenticated(self):
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice@example.org", password="password")
|
||||||
|
|
||||||
r = self.client.get("/pricing/")
|
r = self.client.get("/pricing/")
|
||||||
self.assertContains(r, "Unlimited Checks", status_code=200)
|
self.assertContains(r, "Unlimited Checks", status_code=200)
|
||||||
|
@ -52,7 +52,7 @@ MIDDLEWARE_CLASSES = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = (
|
AUTHENTICATION_BACKENDS = (
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
'hc.accounts.backends.EmailBackend',
|
||||||
'hc.accounts.backends.ProfileBackend'
|
'hc.accounts.backends.ProfileBackend'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
7
static/js/login.js
Normal file
7
static/js/login.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
$(function () {
|
||||||
|
$("#password-toggle").click(function() {
|
||||||
|
$("#password-toggle").hide();
|
||||||
|
$("#password-block").removeClass("hide");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -1,4 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load compress staticfiles %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -20,22 +21,50 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if bad_credentials %}
|
||||||
|
<p class="alert alert-danger">Incorrect email or password.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group input-group-lg">
|
<div class="input-group input-group-lg">
|
||||||
<div class="input-group-addon">@</div>
|
<div class="input-group-addon">
|
||||||
|
<span class="glyphicon glyphicon-user"></span>
|
||||||
|
</div>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
id="id_email"
|
id="id_email"
|
||||||
name="email"
|
name="email"
|
||||||
|
value="{{ form.email.value|default:"" }}"
|
||||||
placeholder="Email">
|
placeholder="Email">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if not bad_credentials %}
|
||||||
|
<div class="checkbox" id="password-toggle">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox"> I want to use a password
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<div id="password-block" class="form-group {% if not bad_credentials %} hide {% endif %}">
|
||||||
|
<div class="input-group input-group-lg">
|
||||||
|
<div class="input-group-addon">
|
||||||
|
<span class="glyphicon glyphicon-lock"></span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="form-control"
|
||||||
|
name="password"
|
||||||
|
placeholder="password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
<button type="submit" class="btn btn-lg btn-primary pull-right">
|
<button type="submit" class="btn btn-lg btn-primary pull-right">
|
||||||
Log In
|
Log In
|
||||||
@ -45,4 +74,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{% compress js %}
|
||||||
|
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
|
||||||
|
<script src="{% static 'js/login.js' %}"></script>
|
||||||
|
{% endcompress %}
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -39,6 +39,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body settings-block">
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<h2>Set Password</h2>
|
||||||
|
Attach a password to your healthchecks.io account
|
||||||
|
<input type="hidden" name="set_password" value="1" />
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="btn btn-default pull-right">Set Password</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
39
templates/accounts/set_password.html
Normal file
39
templates/accounts/set_password.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6 col-sm-offset-3">
|
||||||
|
<div class="hc-dialog">
|
||||||
|
<h1>Set a Password</h1>
|
||||||
|
<div class="dialog-body">
|
||||||
|
<p>
|
||||||
|
Please pick a password for your healthchecks.io account.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group input-group-lg">
|
||||||
|
<div class="input-group-addon">
|
||||||
|
<span class="glyphicon glyphicon-user"></span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="form-control"
|
||||||
|
name="password"
|
||||||
|
placeholder="pick a password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clearfix">
|
||||||
|
<button type="submit" class="btn btn-lg btn-primary pull-right">
|
||||||
|
Set Password
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
18
templates/accounts/set_password_link_sent.html
Normal file
18
templates/accounts/set_password_link_sent.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6 col-sm-offset-3">
|
||||||
|
<div class="hc-dialog">
|
||||||
|
<h1>Email with Instructions Sent!</h1>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
We've sent you an email with instructions to set
|
||||||
|
a password for your account. Please check your inbox!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
10
templates/emails/set-password-body-html.html
Normal file
10
templates/emails/set-password-body-html.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<p>Hello,</p>
|
||||||
|
|
||||||
|
<p>Here's a link to set a password for your account on healthchecks.io:</p>
|
||||||
|
<p><a href="{{ set_password_link }}">{{ set_password_link }}</a></p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
--<br />
|
||||||
|
Regards,<br />
|
||||||
|
healthchecks.io
|
||||||
|
</p>
|
1
templates/emails/set-password-subject.html
Normal file
1
templates/emails/set-password-subject.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
Set password on healthchecks.io
|
Loading…
x
Reference in New Issue
Block a user