diff --git a/docs/sources/set-up/open-source/index.md b/docs/sources/set-up/open-source/index.md
index b925c7b3..734ec8fc 100644
--- a/docs/sources/set-up/open-source/index.md
+++ b/docs/sources/set-up/open-source/index.md
@@ -234,8 +234,7 @@ Zvonok.com, complete the following steps:
to the variable `ZVONOK_AUDIO_ID` (optional step).
6. To make a call with a specific voice, you can set the `ZVONOK_SPEAKER_ID`.
By default, the ID used is `Salli` (optional step).
-7. To change the voice message for phone verification, you can set the variable `ZVONOK_VERIFICATION_TEMPLATE`
- with the following format (optional step): `Your verification code is $verification_code, have a nice day.`.
+7. Create phone number verification campaign with type `tellcode` and assign its ID value to `ZVONOK_VERIFICATION_CAMPAIGN_ID`.
8. To process the call status, it is required to add a postback with the GET/POST method on the side of the zvonok.com
service with the following format (optional step):
`${ONCALL_BASE_URL}/zvonok/call_status_events?campaign_id={ct_campaign_id}&call_id={ct_call_id}&status={ct_status}&user_choice={ct_user_choice}`
diff --git a/engine/apps/base/models/live_setting.py b/engine/apps/base/models/live_setting.py
index f6e8b7e5..7c9d39b0 100644
--- a/engine/apps/base/models/live_setting.py
+++ b/engine/apps/base/models/live_setting.py
@@ -71,7 +71,7 @@ class LiveSetting(models.Model):
"ZVONOK_POSTBACK_STATUS",
"ZVONOK_POSTBACK_USER_CHOICE",
"ZVONOK_POSTBACK_USER_CHOICE_ACK",
- "ZVONOK_VERIFICATION_TEMPLATE",
+ "ZVONOK_VERIFICATION_CAMPAIGN_ID",
)
DESCRIPTIONS = {
@@ -170,7 +170,7 @@ class LiveSetting(models.Model):
"ZVONOK_POSTBACK_STATUS": "'Postback' status (ct_status) query parameter name to validate a postback request.",
"ZVONOK_POSTBACK_USER_CHOICE": "'Postback' user choice (ct_user_choice) query parameter name (optional).",
"ZVONOK_POSTBACK_USER_CHOICE_ACK": "'Postback' user choice (ct_user_choice) query parameter value for acknowledge alert group (optional).",
- "ZVONOK_VERIFICATION_TEMPLATE": "The message template used for phone number verification (optional).",
+ "ZVONOK_VERIFICATION_CAMPAIGN_ID": "The phone number verification campaign ID. You can get it after verification campaign creation.",
}
SECRET_SETTING_NAMES = (
diff --git a/engine/apps/zvonok/phone_provider.py b/engine/apps/zvonok/phone_provider.py
index e19e771f..4af75b6b 100644
--- a/engine/apps/zvonok/phone_provider.py
+++ b/engine/apps/zvonok/phone_provider.py
@@ -1,6 +1,5 @@
import logging
from random import randint
-from string import Template
from typing import Optional
import requests
@@ -12,6 +11,7 @@ from apps.phone_notifications.phone_provider import PhoneProvider, ProviderFlags
from apps.zvonok.models.phone_call import ZvonokCallStatuses, ZvonokPhoneCall
ZVONOK_CALL_URL = "https://zvonok.com/manager/cabapi_external/api/v1/phones/call/"
+ZVONOK_VERIFICATION_CALL_URL = "https://zvonok.com/manager/cabapi_external/api/v1/phones/tellcode/"
logger = logging.getLogger(__name__)
@@ -96,6 +96,15 @@ class ZvonokPhoneProvider(PhoneProvider):
return requests.post(ZVONOK_CALL_URL, params=params)
+ def _verification_call_create(self, number: str, code: int):
+ params = {
+ "public_key": live_settings.ZVONOK_API_KEY,
+ "campaign_id": live_settings.ZVONOK_VERIFICATION_CAMPAIGN_ID,
+ "phone": number,
+ "pincode": code,
+ }
+ return requests.post(ZVONOK_VERIFICATION_CALL_URL, params=params)
+
def _get_graceful_msg(self, body, number):
if body:
status = body.get("status")
@@ -105,34 +114,19 @@ class ZvonokPhoneProvider(PhoneProvider):
return f"Failed make call to {number}"
def make_verification_call(self, number: str):
+ body = None
code = self._generate_verification_code()
cache.set(self._cache_key(number), code, timeout=10 * 60)
- codewspaces = " ".join(code)
- body = None
- speaker = live_settings.ZVONOK_SPEAKER_ID
-
- if live_settings.ZVONOK_VERIFICATION_TEMPLATE:
- message = Template(live_settings.ZVONOK_VERIFICATION_TEMPLATE).safe_substitute(
- verification_code=codewspaces
+ if not live_settings.ZVONOK_VERIFICATION_CAMPAIGN_ID:
+ raise FailedToStartVerification(
+ graceful_msg="Failed make verification call, verification campaign id not set."
)
- else:
- message = f"Your verification code is {codewspaces}"
+
try:
- response = self._call_create(
- number,
- message,
- speaker,
- )
- response.raise_for_status()
+ response = self._verification_call_create(number, code)
body = response.json()
- if not body:
- logger.error("ZvonokPhoneProvider.make_verification_call: failed, empty body")
- raise FailedToMakeCall(graceful_msg=f"Failed make verification call to {number}, empty body")
-
- call_id = body.get("call_id")
- if not call_id:
- raise FailedToStartVerification(graceful_msg=self._get_graceful_msg(body, number))
+ response.raise_for_status()
except requests.exceptions.HTTPError as http_err:
logger.error(f"ZvonokPhoneProvider.make_verification_call: failed {http_err}")
raise FailedToStartVerification(graceful_msg=self._get_graceful_msg(body, number))
diff --git a/engine/apps/zvonok/tests/test_zvonok_provider.py b/engine/apps/zvonok/tests/test_zvonok_provider.py
index 04eab9da..5e25045f 100644
--- a/engine/apps/zvonok/tests/test_zvonok_provider.py
+++ b/engine/apps/zvonok/tests/test_zvonok_provider.py
@@ -3,6 +3,7 @@ from unittest.mock import MagicMock, patch
import pytest
from django.test import override_settings
+from apps.phone_notifications.exceptions import FailedToStartVerification
from apps.zvonok.phone_provider import ZvonokPhoneProvider
@@ -12,46 +13,37 @@ def provider():
@pytest.mark.django_db
-def test_make_verification_call_with_template_set(provider):
- verification_code = "123456"
+def test_make_verification_call(provider):
+ verification_code = "123456789"
number = "1234567890"
- speaker_id = "Salli"
- template_value = 'Your code is $verification_code'
- excepted_message = 'Your code is 1 2 3 4 5 6'
-
- with override_settings(ZVONOK_VERIFICATION_TEMPLATE=template_value, ZVONOK_SPEAKER_ID=speaker_id):
+ campaign_id = "123456"
+ with override_settings(ZVONOK_VERIFICATION_CAMPAIGN_ID=campaign_id):
with patch("django.core.cache.cache.set"):
- provider._call_create = MagicMock(return_value=MagicMock(json=lambda: {"call_id": "12345"}))
+ provider._verification_call_create = MagicMock(return_value=MagicMock(json=lambda: {"status": "ok"}))
provider._generate_verification_code = MagicMock(return_value=verification_code)
provider.make_verification_call(number)
- provider._call_create.assert_called_once_with(number, excepted_message, speaker_id)
+ provider._verification_call_create.assert_called_once_with(number, verification_code)
@pytest.mark.django_db
-def test_make_verification_call_with_invalid_template_set(provider):
- verification_code = "123456"
+def test_make_verification_call_without_campaign_id(provider):
number = "1234567890"
- speaker_id = "Salli"
- template_value = "Your code is"
- excepted_message = "Your code is"
-
- with override_settings(ZVONOK_VERIFICATION_TEMPLATE=template_value, ZVONOK_SPEAKER_ID=speaker_id):
- with patch("django.core.cache.cache.set"):
- provider._call_create = MagicMock(return_value=MagicMock(json=lambda: {"call_id": "12345"}))
- provider._generate_verification_code = MagicMock(return_value=verification_code)
+ with patch("django.core.cache.cache.set"):
+ with pytest.raises(FailedToStartVerification):
provider.make_verification_call(number)
- provider._call_create.assert_called_once_with(number, excepted_message, speaker_id)
@pytest.mark.django_db
-def test_make_verification_call_without_template_set(provider):
- verification_code = "123456"
+def test_make_verification_call_with_error(provider):
number = "1234567890"
- speaker_id = "Salli"
- excepted_message = "Your verification code is 1 2 3 4 5 6"
- with override_settings(ZVONOK_SPEAKER_ID=speaker_id):
+ campaign_id = "123456"
+
+ with override_settings(ZVONOK_VERIFICATION_CAMPAIGN_ID=campaign_id):
with patch("django.core.cache.cache.set"):
- provider._call_create = MagicMock(return_value=MagicMock(json=lambda: {"call_id": "12345"}))
- provider._generate_verification_code = MagicMock(return_value=verification_code)
- provider.make_verification_call(number)
- provider._call_create.assert_called_once_with(number, excepted_message, speaker_id)
+ with pytest.raises(FailedToStartVerification):
+ provider._verification_call_create = MagicMock(
+ return_value=MagicMock(
+ json={"status": "error", "data": "Form isn't valid: * campaign_id\n * Invalid campaign type"}
+ )
+ )
+ provider.make_verification_call(number)
diff --git a/engine/settings/base.py b/engine/settings/base.py
index 48d3fbdd..c528ba3c 100644
--- a/engine/settings/base.py
+++ b/engine/settings/base.py
@@ -912,7 +912,7 @@ ZVONOK_POSTBACK_CAMPAIGN_ID = os.getenv("ZVONOK_POSTBACK_CAMPAIGN_ID", "campaign
ZVONOK_POSTBACK_STATUS = os.getenv("ZVONOK_POSTBACK_STATUS", "status")
ZVONOK_POSTBACK_USER_CHOICE = os.getenv("ZVONOK_POSTBACK_USER_CHOICE", None)
ZVONOK_POSTBACK_USER_CHOICE_ACK = os.getenv("ZVONOK_POSTBACK_USER_CHOICE_ACK", None)
-ZVONOK_VERIFICATION_TEMPLATE = os.getenv("ZVONOK_VERIFICATION_TEMPLATE", None)
+ZVONOK_VERIFICATION_CAMPAIGN_ID = os.getenv("ZVONOK_VERIFICATION_CAMPAIGN_ID", None)
DETACHED_INTEGRATIONS_SERVER = getenv_boolean("DETACHED_INTEGRATIONS_SERVER", default=False)