diff --git a/bandwidth/model/bxml/terminal_verb.py b/bandwidth/model/bxml/terminal_verb.py index b2766f79..41d689d5 100644 --- a/bandwidth/model/bxml/terminal_verb.py +++ b/bandwidth/model/bxml/terminal_verb.py @@ -28,6 +28,6 @@ def add_verb(self, verb: Verb): verb (Verb): BXML verb Raises: - AttributeError: This method is not allowed for + AttributeError: This method is not allowed for this verb """ raise AttributeError('Adding verbs is not supported by this verb') diff --git a/bandwidth/model/bxml/verbs/__init__.py b/bandwidth/model/bxml/verbs/__init__.py index b630beda..564ade94 100644 --- a/bandwidth/model/bxml/verbs/__init__.py +++ b/bandwidth/model/bxml/verbs/__init__.py @@ -1,8 +1,22 @@ from .bridge import Bridge +from .conference import Conference +from .hangup import Hangup +from .gather import Gather +from .pause import Pause from .pause_recording import PauseRecording from .phone_number import PhoneNumber +from .play_audio import PlayAudio from .record import Record +from .ring import Ring from .send_dtmf import SendDtmf from .sip_uri import SipUri +from .speak_sentence import SpeakSentence +from .start_gather import StartGather +from .start_recording import StartRecording +from .start_stream import StartStream +from .stop_gather import StopGather +from .stop_stream import StopStream +from .stop_recording import StopRecording +from .stream_param import StreamParam from .tag import Tag from .transfer import Transfer diff --git a/bandwidth/model/bxml/verbs/conference.py b/bandwidth/model/bxml/verbs/conference.py new file mode 100644 index 00000000..2c1dc49e --- /dev/null +++ b/bandwidth/model/bxml/verbs/conference.py @@ -0,0 +1,97 @@ +""" +conference.py + +Bandwidth's Conference BXML verb + +@copyright Bandwidth INC +""" +from typing import Union, List +from ..verb import Verb +from .play_audio import PlayAudio +from .speak_sentence import SpeakSentence +from .start_recording import StartRecording +from .stop_recording import StopRecording +from .pause_recording import PauseRecording +from .resume_recording import ResumeRecording + + +class Conference(Verb): + + def __init__( + self, name: str, + audio_and_recording_verbs: List[Union[PlayAudio, SpeakSentence, StartRecording, StopRecording, PauseRecording, ResumeRecording]] = [], mute: str=None, + hold: str=None, call_ids_to_coach: str=None, + conference_event_url: str=None, conference_event_method: str=None, + conference_event_fallback_url: str=None, conference_event_fallback_method: str=None, + username: str=None, password: str=None, + fallback_username: str=None, fallback_password: str=None, + tag: str=None, callback_timeout: str=None, + ): + """Initialize a verb + + Args: + name (str): The name of the conference. Can contain up to 100 characters of letters, numbers, and the symbols -, _, and . + mute (str, optional): A boolean value to indicate whether the member should be on mute in the conference. When muted, a member can hear others speak, but others cannot hear them speak. Defaults to false. + hold (str, optional): A boolean value to indicate whether the member should be on hold in the conference. When on hold, a member cannot hear others, and they cannot be heard. Defaults to false. + call_ids_to_coach (str, optional): A comma-separated list of call ids to coach. When a call joins a conference with this attribute set, it will coach the listed calls. + Those calls will be able to hear and be heard by the coach, but other calls in the conference will not hear the coach. + conference_event_url (str, optional): URL to send Conference events to. The URL, method, username, and password are set by the BXML document that creates the conference, + and all events related to that conference will be delivered to that same endpoint. If more calls join afterwards and also have this property (or any other webhook related properties like username and password), + they will be ignored and the original webhook information will be used. This URL may be a relative endpoint. + conference_event_method (str, optional): The HTTP method to use for the request to conferenceEventUrl. GET or POST. Default value is POST. + conference_event_fallback_url (str, optional): A fallback url which, if provided, will be used to retry the conference webhook deliveries in case conferenceEventUrl fails to respond. + conference_event_fallback_method (str, optional): The HTTP method to use to deliver the conference webhooks to conferenceEventFallbackUrl. GET or POST. Default value is POST. + username (str, optional):The username to send in the HTTP request to conferenceEventUrl. + password (str, optional): The password to send in the HTTP request to conferenceEventUrl. + fallback_username (str, optional): The username to send in the HTTP request to conferenceEventFallbackUrl. + fallback_password (str, optional): The password to send in the HTTP request to conferenceEventFallbackUrl. + tag (str, optional): A custom string that will be sent with this and all future callbacks unless overwritten by a future tag attribute or verb, or cleared. May be cleared by setting tag="". + Max length 256 characters. Defaults to None. + callback_timeout (str, optional): This is the timeout (in seconds) to use when delivering webhooks for the conference. + If not set, it will inherit the webhook timeout from the call that creates the conference. Can be any numeric value (including decimals) between 1 and 25. + + Nested Verbs: + PlayAudio: (optional) + SpeakSentence: (optional) + StartRecording: (optional) + StopRecording: (optional) + PauseRecording: (optional) + ResumeRecording: (optional) + """ + self.name = name + self.mute = mute + self.hold = hold + self.call_ids_to_coach = call_ids_to_coach + self.conference_event_url = conference_event_url + self.conference_event_method = conference_event_method + self.conference_event_fallback_url = conference_event_fallback_url + self.conference_event_fallback_method = conference_event_fallback_method + self.username = username + self.password = password + self.fallback_username = fallback_username + self.fallback_password = fallback_password + self.tag = tag + self.callback_timeout = callback_timeout + self.audio_and_recording_verbs = audio_and_recording_verbs + super().__init__( + tag="Conference", + content=self.name, + nested_verbs=self.audio_and_recording_verbs) + + @property + def _attributes(self): + return { + "mute": self.mute, + "hold": self.hold, + "callIdsToCoach": self.call_ids_to_coach, + "conferenceEventUrl": self.conference_event_url, + "conferenceEventMethod": self.conference_event_method, + "conferenceEventFallbackUrl": self.conference_event_fallback_url, + "conferenceEventFallbackMethod": self.conference_event_fallback_method, + "username": self.username, + "password": self.password, + "fallbackUsername": self.fallback_username, + "fallbackPassword": self.fallback_password, + "tag": self.tag, + "callbackTimeout": self.callback_timeout, + } diff --git a/bandwidth/model/bxml/verbs/forward.py b/bandwidth/model/bxml/verbs/forward.py new file mode 100644 index 00000000..27caea98 --- /dev/null +++ b/bandwidth/model/bxml/verbs/forward.py @@ -0,0 +1,67 @@ +""" +forward.py + +Bandwidth's Forward BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class Forward(TerminalVerb): + + def __init__( + self, to: str=None, _from: str=None, + call_timeout: str=None, diversion_treatment: str=None, + diversion_reason: str=None, uui: str=None + ): + """Initialize a verb + + Args: + to (str): The phone number destination of the call. + from_ (str, optional): The phone number that the recipient will receive the call from. + call_timeout (str, optional): The number of seconds to wait before timing out the call. + diversion_treatment (str, optional): Can be any of the following: + none: No diversion headers are sent on the outbound leg of the transferred call. + propagate: Copy the Diversion header from the inbound leg to the outbound leg. Ignored if there is no Diversion header present on the inbound leg. + stack: After propagating any Diversion header from the inbound leg to the outbound leg, stack on top another Diversion header based on the Request-URI of the inbound call. + + Defaults to none. If diversionTreatment is not specified, no diversion header will be included for the transfer even if one came with the inbound call. Defaults to None. + diversion_reason (str, optional): Can be any of the following values: + unknown + user-busy + no-answer + unavailable + unconditional + time-of-day + do-not-disturb + deflection + follow-me + out-of-service + away + + This parameter is considered only when diversionTreatment is set to stack. Defaults is unknown. + Defaults to None. + uui (str, optional): The value of the User-To-User header to send within the outbound INVITE when forwarding to a SIP URI. + Must include the encoding parameter as specified in RFC 7433. Only base64 and jwt encoding are currently allowed. + This value, including the encoding specifier, may not exceed 256 characters. + """ + self.to = to + self._from = _from + self.call_timeout = call_timeout + self.diversion_treatment = diversion_treatment + self.diversion_reason = diversion_reason + self.uui = uui + + super().__init__(tag="Forward") + + @property + def _attributes(self): + return { + "to": self.to, + "_from": self._from, + "callTimeout": self.call_timeout, + "diversionTreatment": self.diversion_treatment, + "diversionReason": self.diversion_reason, + "uui": self.uui, + } diff --git a/bandwidth/model/bxml/verbs/gather.py b/bandwidth/model/bxml/verbs/gather.py new file mode 100644 index 00000000..7285a1b4 --- /dev/null +++ b/bandwidth/model/bxml/verbs/gather.py @@ -0,0 +1,87 @@ +""" +gather.py + +Bandwidth's Gather BXML verb + +@copyright Bandwidth INC +""" +from typing import Union, List +from ..verb import Verb +from .play_audio import PlayAudio +from .speak_sentence import SpeakSentence + + +class Gather(Verb): + + def __init__( + self, audio_verbs: List[Union[PlayAudio, SpeakSentence]] = [], + gather_url: str=None, gather_method: str=None, + gather_fallback_url: str=None, gather_fallback_method: str=None, + username: str=None, password: str=None, + fallback_username: str=None, fallback_password: str=None, + tag: str=None, terminating_digits: str=None, + max_digits: str=None, inter_digit_timeout: str=None, + first_digit_timeout: str=None, repeat_count: str=None + ): + """Initialize a verb + + Args: + gather_url (str, optional): URL to send Gather event to and request new BXML. May be a relative URL. + gather_method (str, optional): The HTTP method to use for the request to gather_url. GET or POST. Default value is POST. + gather_fallback_url (str, optional): A fallback url which, if provided, will be used to retry the Gather event callback delivery in case gather_url fails to respond. + gather_fallback_method (str, optional): The HTTP method to use to deliver the Gather event callback to gather_fallback_url. GET or POST. Default value is POST. + username (str, optional): The username to send in the HTTP request to gather_url. + password (str, optional): The password to send in the HTTP request to gather_url. + fallback_username (str, optional): The username to send in the HTTP request to gather_fallback_url. + fallback_password (str, optional): The password to send in the HTTP request to gather_fallback_url. + tag (str, optional): A custom string that will be sent with this and all future callbacks unless overwritten by a future tag attribute or verb, or cleared. + May be cleared by setting tag="". Max length 256 characters. + terminating_digits (str, optional): When any of these digits are pressed, it will terminate the Gather. Default value is "", which disables this feature. + max_digits (str, optional): Max number of digits to collect. Default value is 50. Range: decimal values between 1 - 50. + inter_digit_timeout (str, optional): Time (in seconds) allowed between digit presses before automatically terminating the Gather. Default value is 5. Range: decimal values between 1 - 60. + first_digit_timeout (str, optional): Time (in seconds) to pause after any audio from nested or verb is played (in seconds) before terminating the Gather. + Default value is 5. Range: decimal values between 0 - 60. + repeat_count (str, optional): The number of times the audio prompt should be played if no digits are pressed. For example, if this value is 3, the nested audio clip will be played a maximum of three times. + The delay between repetitions will be equal to first_digit_timeout. Default value is 1. repeat_count * number of verbs must not be greater than 20. + + Nested Verbs: + PlayAudio: (optional) Using the PlayAudio inside the Gather verb will play the media until a digit is received. + SpeakSentence: (optional) Using the SpeakSentence inside the Gather verb will speak the text until a digit is received. + """ + self.gather_url = gather_url + self.gather_method = gather_method + self.gather_fallback_url = gather_fallback_url + self.gather_fallback_method = gather_fallback_method + self.username = username + self.password = password + self.fallback_username = fallback_username + self.fallback_password = fallback_password + self.tag = tag + self.terminating_digits = terminating_digits + self.max_digits = max_digits + self.inter_digit_timeout = inter_digit_timeout + self.first_digit_timeout = first_digit_timeout + self.repeat_count = repeat_count + self.audio_verbs = audio_verbs + super().__init__( + tag="Gather", + nested_verbs=self.audio_verbs) + + @property + def _attributes(self): + return { + "gatherUrl": self.gather_url, + "gatherMethod": self.gather_method, + "gatherFallbackUrl": self.gather_fallback_url, + "gatherFallbackMethod": self.gather_fallback_method, + "username": self.username, + "password": self.password, + "fallbackUsername": self.fallback_username, + "fallbackPassword": self.fallback_password, + "tag": self.tag, + "terminatingDigits": self.terminating_digits, + "maxDigits": self.max_digits, + "interDigitTimeout": self.inter_digit_timeout, + "firstDigitTimeout": self.first_digit_timeout, + "repeatCount": self.repeat_count, + } diff --git a/bandwidth/model/bxml/verbs/hangup.py b/bandwidth/model/bxml/verbs/hangup.py new file mode 100644 index 00000000..f6603efa --- /dev/null +++ b/bandwidth/model/bxml/verbs/hangup.py @@ -0,0 +1,19 @@ +""" +hangup.py + +Bandwidth's Hangup BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class Hangup(TerminalVerb): + + def __init__(self): + """Initialize a verb + + Args: + None + """ + super().__init__(tag="Hangup") diff --git a/bandwidth/model/bxml/verbs/pause.py b/bandwidth/model/bxml/verbs/pause.py new file mode 100644 index 00000000..67202f47 --- /dev/null +++ b/bandwidth/model/bxml/verbs/pause.py @@ -0,0 +1,23 @@ +""" +pause.py + +Bandwidth's Pause BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb +class Pause(TerminalVerb): + def __init__(self, duration:str=None): + """Initialize a verb + Args: + duration (str, optional): The time in seconds to pause. Default value is 1. + """ + self.duration = duration + + super().__init__(tag="Pause") + + @property + def _attributes(self): + return { + "duration": self.duration + } \ No newline at end of file diff --git a/bandwidth/model/bxml/verbs/pause_recording.py b/bandwidth/model/bxml/verbs/pause_recording.py index dffc73ab..b7a7de5e 100644 --- a/bandwidth/model/bxml/verbs/pause_recording.py +++ b/bandwidth/model/bxml/verbs/pause_recording.py @@ -13,4 +13,4 @@ class PauseRecording(TerminalVerb): def __init__(self): """Initialize a verb """ - super().__init__(tag="PauseRecording", content=None, attributes=None) + super().__init__(tag="PauseRecording") diff --git a/bandwidth/model/bxml/verbs/play_audio.py b/bandwidth/model/bxml/verbs/play_audio.py new file mode 100644 index 00000000..727d1256 --- /dev/null +++ b/bandwidth/model/bxml/verbs/play_audio.py @@ -0,0 +1,37 @@ +""" +play_audio.py + +Bandwidth's PlayAudio BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class PlayAudio(TerminalVerb): + + def __init__( + self, audio_uri: str, + username: str=None, password: str=None + ): + """Initialize a verb + + Args: + audio_uri (str): The URL of the audio file to play. May be a relative URL. + username (str, optional): The username to send in the HTTP request to audio_uri. + password (str, optional): The password to send in the HTTP request to audio_uri. + """ + self.audio_uri = audio_uri + self.username = username + self.password = password + super().__init__( + tag="PlayAudio", + content=self.audio_uri, + ) + + @property + def _attributes(self): + return { + "username": self.username, + "password": self.password, + } diff --git a/bandwidth/model/bxml/verbs/resume_recording.py b/bandwidth/model/bxml/verbs/resume_recording.py new file mode 100644 index 00000000..45fdf166 --- /dev/null +++ b/bandwidth/model/bxml/verbs/resume_recording.py @@ -0,0 +1,21 @@ +""" +record.py + +Bandwidth's ResumeRecording BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class ResumeRecording(TerminalVerb): + + def __init__( + self + ): + """Initialize a verb + + Args: There are no args or text content for ResumeRecording + """ + + super().__init__(tag="ResumeRecording", content=None) diff --git a/bandwidth/model/bxml/verbs/ring.py b/bandwidth/model/bxml/verbs/ring.py new file mode 100644 index 00000000..632911bf --- /dev/null +++ b/bandwidth/model/bxml/verbs/ring.py @@ -0,0 +1,32 @@ +""" +ring.py + +Bandwidth's Ring BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class Ring(TerminalVerb): + + def __init__( + self, duration: str = None, + answer_call: str = None, + ): + """Initialize a verb + + Args: + duration (str, optional): How many seconds to play ringing on the call. Default value is 5. Range: decimal values between 0.1 - 86400. + answer_call (str, optional): A boolean indicating whether or not to answer the call when Ring is executed on an unanswered incoming call. Default value is 'true'. + """ + self.duration = duration + self.answer_call = answer_call + super().__init__(tag="Ring") + + @property + def _attributes(self): + return { + "duration": self.duration, + "answerCall": self.answer_call, + } diff --git a/bandwidth/model/bxml/verbs/speak_sentence.py b/bandwidth/model/bxml/verbs/speak_sentence.py new file mode 100644 index 00000000..6fd05f44 --- /dev/null +++ b/bandwidth/model/bxml/verbs/speak_sentence.py @@ -0,0 +1,42 @@ +""" +speak_sentence.py + +Bandwidth's SpeakSentence BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class SpeakSentence(TerminalVerb): + + def __init__( + self, text: str, voice: str=None, + gender: str=None, locale: str=None + ): + """Initialize a verb + + Args: + text (str): The text to speak. Cannot be blank. Can be a mixture of plain text and SSML tags. + You can find a list of supported SSML tags here: https://dev.bandwidth.com/docs/voice/bxml/speakSentence/#supported-ssml-tags + voice (str, optional): Selects the voice of the speaker. Consult the voice column in the below table for valid values. + If the voice attribute is present, gender and locale are ignored. You can find a list of supported voices here: https://dev.bandwidth.com/docs/voice/bxml/speakSentence/#supported-voices + gender (str, optional): Selects the gender of the speaker. Valid values are "male" or "female". Default "female". + locale (str, optional): Selects the locale of the speaker. Consult the locale column in the below table for valid values. Default "en_US" + """ + self.text = text + self.voice = voice + self.gender = gender + self.locale = locale + super().__init__( + tag="SpeakSentence", + content=self.text, + ) + + @property + def _attributes(self): + return { + "voice": self.voice, + "gender": self.gender, + "locale": self.locale, + } diff --git a/bandwidth/model/bxml/verbs/start_gather.py b/bandwidth/model/bxml/verbs/start_gather.py new file mode 100644 index 00000000..560e4c78 --- /dev/null +++ b/bandwidth/model/bxml/verbs/start_gather.py @@ -0,0 +1,43 @@ +""" +start_gather.py + +Bandwidth's StartGather BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class StartGather(TerminalVerb): + + def __init__( + self, dtmf_url: str, dtmf_method: str=None, username: str=None, + password: str=None, tag: str=None, + ): + """Initialize a verb + + Args: + dtmf_url (str): URL to send the DTMF event to. May be a relative URL.. + dtmf_method (str, optional): The HTTP method to use for the request to dtmfUrl. GET or POST. Default value is POST. Defaults to None. + username (str, optional): The username to send in the HTTP request to dtmfUrl. Defaults to None. + password (str, optional): The password to send in the HTTP request to dtmfUrl. Defaults to None. + tag (str, optional): A custom string that will be sent with these and all future callbacks unless overwritten by a future tag attribute or cleared. May be cleared by setting tag="" Max length 256 characters. Defaults to None. + """ + self.dtmf_url = dtmf_url + self.dtmf_method = dtmf_method + self.username = username + self.password = password + self.tag = tag + super().__init__( + tag="StartGather" + ) + + @property + def _attributes(self): + return { + "dtmfUrl": self.dtmf_url, + "dtmfMethod": self.dtmf_method, + "username": self.username, + "password": self.password, + "tag": self.tag + } diff --git a/bandwidth/model/bxml/verbs/start_recording.py b/bandwidth/model/bxml/verbs/start_recording.py new file mode 100644 index 00000000..1b4a36c8 --- /dev/null +++ b/bandwidth/model/bxml/verbs/start_recording.py @@ -0,0 +1,61 @@ +""" +start_recording.py + +Bandwidth's StartRecording BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class StartRecording(TerminalVerb): + + def __init__( + self, recording_available_url: str = None, + recording_available_method: str = None, + transcribe: str = None, transcription_available_url: str = None, + transcription_available_method: str = None, username: str=None, + password: str=None, tag: str=None, + file_format: str = None, multi_channel: str = None + ): + """Initialize a verb + + Args: + recording_available_url (str, optional): URL to send the Recording Available event to once it has been processed. Does not accept BXML. May be a relative URL. Defaults to None. + recording_available_method (str, optional): The HTTP method to use for the request to recordingAvailableUrl. GET or POST. Default value is POST. + transcribe (str, optional): A boolean value to indicate that recording should be transcribed. Transcription can succeed only for recordings of length greater than 500 milliseconds and less than 4 hours. Default is false. Defaults to None. + transcription_available_url (str, optional): URL to send the Transcription Available event to once it has been processed. Does not accept BXML. May be a relative URL. Defaults to None. + transcription_available_method (str, optional): The HTTP method to use for the request to transcriptionAvailableUrl. GET or POST. Default value is POST. Defaults to None. + username (str, optional): The username to send in the HTTP request to recordCompleteUrl, recordingAvailableUrl or transcriptionAvailableUrl. If specified, the URLs must be TLS-encrypted (i.e., https). Defaults to None. + password (str, optional): The password to send in the HTTP request to recordCompleteUrl, recordingAvailableUrl or transcriptionAvailableUrl. If specified, the URLs must be TLS-encrypted (i.e., https). Defaults to None. + tag (str, optional): A custom string that will be sent with this and all future callbacks unless overwritten by a future tag attribute or verb, or cleared. May be cleared by setting tag="". Max length 256 characters. Defaults to None. + file_format (str, optional): The audio format that the recording will be saved as: mp3 or wav. Default value is wav. Defaults to None. max_duration (str, optional): Maximum length of recording (in seconds). Max 10800 (3 hours). Default value is 60. Defaults to None. + multi_channel (str, optional): A boolean value indicating whether or not the recording file should separate each side of the call into its own audio channel. Default value is false. + + """ + self.recording_available_url = recording_available_url + self.recording_available_method = recording_available_method + self.transcribe = transcribe + self.transcription_available_url = transcription_available_url + self.transcription_available_method = transcription_available_method + self.username = username + self.password = password + self.tag = tag + self.file_format = file_format + self.multi_channel = multi_channel + super().__init__(tag="StartRecording") + + @property + def _attributes(self): + return { + "recordingAvailableUrl": self.recording_available_url, + "recordingAvailableMethod": self.recording_available_method, + "transcribe": self.transcribe, + "transcriptionAvailableUrl": self.transcription_available_url, + "transcriptionAvailableMethod": self.transcription_available_method, + "username": self.username, + "password": self.password, + "tag": self.tag, + "fileFormat": self.file_format, + "multiChannel": self.multi_channel + } diff --git a/bandwidth/model/bxml/verbs/start_stream.py b/bandwidth/model/bxml/verbs/start_stream.py new file mode 100644 index 00000000..d44d678b --- /dev/null +++ b/bandwidth/model/bxml/verbs/start_stream.py @@ -0,0 +1,61 @@ +""" +start_stream.py + +Bandwidth's StartStream BXML verb + +@copyright Bandwidth INC +""" +from typing import List + +from ..verb import Verb +from ..verbs.stream_param import StreamParam + + +class StartStream(Verb): + + def __init__( + self, destination: str, stream_params: List[StreamParam] = [], + name: str=None, tracks: str=None, + stream_event_url: str=None, + stream_event_method: str=None, + username: str=None, password: str=None, + ): + """Initialize a verb + + Args: + name (str, optional): A name to refer to this stream by. Used when sending . If not provided, it will default to the generated stream id as sent in the Media Stream Started webhook. + tracks (str, optional): The part of the call to send a stream from. inbound, outbound or both. Default is inbound. + destination (str, optional): A websocket URI to send the stream to. The audio from the specified tracks will be sent via websocket to this URL as base64-encoded PCMU/G711 audio. See below for more details on the websocket packet format. + stream_event_url (str, optional): URL to send the associated Webhook events to during this stream's lifetime. Does not accept BXML. May be a relative URL. + stream_event_method (str, optional): The HTTP method to use for the request to streamEventUrl. GET or POST. Default value is POST. + username (str, optional): The username to send in the HTTP request to streamEventUrl. If specified, the URLs must be TLS-encrypted (i.e., https). + password (str, optional): The password to send in the HTTP request to streamEventUrl. If specified, the URLs must be TLS-encrypted (i.e., https). + + Nested Verbs: + StreamParam: (optional) You may specify up to 12 elements nested within a tag. These elements define optional user specified parameters that will be sent to the destination URL when the stream is first started. + + """ + self.destination = destination + self.stream_params = stream_params + self.name = name + self.tracks = tracks + self.stream_event_url = stream_event_url + self.stream_event_method = stream_event_method + self.username = username + self.password = password + super().__init__( + tag="StartStream", + nested_verbs=self.stream_params + ) + + @property + def _attributes(self): + return { + "destination": self.destination, + "name": self.name, + "tracks": self.tracks, + "streamEventUrl": self.stream_event_url, + "streamEventMethod": self.stream_event_method, + "username": self.username, + "password": self.password, + } diff --git a/bandwidth/model/bxml/verbs/stop_gather.py b/bandwidth/model/bxml/verbs/stop_gather.py new file mode 100644 index 00000000..73b6b8a3 --- /dev/null +++ b/bandwidth/model/bxml/verbs/stop_gather.py @@ -0,0 +1,16 @@ +""" +stop_gather.py + +Bandwidth's StopGather BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class StopGather(TerminalVerb): + + def __init__(self): + """Initialize a verb + """ + super().__init__(tag="StopGather", content=None) diff --git a/bandwidth/model/bxml/verbs/stop_recording.py b/bandwidth/model/bxml/verbs/stop_recording.py new file mode 100644 index 00000000..651f9caa --- /dev/null +++ b/bandwidth/model/bxml/verbs/stop_recording.py @@ -0,0 +1,19 @@ +""" +record.py + +Bandwidth's StopRecording BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class StopRecording(TerminalVerb): + + def __init__(self): + """Initialize a verb + + Args: There are no args or text content for StopRecording + """ + + super().__init__(tag="StopRecording") diff --git a/bandwidth/model/bxml/verbs/stop_stream.py b/bandwidth/model/bxml/verbs/stop_stream.py new file mode 100644 index 00000000..87f7f596 --- /dev/null +++ b/bandwidth/model/bxml/verbs/stop_stream.py @@ -0,0 +1,30 @@ +""" +stop_stream.py + +Bandwidth's StopStream BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class StopStream(TerminalVerb): + + def __init__( + self, name: str + ): + """Initialize a verb + + Args: + name (str): The name of the stream to stop. This is either the user selected name when sending the verb, or the system generated name returned in the Media Stream Started webhook if was sent with no name attribute. + """ + self.name = name + super().__init__( + tag="StopStream", + ) + + @property + def _attributes(self): + return { + "name": self.name, + } diff --git a/bandwidth/model/bxml/verbs/stream_param.py b/bandwidth/model/bxml/verbs/stream_param.py new file mode 100644 index 00000000..dbd4516d --- /dev/null +++ b/bandwidth/model/bxml/verbs/stream_param.py @@ -0,0 +1,33 @@ +""" +stream_param.py + +Bandwidth's StreamParam BXML verb + +@copyright Bandwidth INC +""" +from ..terminal_verb import TerminalVerb + + +class StreamParam(TerminalVerb): + + def __init__( + self, name: str, value: str + ): + """Initialize a verb + + Args: + name (str): The name of this parameter, up to 256 characters. + value (str): The value of this parameter, up to 2048 characters. + """ + self.name = name + self.value = value + super().__init__( + tag="StreamParam" + ) + + @property + def _attributes(self): + return { + "name": self.name, + "value": self.value, + } diff --git a/bandwidth/model/bxml/verbs/transfer.py b/bandwidth/model/bxml/verbs/transfer.py index a366ecb6..dae7e88c 100644 --- a/bandwidth/model/bxml/verbs/transfer.py +++ b/bandwidth/model/bxml/verbs/transfer.py @@ -77,7 +77,6 @@ def __init__( self.diversion_reason = diversion_reason super().__init__( tag="Transfer", - content=None, nested_verbs=self.transfer_to ) diff --git a/test/unit/bxml/test_conference.py b/test/unit/bxml/test_conference.py new file mode 100644 index 00000000..b94e0442 --- /dev/null +++ b/test/unit/bxml/test_conference.py @@ -0,0 +1,66 @@ +""" +test_conference.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs import * + +class TestGather(unittest.TestCase): + + def setUp(self): + self.play_audio = PlayAudio( + audio_uri="https://audio.url/audio1.wav" + ) + + self.speak_sentence = SpeakSentence( + text='Hello there.' + ) + self.start_recording = StartRecording( + recording_available_url = "example.com", + recording_available_method = "POST", + username = "user", + password = "pass", + tag = "tag", + file_format = "wav", + multi_channel = "true" + ) + + self.conference = Conference( + name="conf1", + mute = "true", + hold = "false", + call_ids_to_coach = "example-call-id", + conference_event_url = "example.com/eventurl", + conference_event_method = "POST", + conference_event_fallback_url = "backupexample.com/eventurl", + conference_event_fallback_method = "POST", + username = "user", + password = "pass", + fallback_username = "user", + fallback_password = "pass", + tag = "tag", + callback_timeout = "5", + audio_and_recording_verbs=[self.play_audio, self.start_recording] + ) + + def test_to_bxml(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = 'conf1https://audio.url/audio1.wav' + else: + expected = 'conf1https://audio.url/audio1.wav' + assert(expected == self.conference.to_bxml()) + + def test_add_verb(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = 'conf1https://audio.url/audio1.wavHello there.' + else: + expected = 'conf1https://audio.url/audio1.wavHello there.' + self.conference.add_verb(self.speak_sentence) + assert(expected == self.conference.to_bxml()) diff --git a/test/unit/bxml/test_forward.py b/test/unit/bxml/test_forward.py new file mode 100644 index 00000000..f24e9f4a --- /dev/null +++ b/test/unit/bxml/test_forward.py @@ -0,0 +1,38 @@ +""" +test_forward.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.forward import Forward + +class TestForward(unittest.TestCase): + + def setUp(self): + self.forward = Forward( + to="19195554321", + _from="19195554322", + call_timeout = "15", + diversion_treatment="propagate", + diversion_reason="away", + uui="93d6f3c0be5845960b744fa28015d8ede84bd1a4;encoding=base64,asdf;encoding=jwt" + ) + self.test_verb = Verb(tag="test") + + + def test_to_bxml(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = '' + else: + expected = '' + assert(expected == self.forward.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.forward.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_gather.py b/test/unit/bxml/test_gather.py new file mode 100644 index 00000000..27e3f3ba --- /dev/null +++ b/test/unit/bxml/test_gather.py @@ -0,0 +1,59 @@ +""" +test_gather.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs import PlayAudio,SpeakSentence,Gather + +class TestGather(unittest.TestCase): + + def setUp(self): + self.play_audio = PlayAudio( + audio_uri="https://audio.url/audio1.wav", + username="user", + password="pass" + ) + + self.speak_sentence = SpeakSentence( + text='Hello. Your number is asdf, lets play a game. What is 10 + 3. Press the pound key when finished.' + ) + + self.gather = Gather( + gather_url="test.com", + gather_method="POST", + gather_fallback_url= "fallback-test.com", + gather_fallback_method="GET", + username="user", + password="pass", + fallback_username="user", + fallback_password="pass", + tag = "tag", + terminating_digits = "2", + max_digits = "5", + inter_digit_timeout = "1", + first_digit_timeout = "3", + repeat_count = "2", + audio_verbs=[self.play_audio] + ) + + def test_to_bxml(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = 'https://audio.url/audio1.wav' + else: + expected = 'https://audio.url/audio1.wav' + assert(expected == self.gather.to_bxml()) + + def test_add_verb(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = 'https://audio.url/audio1.wavHello. Your number is <say-as interpret-as="telephone">asdf</say-as>, lets play a game. What is 10 + 3. Press the pound key when finished.' + else: + expected = 'https://audio.url/audio1.wavHello. Your number is <say-as interpret-as="telephone">asdf</say-as>, lets play a game. What is 10 + 3. Press the pound key when finished.' + self.gather.add_verb(self.speak_sentence) + assert(expected == self.gather.to_bxml()) diff --git a/test/unit/bxml/test_hangup.py b/test/unit/bxml/test_hangup.py new file mode 100644 index 00000000..2d847260 --- /dev/null +++ b/test/unit/bxml/test_hangup.py @@ -0,0 +1,28 @@ +""" +test_hangup.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.hangup import Hangup + + +class TestHangup(unittest.TestCase): + + def setUp(self): + self.hangup = Hangup() + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + expected = '' + assert(expected == self.hangup.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.hangup.add_verb(self.test_verb) + diff --git a/test/unit/bxml/test_pause.py b/test/unit/bxml/test_pause.py new file mode 100644 index 00000000..8376e2ff --- /dev/null +++ b/test/unit/bxml/test_pause.py @@ -0,0 +1,25 @@ +""" +test_Pause.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import pytest +import unittest +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.pause import Pause + +class TestPause(unittest.TestCase): + + def setUp(self): + self.pause = Pause(duration="30") + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + expected = '' + assert(expected == self.pause.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.pause.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_play_audio.py b/test/unit/bxml/test_play_audio.py new file mode 100644 index 00000000..7077f44e --- /dev/null +++ b/test/unit/bxml/test_play_audio.py @@ -0,0 +1,35 @@ +""" +test_play_audio.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs import PlayAudio + +class TestPlayAudio(unittest.TestCase): + + def setUp(self): + self.play_audio = PlayAudio( + audio_uri="https://audio.url/audio1.wav", + username="user", + password="pass" + ) + self.test_verb = Verb(tag="test") + + + def test_to_bxml(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = 'https://audio.url/audio1.wav' + else: + expected = 'https://audio.url/audio1.wav' + assert(expected == self.play_audio.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.play_audio.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_resume_recording.py b/test/unit/bxml/test_resume_recording.py new file mode 100644 index 00000000..ef8eb260 --- /dev/null +++ b/test/unit/bxml/test_resume_recording.py @@ -0,0 +1,27 @@ +""" +test_resume_recording.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.resume_recording import ResumeRecording + + +class TestTag(unittest.TestCase): + + def setUp(self): + self.resume_recording = ResumeRecording() + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + expected = '' + assert(expected == self.resume_recording.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.resume_recording.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_ring.py b/test/unit/bxml/test_ring.py new file mode 100644 index 00000000..2ce75767 --- /dev/null +++ b/test/unit/bxml/test_ring.py @@ -0,0 +1,35 @@ +""" +test_ring.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.ring import Ring + + +class TestRing(unittest.TestCase): + + def setUp(self): + self.ring = Ring( + duration="30", + answer_call="true", + ) + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = '' + else: + expected = '' + + assert(expected == self.ring.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.ring.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_speak_sentence.py b/test/unit/bxml/test_speak_sentence.py new file mode 100644 index 00000000..c152b667 --- /dev/null +++ b/test/unit/bxml/test_speak_sentence.py @@ -0,0 +1,31 @@ +""" +test_speak_sentence.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs import SpeakSentence + +class TestSpeakSentence(unittest.TestCase): + + def setUp(self): + self.speak_sentence = SpeakSentence( + text='Hello. Your number is asdf, lets play a game. What is 10 + 3. Press the pound key when finished.', + voice="julie" + ) + + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + expected = 'Hello. Your number is <say-as interpret-as="telephone">asdf</say-as>, lets play a game. What is 10 + 3. Press the pound key when finished.' + assert(expected == self.speak_sentence.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.speak_sentence.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_start_gather.py b/test/unit/bxml/test_start_gather.py new file mode 100644 index 00000000..7600c3ad --- /dev/null +++ b/test/unit/bxml/test_start_gather.py @@ -0,0 +1,38 @@ +""" +test_start_gather.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.start_gather import StartGather + + +class TestPhoneNumber(unittest.TestCase): + + def setUp(self): + self.start_gather = StartGather( + dtmf_url="https://example.com/startgather", + dtmf_method="POST", + username="user", + password="pass", + tag="tag" + ) + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = '' + else: + expected = '' + + assert(expected == self.start_gather.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.start_gather.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_start_recording.py b/test/unit/bxml/test_start_recording.py new file mode 100644 index 00000000..d1b40c91 --- /dev/null +++ b/test/unit/bxml/test_start_recording.py @@ -0,0 +1,45 @@ +""" +test_start_recording.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.start_recording import StartRecording + + +class TestRecord(unittest.TestCase): + + def setUp(self): + self.start_recording = StartRecording( + recording_available_url = "example.com", + recording_available_method = "POST", + transcribe = "true", + transcription_available_url = "transcription-example.com", + transcription_available_method = "POST", + username = "user", + password = "pass", + tag = "tag", + file_format = "wav", + multi_channel = "true" + ) + self.test_verb = Verb(tag="test") + + + def test_to_bxml(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = '' + else: + expected = '' + + assert(expected == self.start_recording.to_bxml()) + + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.start_recording.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_start_stream.py b/test/unit/bxml/test_start_stream.py new file mode 100644 index 00000000..912832d4 --- /dev/null +++ b/test/unit/bxml/test_start_stream.py @@ -0,0 +1,51 @@ +""" +test_start_stream.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + +from bandwidth.model.bxml.verbs import StartStream, StreamParam + +class TestStartStream(unittest.TestCase): + + def setUp(self): + self.stream_param1 = StreamParam( + name="name1", + value="value1" + ) + + self.stream_param2 = StreamParam( + name="name2", + value="value2" + ) + + self.start_stream = StartStream( + stream_params=[self.stream_param1], + name = "stream1", + tracks = "inbound", + destination = "testurl.com", + stream_event_url="eventurl.com", + stream_event_method= "POST", + username = "user", + password = "pass" + ) + + def test_to_bxml(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = '' + else: + expected = '' + assert(expected == self.start_stream.to_bxml()) + + def test_add_verb(self): + if os.environ['PYTHON_VERSION'] == '3.7': + expected = '' + else: + expected = '' + self.start_stream.add_verb(self.stream_param2) + assert(expected == self.start_stream.to_bxml()) diff --git a/test/unit/bxml/test_stop_gather.py b/test/unit/bxml/test_stop_gather.py new file mode 100644 index 00000000..64578c2d --- /dev/null +++ b/test/unit/bxml/test_stop_gather.py @@ -0,0 +1,28 @@ +""" +test_stop_gather.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.stop_gather import StopGather + + +class TestTag(unittest.TestCase): + + def setUp(self): + self.stop_gather = StopGather() + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + expected = '' + assert(expected == self.stop_gather.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.stop_gather.add_verb(self.test_verb) + diff --git a/test/unit/bxml/test_stop_recording.py b/test/unit/bxml/test_stop_recording.py new file mode 100644 index 00000000..c07ec531 --- /dev/null +++ b/test/unit/bxml/test_stop_recording.py @@ -0,0 +1,27 @@ +""" +test_stop_recording.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.stop_recording import StopRecording + + +class TestTag(unittest.TestCase): + + def setUp(self): + self.stop_recording = StopRecording() + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + expected = '' + assert(expected == self.stop_recording.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.stop_recording.add_verb(self.test_verb) diff --git a/test/unit/bxml/test_stop_stream.py b/test/unit/bxml/test_stop_stream.py new file mode 100644 index 00000000..b5dae299 --- /dev/null +++ b/test/unit/bxml/test_stop_stream.py @@ -0,0 +1,28 @@ +""" +test_stop_stream.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import pytest +import unittest + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs.stop_stream import StopStream + + +class TestTag(unittest.TestCase): + + def setUp(self): + self.stop_stream = StopStream(name="conf") + self.test_verb = Verb(tag="test") + + def test_to_bxml(self): + expected = '' + assert(expected == self.stop_stream.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.stop_stream.add_verb(self.test_verb) + diff --git a/test/unit/bxml/test_stream_param.py b/test/unit/bxml/test_stream_param.py new file mode 100644 index 00000000..de4a8dfd --- /dev/null +++ b/test/unit/bxml/test_stream_param.py @@ -0,0 +1,32 @@ +""" +test_stream_param.py + +Unit tests for the BXML verb + +@copyright Bandwidth Inc. +""" +import os +import pytest +import unittest + + +from bandwidth.model.bxml.verb import Verb +from bandwidth.model.bxml.verbs import StreamParam + +class TestStreamParam(unittest.TestCase): + + def setUp(self): + self.stream_param = StreamParam( + name="name1", + value="value1" + ) + self.test_verb = Verb(tag="test") + + + def test_to_bxml(self): + expected = '' + assert(expected == self.stream_param.to_bxml()) + + def test_add_verb(self): + with pytest.raises(AttributeError): + self.stream_param.add_verb(self.test_verb)