Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 24 additions & 20 deletions bandwidth/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from bandwidth.messaging.exceptions.messaging_exception import MessagingException
from bandwidth.exceptions.api_exception import APIException
from bandwidth.messaging.models.message_request import MessageRequest
from bandwidth.voice.exceptions.api_error_exception import ApiErrorException
from bandwidth.voice.models.create_call_request import CreateCallRequest
from bandwidth.voice.models.machine_detection_configuration import MachineDetectionConfiguration
from bandwidth.voice.models.callback_method_enum import CallbackMethodEnum
Expand Down Expand Up @@ -222,13 +223,31 @@ def test_successful_create_and_get_call(self, voice_client):

create_response = voice_client.create_call(BW_ACCOUNT_ID, call_body)
create_response_body = create_response.body
time.sleep(15)
get_response = voice_client.get_call(BW_ACCOUNT_ID, create_response.body.call_id)
get_response_body = get_response.body
time.sleep(2)
try:
get_response = voice_client.get_call(BW_ACCOUNT_ID, create_response.body.call_id)
get_response_body = get_response.body
print(vars(get_response))
assert get_response.status_code == 200
assert get_response_body.call_id == create_response_body.call_id
assert get_response_body.application_id == BW_VOICE_APPLICATION_ID
assert get_response_body.account_id == BW_ACCOUNT_ID
if get_response_body.start_time:
assert dateutil.parser.isoparse(str(get_response_body.start_time))
assert dateutil.parser.isoparse(str(get_response_body.enqueued_time))
assert dateutil.parser.isoparse(str(get_response_body.last_update))
if get_response_body.answer_time: # may be null dependent on timing
assert dateutil.parser.isoparse(str(get_response_body.answer_time))
if get_response_body.end_time: # may be null dependent on timing
assert dateutil.parser.isoparse(str(get_response_body.end_time))
if get_response_body.disconnect_cause == "error":
assert type(get_response_body.error_message) is str
assert len(get_response_body.error_id) == 36
except ApiErrorException as e:
if e.response_code != 404:
raise e

print(vars(create_response))
print(vars(get_response))

assert create_response.status_code == 201
assert len(create_response_body.call_id) == 47 # assert request created and id matches expected length (47)
assert create_response_body.account_id == BW_ACCOUNT_ID
Expand All @@ -242,21 +261,6 @@ def test_successful_create_and_get_call(self, voice_client):
assert type(create_response_body.callback_timeout) is float
assert create_response_body.answer_method == "POST"
assert create_response_body.disconnect_method == "GET"
assert get_response.status_code == 200
assert get_response_body.call_id == create_response_body.call_id
assert get_response_body.application_id == BW_VOICE_APPLICATION_ID
assert get_response_body.account_id == BW_ACCOUNT_ID
if get_response_body.start_time:
assert dateutil.parser.isoparse(str(get_response_body.start_time))
assert dateutil.parser.isoparse(str(get_response_body.enqueued_time))
assert dateutil.parser.isoparse(str(get_response_body.last_update))
if get_response_body.answer_time: # may be null dependent on timing
assert dateutil.parser.isoparse(str(get_response_body.answer_time))
if get_response_body.end_time: # may be null dependent on timing
assert dateutil.parser.isoparse(str(get_response_body.end_time))
if get_response_body.disconnect_cause == "error":
assert type(get_response_body.error_message) is str
assert len(get_response_body.error_id) == 36

def test_failed_create_and_failed_get_call(self, voice_client):
"""Create a failed call and get status of a call that doesnt exist.
Expand Down
39 changes: 39 additions & 0 deletions bandwidth/tests/test_bxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,42 @@ def test_stop_stream_bxml_verb(self):
actual = response.to_bxml()

assert expected == actual

def test_start_transcription_bxml_verb(self):
expected = '<?xml version="1.0" encoding="UTF-8"?><Response><StartTranscription name="name" tracks="both" transcriptionEventUrl="https://www.test.com/transcription" transcriptionEventMethod="POST" username="username" password="password" destination="https://www.test.com/transcribeCallback" stabilized="true"><CustomParam name="name1" value="value1"/><CustomParam name="name2" value="value2"/></StartTranscription></Response>'
response = Response()
custom_param_1 = CustomParam(
name="name1",
value="value1"
)
custom_param_2 = CustomParam(
name="name2",
value="value2"
)
custom_params = [custom_param_1, custom_param_2]
start_transcription = StartTranscription(
name='name',
tracks='both',
transcription_event_url='https://www.test.com/transcription',
transcription_event_method='POST',
username='username',
password='password',
destination='https://www.test.com/transcribeCallback',
stabilized=True,
custom_params=custom_params
)
response.add_verb(start_transcription)
actual = response.to_bxml()

assert expected == actual

def test_stop_transcription_bxml(self):
expected= '<?xml version="1.0" encoding="UTF-8"?><Response><StopTranscription name="name"/></Response>'
response = Response()
stop_transcription = StopTranscription(
name='name'
)
response.add_verb(stop_transcription)
actual = response.to_bxml()

assert expected == actual
3 changes: 3 additions & 0 deletions bandwidth/voice/bxml/verbs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@
from .start_stream import StartStream
from .stream_param import StreamParam
from .stop_stream import StopStream
from .start_transcription import StartTranscription
from .stop_transcription import StopTranscription
from .custom_param import CustomParam
38 changes: 38 additions & 0 deletions bandwidth/voice/bxml/verbs/custom_param.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
custom_param.py

Representation of Bandwidth's StartTranscription BXML verb

@license MIT
"""

from lxml import etree

from .base_verb import AbstractBxmlVerb

CUSTOM_PARAM_TAG = "CustomParam"


class CustomParam(AbstractBxmlVerb):
def __init__(
self,
name: str,
value: str,
):
"""
Initializes the CustomParam class
:param name: The name of this parameter, up to 256 characters.
:param value: The value of this parameter, up to 2048 characters.
"""
self.name = name
self.value = value

def to_etree_element(self):
root = etree.Element(CUSTOM_PARAM_TAG)
root.set("name", self.name)
root.set("value", self.value)
return root

def to_bxml(self):
root = etree.Element(CUSTOM_PARAM_TAG)
return etree.tostring(root).decode()
76 changes: 76 additions & 0 deletions bandwidth/voice/bxml/verbs/start_transcription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
start_transcription.py

Representation of Bandwidth's StartTranscription BXML verb

@license MIT
"""

from typing import List

from lxml import etree

from .base_verb import AbstractBxmlVerb
from .custom_param import CustomParam

START_TRANSCRIPTION_TAG = "StartTranscription"


class StartTranscription(AbstractBxmlVerb):

def __init__(
self,
name: str = None,
tracks: str = None,
transcription_event_url: str = None,
transcription_event_method: str = None,
username: str = None,
password: str = None,
destination: str = None,
stabilized: bool = None,
custom_params: List[CustomParam] = None,
):
"""
Initializes the StartTranscription class
:param name: A name to refer to this transcription by. Used when sending <StopTranscription>. If not provided, it will default to the generated transcription id as sent in the Real-Time Transcription Started webhook.
:param tracks: The part of the call to send a transcription from. inbound, outbound or both. Default is inbound.
:param transcription_event_url: URL to send the associated Webhook events to during this real-time transcription's lifetime. Does not accept BXML. May be a relative URL.
:param transcription_event_method: The HTTP method to use for the request to transcriptionEventUrl. GET or POST. Default value is POST.
:param username: The username to send in the HTTP request to transcriptionEventUrl. If specified, the transcriptionEventUrl must be TLS-encrypted (i.e., https).
:param password: The password to send in the HTTP request to transcriptionEventUrl. If specified, the transcriptionEventUrl must be TLS-encrypted (i.e., https).
:param destination: A websocket URI to send the transcription to. A transcription of the specified tracks will be sent via websocket to this URL as a series of JSON messages. See below for more details on the websocket packet format.
:param stabilized: Whether to send transcription update events to the specified destination only after they have become stable. Requires destination. Defaults to true.
:param custom_params: These elements define optional user specified parameters that will be sent to the destination URL when the real-time transcription is first started.
"""
self.name = name
self.tracks = tracks
self.transcription_event_url = transcription_event_url
self.transcription_event_method = transcription_event_method
self.username = username
self.password = password
self.destination = destination
self.stabilized = stabilized
self.custom_params = custom_params

def to_bxml(self):
root = etree.Element(START_TRANSCRIPTION_TAG)
if self.name is not None:
root.set("name", self.name)
if self.tracks is not None:
root.set("tracks", self.tracks)
if self.transcription_event_url is not None:
root.set("transcriptionEventUrl", self.transcription_event_url)
if self.transcription_event_method is not None:
root.set("transcriptionEventMethod", self.transcription_event_method)
if self.username is not None:
root.set("username", self.username)
if self.password is not None:
root.set("password", self.password)
if self.destination is not None:
root.set("destination", self.destination)
if self.stabilized is not None:
root.set("stabilized", str(self.stabilized).lower())
if self.custom_params is not None:
for custom_param in self.custom_params:
root.append(custom_param.to_etree_element())
return etree.tostring(root).decode()
32 changes: 32 additions & 0 deletions bandwidth/voice/bxml/verbs/stop_transcription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
stop_transcription.py

Representation of Bandwidth's StartTranscription BXML verb

@license MIT
"""

from lxml import etree

from .base_verb import AbstractBxmlVerb

STOP_TRANSCRIPTION_TAG = "StopTranscription"


class StopTranscription(AbstractBxmlVerb):

def __init__(
self,
name: str = None
):
"""
Initializes the StopTranscription class
:param name: The name of the real-time transcription to stop. This is either the user selected name when sending the <StartTranscription> verb, or the system generated name returned in the Real-Time Transcription Started webhook if <StartTranscription> was sent with no name attribute. If no name is specified, then all active call transcriptions will be stopped.
"""
self.name = name

def to_bxml(self):
root = etree.Element(STOP_TRANSCRIPTION_TAG)
if self.name is not None:
root.set("name", self.name)
return etree.tostring(root).decode()