Browse Source

Pricing page tweaks. Limit free accounts to 20 checks per account.

pull/114/merge
Pēteris Caune 8 years ago
parent
commit
859a9ed735
15 changed files with 129 additions and 15 deletions
  1. +20
    -0
      hc/accounts/migrations/0007_profile_check_limit.py
  2. +5
    -0
      hc/accounts/models.py
  3. +21
    -0
      hc/api/migrations/0029_auto_20170507_1251.py
  4. +7
    -0
      hc/api/tests/test_create_check.py
  5. +4
    -0
      hc/api/views.py
  6. +9
    -0
      hc/front/tests/test_add_check.py
  7. +8
    -0
      hc/front/tests/test_my_checks.py
  8. +8
    -1
      hc/front/views.py
  9. +11
    -0
      hc/payments/tests/test_cancel_plan.py
  10. +3
    -1
      hc/payments/tests/test_create_plan.py
  11. +10
    -0
      hc/payments/views.py
  12. +5
    -0
      templates/front/docs_api.html
  13. +8
    -0
      templates/front/my_checks.html
  14. +2
    -2
      templates/front/snippets/crontab.txt
  15. +8
    -11
      templates/payments/pricing.html

+ 20
- 0
hc/accounts/migrations/0007_profile_check_limit.py View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-05-07 13:04
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0006_profile_current_team'),
]
operations = [
migrations.AddField(
model_name='profile',
name='check_limit',
field=models.IntegerField(default=20),
),
]

+ 5
- 0
hc/accounts/models.py View File

@ -18,6 +18,10 @@ class ProfileManager(models.Manager):
profile = self.filter(user=user).first() profile = self.filter(user=user).first()
if profile is None: if profile is None:
profile = Profile(user=user, team_access_allowed=user.is_superuser) profile = Profile(user=user, team_access_allowed=user.is_superuser)
if not settings.USE_PAYMENTS:
# If not using payments, set a high check_limit
profile.check_limit = 500
profile.save() profile.save()
return profile return profile
@ -30,6 +34,7 @@ class Profile(models.Model):
next_report_date = models.DateTimeField(null=True, blank=True) next_report_date = models.DateTimeField(null=True, blank=True)
reports_allowed = models.BooleanField(default=True) reports_allowed = models.BooleanField(default=True)
ping_log_limit = models.IntegerField(default=100) ping_log_limit = models.IntegerField(default=100)
check_limit = models.IntegerField(default=20)
token = models.CharField(max_length=128, blank=True) token = models.CharField(max_length=128, blank=True)
api_key = models.CharField(max_length=128, blank=True) api_key = models.CharField(max_length=128, blank=True)
current_team = models.ForeignKey("self", null=True) current_team = models.ForeignKey("self", null=True)


+ 21
- 0
hc/api/migrations/0029_auto_20170507_1251.py View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-05-07 12:51
from __future__ import unicode_literals
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('api', '0028_auto_20170305_1907'),
]
operations = [
migrations.AlterField(
model_name='notification',
name='code',
field=models.UUIDField(default=uuid.uuid4, editable=False, null=True),
),
]

+ 7
- 0
hc/api/tests/test_create_check.py View File

@ -179,3 +179,10 @@ class CreateCheckTestCase(BaseTestCase):
doc = r.json() doc = r.json()
self.assertEqual(doc["timeout"], 86400) self.assertEqual(doc["timeout"], 86400)
def test_it_obeys_check_limit(self):
self.profile.check_limit = 0
self.profile.save()
r = self.post({"api_key": "abc"})
self.assertEqual(r.status_code, 403)

+ 4
- 0
hc/api/views.py View File

@ -111,6 +111,10 @@ def checks(request):
created = False created = False
check = _lookup(request.user, request.json) check = _lookup(request.user, request.json)
if check is None: if check is None:
num_checks = Check.objects.filter(user=request.user).count()
if num_checks >= request.user.profile.check_limit:
return HttpResponseForbidden()
check = Check(user=request.user) check = Check(user=request.user)
created = True created = True


+ 9
- 0
hc/front/tests/test_add_check.py View File

@ -25,3 +25,12 @@ class AddCheckTestCase(BaseTestCase):
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 405) self.assertEqual(r.status_code, 405)
def test_it_obeys_check_limit(self):
self.profile.check_limit = 0
self.profile.save()
url = "/checks/add/"
self.client.login(username="[email protected]", password="password")
r = self.client.post(url)
self.assertEqual(r.status_code, 400)

+ 8
- 0
hc/front/tests/test_my_checks.py View File

@ -58,3 +58,11 @@ class MyChecksTestCase(BaseTestCase):
# Mobile # Mobile
self.assertContains(r, "label-warning") self.assertContains(r, "label-warning")
def test_it_hides_add_check_button(self):
self.profile.check_limit = 0
self.profile.save()
self.client.login(username="[email protected]", password="password")
r = self.client.get("/checks/")
self.assertContains(r, "Check limit reached", status_code=200)

+ 8
- 1
hc/front/views.py View File

@ -54,6 +54,8 @@ def my_checks(request):
elif check.in_grace_period(): elif check.in_grace_period():
grace_tags.add(tag) grace_tags.add(tag)
can_add_more = len(checks) < request.team.check_limit
ctx = { ctx = {
"page": "checks", "page": "checks",
"checks": checks, "checks": checks,
@ -62,7 +64,8 @@ def my_checks(request):
"down_tags": down_tags, "down_tags": down_tags,
"grace_tags": grace_tags, "grace_tags": grace_tags,
"ping_endpoint": settings.PING_ENDPOINT, "ping_endpoint": settings.PING_ENDPOINT,
"timezones": all_timezones
"timezones": all_timezones,
"can_add_more": can_add_more
} }
return render(request, "front/my_checks.html", ctx) return render(request, "front/my_checks.html", ctx)
@ -135,6 +138,10 @@ def about(request):
@require_POST @require_POST
@login_required @login_required
def add_check(request): def add_check(request):
num_checks = Check.objects.filter(user=request.team.user).count()
if num_checks >= request.team.check_limit:
return HttpResponseBadRequest()
check = Check(user=request.team.user) check = Check(user=request.team.user)
check.save() check.save()


+ 11
- 0
hc/payments/tests/test_cancel_plan.py View File

@ -1,5 +1,6 @@
from mock import patch from mock import patch
from hc.accounts.models import Profile
from hc.payments.models import Subscription from hc.payments.models import Subscription
from hc.test import BaseTestCase from hc.test import BaseTestCase
@ -13,6 +14,10 @@ class CancelPlanTestCase(BaseTestCase):
self.sub.plan_id = "P5" self.sub.plan_id = "P5"
self.sub.save() self.sub.save()
self.profile.ping_log_limit = 1000
self.profile.check_limit = 500
self.profile.save()
@patch("hc.payments.models.braintree") @patch("hc.payments.models.braintree")
def test_it_works(self, mock_braintree): def test_it_works(self, mock_braintree):
@ -23,3 +28,9 @@ class CancelPlanTestCase(BaseTestCase):
self.sub.refresh_from_db() self.sub.refresh_from_db()
self.assertEqual(self.sub.subscription_id, "") self.assertEqual(self.sub.subscription_id, "")
self.assertEqual(self.sub.plan_id, "") self.assertEqual(self.sub.plan_id, "")
# User's profile should have standard limits
profile = Profile.objects.get(user=self.alice)
self.assertEqual(profile.ping_log_limit, 100)
self.assertEqual(profile.check_limit, 20)
self.assertFalse(profile.team_access_allowed)

+ 3
- 1
hc/payments/tests/test_create_plan.py View File

@ -38,9 +38,11 @@ class CreatePlanTestCase(BaseTestCase):
self.assertEqual(sub.subscription_id, "t-sub-id") self.assertEqual(sub.subscription_id, "t-sub-id")
self.assertEqual(sub.plan_id, "P5") self.assertEqual(sub.plan_id, "P5")
# User's profile should have a higher ping log limit:
# User's profile should have a higher limits
profile = Profile.objects.get(user=self.alice) profile = Profile.objects.get(user=self.alice)
self.assertEqual(profile.ping_log_limit, 1000) self.assertEqual(profile.ping_log_limit, 1000)
self.assertEqual(profile.check_limit, 500)
self.assertTrue(profile.team_access_allowed)
# braintree.Subscription.cancel should have not been called # braintree.Subscription.cancel should have not been called
assert not mock.Subscription.cancel.called assert not mock.Subscription.cancel.called


+ 10
- 0
hc/payments/views.py View File

@ -108,10 +108,12 @@ def create_plan(request):
profile = request.user.profile profile = request.user.profile
if plan_id == "P5": if plan_id == "P5":
profile.ping_log_limit = 1000 profile.ping_log_limit = 1000
profile.check_limit = 500
profile.team_access_allowed = True profile.team_access_allowed = True
profile.save() profile.save()
elif plan_id == "P75": elif plan_id == "P75":
profile.ping_log_limit = 1000 profile.ping_log_limit = 1000
profile.check_limit = 500
profile.team_access_allowed = True profile.team_access_allowed = True
profile.save() profile.save()
@ -157,6 +159,14 @@ def update_payment_method(request):
def cancel_plan(request): def cancel_plan(request):
sub = Subscription.objects.get(user=request.user) sub = Subscription.objects.get(user=request.user)
sub.cancel() sub.cancel()
# Revert to default limits--
profile = request.user.profile
profile.ping_log_limit = 100
profile.check_limit = 20
profile.team_access_allowed = False
profile.save()
return redirect("hc-pricing") return redirect("hc-pricing")


+ 5
- 0
templates/front/docs_api.html View File

@ -191,6 +191,11 @@ To create a "cron" check, specify the "schedule" and "tz" parameters.
<td>Returned if the <code>unique</code> parameter was used and an <td>Returned if the <code>unique</code> parameter was used and an
existing check was matched.</td> existing check was matched.</td>
</tr> </tr>
<tr>
<th>403 Forbidden</th>
<td>Returned if the account's check limit has been reached.
For free accounts, the limit is 20 checks per account.</td>
</tr>
</table> </table>
<h3 class="api-section">Example Request</h3> <h3 class="api-section">Example Request</h3>


+ 8
- 0
templates/front/my_checks.html View File

@ -42,10 +42,18 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
{% if can_add_more %}
<form method="post" action="{% url 'hc-add-check' %}" class="text-center"> <form method="post" action="{% url 'hc-add-check' %}" class="text-center">
{% csrf_token %} {% csrf_token %}
<input type="submit" class="btn btn-primary btn-lg" value="Add Check"> <input type="submit" class="btn btn-primary btn-lg" value="Add Check">
</form> </form>
{% else %}
<div class="alert alert-info">
<strong>Check limit reached.</strong>
To add more checks, please
<a href="{% url 'hc-pricing' %}">upgrade your account!</a>
</div>
{% endif %}
</div> </div>
</div> </div>


+ 2
- 2
templates/front/snippets/crontab.txt View File

@ -1,2 +1,2 @@
# m h dom mon dow command
8 6 * * * /home/user/backup.sh && curl -fsS --retry 3 PING_URL > /dev/null
# m h dom mon dow command
8 6 * * * /home/user/backup.sh && curl -fsS --retry 3 PING_URL > /dev/null

+ 8
- 11
templates/payments/pricing.html View File

@ -67,11 +67,10 @@
<p>free</p> <p>free</p>
</div> </div>
<ul class="list-group text-center"> <ul class="list-group text-center">
<li class="list-group-item"><i class="fa fa-check"></i> Personal or Commercial use</li>
<li class="list-group-item"><i class="fa fa-check"></i> Unlimited Checks</li>
<li class="list-group-item"><i class="fa fa-check"></i> Unlimited Alerts</li>
<li class="list-group-item">Single User Access</li>
<li class="list-group-item"><i class="fa fa-check"></i> 20 Checks</li>
<li class="list-group-item">100 log entries per check</li> <li class="list-group-item">100 log entries per check</li>
<li class="list-group-item">One User</li>
<li class="list-group-item"><i class="fa fa-check"></i> Personal or Commercial use</li>
<li class="list-group-item">&nbsp;</li> <li class="list-group-item">&nbsp;</li>
</ul> </ul>
<div class="panel-footer"> <div class="panel-footer">
@ -102,11 +101,10 @@
</div> </div>
<ul class="list-group text-center"> <ul class="list-group text-center">
<li class="list-group-item">Personal or Commercial use</li>
<li class="list-group-item">Team Access</li>
<li class="list-group-item">Unlimited Checks</li> <li class="list-group-item">Unlimited Checks</li>
<li class="list-group-item">Unlimited Alerts</li>
<li class="list-group-item">1000 log entries per check</li> <li class="list-group-item">1000 log entries per check</li>
<li class="list-group-item">Team Access</li>
<li class="list-group-item">Personal or Commercial use</li>
<li class="list-group-item">Email Support</li> <li class="list-group-item">Email Support</li>
</ul> </ul>
<div class="panel-footer"> <div class="panel-footer">
@ -144,11 +142,10 @@
</div> </div>
<ul class="list-group text-center"> <ul class="list-group text-center">
<li class="list-group-item">Personal or Commercial use</li>
<li class="list-group-item">Team Access</li>
<li class="list-group-item">Unlimited Checks</li> <li class="list-group-item">Unlimited Checks</li>
<li class="list-group-item">Unlimited Alerts</li>
<li class="list-group-item">1000 log entries per check</li> <li class="list-group-item">1000 log entries per check</li>
<li class="list-group-item">Team Access</li>
<li class="list-group-item">Personal or Commercial use</li>
<li class="list-group-item">Priority Email Support</li> <li class="list-group-item">Priority Email Support</li>
</ul> </ul>
<div class="panel-footer"> <div class="panel-footer">
@ -213,7 +210,7 @@
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<h1>Premium Features</h1> <h1>Premium Features</h1>
<h2>What is the "log entries / check" number?</h2>
<h2>What is the "log entries per check" number?</h2>
<p> <p>
For each of your checks, healthchecks.io keeps a For each of your checks, healthchecks.io keeps a
historic log of the received pings. The log can be useful historic log of the received pings. The log can be useful


Loading…
Cancel
Save