forked from GithubBackups/healthchecks
Use separate counters for SMS and phone calls.
This commit is contained in:
parent
77ee8452c5
commit
8c13457037
@ -62,6 +62,9 @@ class TeamFieldset(Fieldset):
|
|||||||
"sms_limit",
|
"sms_limit",
|
||||||
"sms_sent",
|
"sms_sent",
|
||||||
"last_sms_date",
|
"last_sms_date",
|
||||||
|
"call_limit",
|
||||||
|
"calls_sent",
|
||||||
|
"last_call_date",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
28
hc/accounts/migrations/0031_auto_20200803_1413.py
Normal file
28
hc/accounts/migrations/0031_auto_20200803_1413.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 3.0.8 on 2020-08-03 14:13
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0030_member_transfer_request_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='profile',
|
||||||
|
name='call_limit',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='profile',
|
||||||
|
name='calls_sent',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='profile',
|
||||||
|
name='last_call_date',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -37,6 +37,7 @@ class ProfileManager(models.Manager):
|
|||||||
# If not using payments, set high limits
|
# If not using payments, set high limits
|
||||||
profile.check_limit = 500
|
profile.check_limit = 500
|
||||||
profile.sms_limit = 500
|
profile.sms_limit = 500
|
||||||
|
profile.call_limit = 500
|
||||||
profile.team_limit = 500
|
profile.team_limit = 500
|
||||||
|
|
||||||
profile.save()
|
profile.save()
|
||||||
@ -52,9 +53,15 @@ class Profile(models.Model):
|
|||||||
ping_log_limit = models.IntegerField(default=100)
|
ping_log_limit = models.IntegerField(default=100)
|
||||||
check_limit = models.IntegerField(default=20)
|
check_limit = models.IntegerField(default=20)
|
||||||
token = models.CharField(max_length=128, blank=True)
|
token = models.CharField(max_length=128, blank=True)
|
||||||
|
|
||||||
last_sms_date = models.DateTimeField(null=True, blank=True)
|
last_sms_date = models.DateTimeField(null=True, blank=True)
|
||||||
sms_limit = models.IntegerField(default=5)
|
sms_limit = models.IntegerField(default=5)
|
||||||
sms_sent = models.IntegerField(default=0)
|
sms_sent = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
last_call_date = models.DateTimeField(null=True, blank=True)
|
||||||
|
call_limit = models.IntegerField(default=0)
|
||||||
|
calls_sent = models.IntegerField(default=0)
|
||||||
|
|
||||||
team_limit = models.IntegerField(default=2)
|
team_limit = models.IntegerField(default=2)
|
||||||
sort = models.CharField(max_length=20, default="created")
|
sort = models.CharField(max_length=20, default="created")
|
||||||
deletion_notice_date = models.DateTimeField(null=True, blank=True)
|
deletion_notice_date = models.DateTimeField(null=True, blank=True)
|
||||||
@ -229,6 +236,29 @@ class Profile(models.Model):
|
|||||||
self.save()
|
self.save()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def calls_sent_this_month(self):
|
||||||
|
# IF last_call_date was never set, we have not made any phone calls yet.
|
||||||
|
if not self.last_call_date:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# If last sent date is not from this month, we've made 0 calls this month.
|
||||||
|
if month(timezone.now()) > month(self.last_call_date):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return self.calls_sent
|
||||||
|
|
||||||
|
def authorize_call(self):
|
||||||
|
""" If monthly limit not exceeded, increase counter and return True """
|
||||||
|
|
||||||
|
sent_this_month = self.calls_sent_this_month()
|
||||||
|
if sent_this_month >= self.call_limit:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.calls_sent = sent_this_month + 1
|
||||||
|
self.last_call_date = timezone.now()
|
||||||
|
self.save()
|
||||||
|
return True
|
||||||
|
|
||||||
def num_checks_used(self):
|
def num_checks_used(self):
|
||||||
from hc.api.models import Check
|
from hc.api.models import Check
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from hc.accounts.models import Project
|
from hc.accounts.models import Profile, Project
|
||||||
from hc.api.models import Channel, Check
|
from hc.api.models import Channel, Check
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
@ -18,6 +18,11 @@ class SignupTestCase(TestCase):
|
|||||||
# An user should have been created
|
# An user should have been created
|
||||||
user = User.objects.get()
|
user = User.objects.get()
|
||||||
|
|
||||||
|
# A profile should have been created
|
||||||
|
profile = Profile.objects.get()
|
||||||
|
self.assertEqual(profile.sms_limit, 5)
|
||||||
|
self.assertEqual(profile.call_limit, 0)
|
||||||
|
|
||||||
# And email sent
|
# And email sent
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
subject = "Log in to %s" % settings.SITE_NAME
|
subject = "Log in to %s" % settings.SITE_NAME
|
||||||
@ -37,6 +42,17 @@ class SignupTestCase(TestCase):
|
|||||||
channel = Channel.objects.get()
|
channel = Channel.objects.get()
|
||||||
self.assertEqual(channel.project, project)
|
self.assertEqual(channel.project, project)
|
||||||
|
|
||||||
|
@override_settings(USE_PAYMENTS=False)
|
||||||
|
def test_it_sets_high_limits(self):
|
||||||
|
form = {"identity": "alice@example.org"}
|
||||||
|
|
||||||
|
self.client.post("/accounts/signup/", form)
|
||||||
|
|
||||||
|
# A profile should have been created
|
||||||
|
profile = Profile.objects.get()
|
||||||
|
self.assertEqual(profile.sms_limit, 500)
|
||||||
|
self.assertEqual(profile.call_limit, 500)
|
||||||
|
|
||||||
@override_settings(REGISTRATION_OPEN=False)
|
@override_settings(REGISTRATION_OPEN=False)
|
||||||
def test_it_obeys_registration_open(self):
|
def test_it_obeys_registration_open(self):
|
||||||
form = {"identity": "dan@example.org"}
|
form = {"identity": "dan@example.org"}
|
||||||
|
18
hc/api/migrations/0074_auto_20200803_1411.py
Normal file
18
hc/api/migrations/0074_auto_20200803_1411.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.0.8 on 2020-08-03 14:11
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0073_auto_20200721_1000'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='channel',
|
||||||
|
name='kind',
|
||||||
|
field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('pagertree', 'PagerTree'), ('pagerteam', 'Pager Team'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS'), ('zendesk', 'Zendesk'), ('trello', 'Trello'), ('matrix', 'Matrix'), ('whatsapp', 'WhatsApp'), ('apprise', 'Apprise'), ('mattermost', 'Mattermost'), ('msteams', 'Microsoft Teams'), ('shell', 'Shell Command'), ('zulip', 'Zulip'), ('spike', 'Spike'), ('call', 'Phone Call')], max_length=20),
|
||||||
|
),
|
||||||
|
]
|
@ -756,6 +756,9 @@ class NotifyTestCase(BaseTestCase):
|
|||||||
|
|
||||||
@patch("hc.api.transports.requests.request")
|
@patch("hc.api.transports.requests.request")
|
||||||
def test_call(self, mock_post):
|
def test_call(self, mock_post):
|
||||||
|
self.profile.call_limit = 1
|
||||||
|
self.profile.save()
|
||||||
|
|
||||||
value = {"label": "foo", "value": "+1234567890"}
|
value = {"label": "foo", "value": "+1234567890"}
|
||||||
self._setup_data("call", json.dumps(value))
|
self._setup_data("call", json.dumps(value))
|
||||||
self.check.last_ping = now() - td(hours=2)
|
self.check.last_ping = now() - td(hours=2)
|
||||||
@ -772,8 +775,8 @@ class NotifyTestCase(BaseTestCase):
|
|||||||
@patch("hc.api.transports.requests.request")
|
@patch("hc.api.transports.requests.request")
|
||||||
def test_call_limit(self, mock_post):
|
def test_call_limit(self, mock_post):
|
||||||
# At limit already:
|
# At limit already:
|
||||||
self.profile.last_sms_date = now()
|
self.profile.last_call_date = now()
|
||||||
self.profile.sms_sent = 50
|
self.profile.calls_sent = 50
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
|
|
||||||
definition = {"value": "+1234567890"}
|
definition = {"value": "+1234567890"}
|
||||||
@ -792,6 +795,19 @@ class NotifyTestCase(BaseTestCase):
|
|||||||
self.assertEqual(email.to[0], "alice@example.org")
|
self.assertEqual(email.to[0], "alice@example.org")
|
||||||
self.assertEqual(email.subject, "Monthly Phone Call Limit Reached")
|
self.assertEqual(email.subject, "Monthly Phone Call Limit Reached")
|
||||||
|
|
||||||
|
@patch("hc.api.transports.requests.request")
|
||||||
|
def test_call_limit_reset(self, mock_post):
|
||||||
|
# At limit, but also into a new month
|
||||||
|
self.profile.calls_sent = 50
|
||||||
|
self.profile.last_call_date = now() - td(days=100)
|
||||||
|
self.profile.save()
|
||||||
|
|
||||||
|
self._setup_data("sms", "+1234567890")
|
||||||
|
mock_post.return_value.status_code = 200
|
||||||
|
|
||||||
|
self.channel.notify(self.check)
|
||||||
|
self.assertTrue(mock_post.called)
|
||||||
|
|
||||||
@patch("apprise.Apprise")
|
@patch("apprise.Apprise")
|
||||||
@override_settings(APPRISE_ENABLED=True)
|
@override_settings(APPRISE_ENABLED=True)
|
||||||
def test_apprise_enabled(self, mock_apprise):
|
def test_apprise_enabled(self, mock_apprise):
|
||||||
|
@ -486,7 +486,7 @@ class Call(HttpTransport):
|
|||||||
|
|
||||||
def notify(self, check):
|
def notify(self, check):
|
||||||
profile = Profile.objects.for_user(self.channel.project.owner)
|
profile = Profile.objects.for_user(self.channel.project.owner)
|
||||||
if not profile.authorize_sms():
|
if not profile.authorize_call():
|
||||||
profile.send_sms_limit_notice("phone call")
|
profile.send_sms_limit_notice("phone call")
|
||||||
return "Monthly phone call limit exceeded"
|
return "Monthly phone call limit exceeded"
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
|
|
||||||
self.profile.sms_limit = 0
|
self.profile.sms_limit = 0
|
||||||
self.profile.sms_sent = 1
|
self.profile.sms_sent = 1
|
||||||
|
self.profile.call_limit = 0
|
||||||
|
self.profile.calls_sent = 1
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
|
|
||||||
r = self.run_update()
|
r = self.run_update()
|
||||||
@ -41,6 +43,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
self.assertEqual(self.profile.team_limit, 9)
|
self.assertEqual(self.profile.team_limit, 9)
|
||||||
self.assertEqual(self.profile.sms_limit, 50)
|
self.assertEqual(self.profile.sms_limit, 50)
|
||||||
self.assertEqual(self.profile.sms_sent, 0)
|
self.assertEqual(self.profile.sms_sent, 0)
|
||||||
|
self.assertEqual(self.profile.call_limit, 20)
|
||||||
|
self.assertEqual(self.profile.calls_sent, 0)
|
||||||
|
|
||||||
# braintree.Subscription.cancel should have not been called
|
# braintree.Subscription.cancel should have not been called
|
||||||
# because there was no previous subscription
|
# because there was no previous subscription
|
||||||
@ -54,6 +58,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
|
|
||||||
self.profile.sms_limit = 0
|
self.profile.sms_limit = 0
|
||||||
self.profile.sms_sent = 1
|
self.profile.sms_sent = 1
|
||||||
|
self.profile.call_limit = 0
|
||||||
|
self.profile.calls_sent = 1
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
|
|
||||||
r = self.run_update("S5")
|
r = self.run_update("S5")
|
||||||
@ -72,6 +78,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
self.assertEqual(self.profile.team_limit, 2)
|
self.assertEqual(self.profile.team_limit, 2)
|
||||||
self.assertEqual(self.profile.sms_limit, 5)
|
self.assertEqual(self.profile.sms_limit, 5)
|
||||||
self.assertEqual(self.profile.sms_sent, 0)
|
self.assertEqual(self.profile.sms_sent, 0)
|
||||||
|
self.assertEqual(self.profile.call_limit, 5)
|
||||||
|
self.assertEqual(self.profile.calls_sent, 0)
|
||||||
|
|
||||||
# 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
|
||||||
@ -82,6 +90,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
|
|
||||||
self.profile.sms_limit = 0
|
self.profile.sms_limit = 0
|
||||||
self.profile.sms_sent = 1
|
self.profile.sms_sent = 1
|
||||||
|
self.profile.call_limit = 0
|
||||||
|
self.profile.calls_sent = 1
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
|
|
||||||
r = self.run_update("Y192")
|
r = self.run_update("Y192")
|
||||||
@ -100,6 +110,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
self.assertEqual(self.profile.team_limit, 9)
|
self.assertEqual(self.profile.team_limit, 9)
|
||||||
self.assertEqual(self.profile.sms_limit, 50)
|
self.assertEqual(self.profile.sms_limit, 50)
|
||||||
self.assertEqual(self.profile.sms_sent, 0)
|
self.assertEqual(self.profile.sms_sent, 0)
|
||||||
|
self.assertEqual(self.profile.call_limit, 20)
|
||||||
|
self.assertEqual(self.profile.calls_sent, 0)
|
||||||
|
|
||||||
# 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
|
||||||
@ -110,6 +122,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
|
|
||||||
self.profile.sms_limit = 0
|
self.profile.sms_limit = 0
|
||||||
self.profile.sms_sent = 1
|
self.profile.sms_sent = 1
|
||||||
|
self.profile.call_limit = 0
|
||||||
|
self.profile.calls_sent = 1
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
|
|
||||||
r = self.run_update("P80")
|
r = self.run_update("P80")
|
||||||
@ -128,6 +142,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
self.assertEqual(self.profile.team_limit, 500)
|
self.assertEqual(self.profile.team_limit, 500)
|
||||||
self.assertEqual(self.profile.sms_limit, 500)
|
self.assertEqual(self.profile.sms_limit, 500)
|
||||||
self.assertEqual(self.profile.sms_sent, 0)
|
self.assertEqual(self.profile.sms_sent, 0)
|
||||||
|
self.assertEqual(self.profile.call_limit, 100)
|
||||||
|
self.assertEqual(self.profile.calls_sent, 0)
|
||||||
|
|
||||||
# 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
|
||||||
@ -144,6 +160,8 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
|
|
||||||
self.profile.sms_limit = 1
|
self.profile.sms_limit = 1
|
||||||
self.profile.sms_sent = 1
|
self.profile.sms_sent = 1
|
||||||
|
self.profile.call_limit = 1
|
||||||
|
self.profile.calls_sent = 1
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
|
|
||||||
r = self.run_update("")
|
r = self.run_update("")
|
||||||
@ -162,6 +180,7 @@ class UpdateSubscriptionTestCase(BaseTestCase):
|
|||||||
self.assertEqual(self.profile.check_limit, 20)
|
self.assertEqual(self.profile.check_limit, 20)
|
||||||
self.assertEqual(self.profile.team_limit, 2)
|
self.assertEqual(self.profile.team_limit, 2)
|
||||||
self.assertEqual(self.profile.sms_limit, 5)
|
self.assertEqual(self.profile.sms_limit, 5)
|
||||||
|
self.assertEqual(self.profile.call_limit, 0)
|
||||||
|
|
||||||
self.assertTrue(mock.Subscription.cancel.called)
|
self.assertTrue(mock.Subscription.cancel.called)
|
||||||
|
|
||||||
|
@ -117,6 +117,7 @@ def update(request):
|
|||||||
profile.check_limit = 20
|
profile.check_limit = 20
|
||||||
profile.team_limit = 2
|
profile.team_limit = 2
|
||||||
profile.sms_limit = 5
|
profile.sms_limit = 5
|
||||||
|
profile.call_limit = 0
|
||||||
profile.save()
|
profile.save()
|
||||||
|
|
||||||
if plan_id == "":
|
if plan_id == "":
|
||||||
@ -135,6 +136,8 @@ def update(request):
|
|||||||
profile.ping_log_limit = 1000
|
profile.ping_log_limit = 1000
|
||||||
profile.sms_limit = 5
|
profile.sms_limit = 5
|
||||||
profile.sms_sent = 0
|
profile.sms_sent = 0
|
||||||
|
profile.call_limit = 5
|
||||||
|
profile.calls_sent = 0
|
||||||
profile.save()
|
profile.save()
|
||||||
elif plan_id in ("P20", "Y192"):
|
elif plan_id in ("P20", "Y192"):
|
||||||
profile.check_limit = 100
|
profile.check_limit = 100
|
||||||
@ -142,6 +145,8 @@ def update(request):
|
|||||||
profile.ping_log_limit = 1000
|
profile.ping_log_limit = 1000
|
||||||
profile.sms_limit = 50
|
profile.sms_limit = 50
|
||||||
profile.sms_sent = 0
|
profile.sms_sent = 0
|
||||||
|
profile.call_limit = 20
|
||||||
|
profile.calls_sent = 0
|
||||||
profile.save()
|
profile.save()
|
||||||
elif plan_id in ("P80", "Y768"):
|
elif plan_id in ("P80", "Y768"):
|
||||||
profile.check_limit = 1000
|
profile.check_limit = 1000
|
||||||
@ -149,6 +154,8 @@ def update(request):
|
|||||||
profile.ping_log_limit = 1000
|
profile.ping_log_limit = 1000
|
||||||
profile.sms_limit = 500
|
profile.sms_limit = 500
|
||||||
profile.sms_sent = 0
|
profile.sms_sent = 0
|
||||||
|
profile.call_limit = 100
|
||||||
|
profile.calls_sent = 0
|
||||||
profile.save()
|
profile.save()
|
||||||
|
|
||||||
request.session["set_plan_status"] = "success"
|
request.session["set_plan_status"] = "success"
|
||||||
|
@ -124,9 +124,12 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
Never
|
Never
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if ch.kind == "sms" or ch.kind == "whatsapp" or ch.kind == "call" %}
|
{% if ch.kind == "sms" or ch.kind == "whatsapp" %}
|
||||||
<p>Used {{ profile.sms_sent_this_month }} of {{ profile.sms_limit }} sends this month.</p>
|
<p>Used {{ profile.sms_sent_this_month }} of {{ profile.sms_limit }} sends this month.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if ch.kind == "call" %}
|
||||||
|
<p>Used {{ profile.calls_sent_this_month }} of {{ profile.call_limit }} phone calls this month.</p>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="actions">
|
<td class="actions">
|
||||||
{% if ch.kind == "webhook" %}
|
{% if ch.kind == "webhook" %}
|
||||||
|
@ -87,9 +87,10 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">API access</li>
|
<li class="list-group-item">API access</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span data-help="sms-help">5 SMS, WhatsApp and call credits</span>
|
<span data-help="sms-help">5 SMS & WhatsApp credits</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item"> </li>
|
<li class="list-group-item"> </li>
|
||||||
|
<li class="list-group-item"> </li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{% if not request.user.is_authenticated %}
|
{% if not request.user.is_authenticated %}
|
||||||
@ -120,7 +121,10 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">API access</li>
|
<li class="list-group-item">API access</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span data-help="sms-help">5 SMS, WhatsApp and call credits</span>
|
<span data-help="sms-help">5 SMS & WhatsApp credits</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<span data-help="phone-call-help">5 phone call credits</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">Email support</li>
|
<li class="list-group-item">Email support</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -156,7 +160,10 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">API access</li>
|
<li class="list-group-item">API access</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span data-help="sms-help">50 SMS, WhatsApp and call credits</span>
|
<span data-help="sms-help">50 SMS & WhatsApp credits</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<span data-help="phone-call-help">20 phone call credits</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">Email support</li>
|
<li class="list-group-item">Email support</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -192,7 +199,10 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">API access</li>
|
<li class="list-group-item">API access</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span data-help="sms-help">500 SMS, WhatsApp and call credits</span>
|
<span data-help="sms-help">500 SMS & WhatsApp credits</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<span data-help="phone-call-help">100 phone call credits</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">Priority email support</li>
|
<li class="list-group-item">Priority email support</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -303,10 +313,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="sms-help" class="hidden">
|
<div id="sms-help" class="hidden">
|
||||||
<p>The maximum number of SMS, WhatsApp and phone call notifications per month.</p>
|
<p>The maximum number of SMS and WhatsApp notifications per month.</p>
|
||||||
|
|
||||||
<p>The limit is applied to the combined number of sent SMS, WhatsApp and phone
|
<p>The limit is applied to the combined number of sent SMS and WhatsApp
|
||||||
call notifications. </p>
|
notifications.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="phone-call-help" class="hidden">
|
||||||
|
<p>The maximum number of phone call notifications per month.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if not request.user.is_authenticated %}
|
{% if not request.user.is_authenticated %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user