├── .github
└── workflows
│ └── unitTests.yml
├── .gitignore
├── AUTHORS.md
├── CHANGELOG.md
├── Dockerfile
├── Jenkinsfile
├── LICENSE.txt
├── MANIFEST.in
├── Makefile
├── README.md
├── ci
└── config.yml
├── docker-compose.yml
├── examples
└── JWT.py
├── package.sh
├── plivo
├── __init__.py
├── base.py
├── exceptions.py
├── resources
│ ├── __init__.py
│ ├── accounts.py
│ ├── addresses.py
│ ├── applications.py
│ ├── brand.py
│ ├── call_feedback.py
│ ├── calls.py
│ ├── campaign.py
│ ├── conferences.py
│ ├── endpoints.py
│ ├── identities.py
│ ├── live_calls.py
│ ├── lookup.py
│ ├── maskingsession.py
│ ├── media.py
│ ├── messages.py
│ ├── multipartycall.py
│ ├── nodes.py
│ ├── numberpools.py
│ ├── numbers.py
│ ├── phlos.py
│ ├── powerpacks.py
│ ├── pricings.py
│ ├── profile.py
│ ├── queued_calls.py
│ ├── recordings.py
│ ├── regulatory_compliance.py
│ ├── token.py
│ ├── tollfree_verification.py
│ ├── transcription.py
│ ├── verify.py
│ └── verify_callerid.py
├── rest
│ ├── .DS_Store
│ ├── __init__.py
│ ├── base_client.py
│ ├── client.py
│ ├── phlo.py
│ └── phlo_client.py
├── utils
│ ├── __init__.py
│ ├── interactive.py
│ ├── jwt.py
│ ├── location.py
│ ├── signature_v3.py
│ ├── template.py
│ └── validators.py
├── version.py
└── xml
│ ├── ConferenceElement.py
│ ├── DTMFElement.py
│ ├── DialElement.py
│ ├── MultiPartyCallElement.py
│ ├── PlivoXMLElement.py
│ ├── ResponseElement.py
│ ├── __init__.py
│ ├── breakElement.py
│ ├── contElement.py
│ ├── emphasisElement.py
│ ├── getDigitsElement.py
│ ├── getInputElement.py
│ ├── hangupElement.py
│ ├── langElement.py
│ ├── messageElement.py
│ ├── numberElement.py
│ ├── pElement.py
│ ├── phonemeElement.py
│ ├── playElement.py
│ ├── preAnswerElement.py
│ ├── prosodyElement.py
│ ├── recordElement.py
│ ├── redirectElement.py
│ ├── sElement.py
│ ├── sayAsElement.py
│ ├── speakElement.py
│ ├── streamElement.py
│ ├── subElement.py
│ ├── userElement.py
│ ├── wElement.py
│ ├── waitElement.py
│ └── xmlUtils.py
├── requirements.txt
├── setup.cfg
├── setup.py
├── setup_sdk.sh
├── tests
├── __init__.py
├── base.py
├── decorators.py
├── resources
│ ├── __init__.py
│ ├── fixtures
│ │ ├── accountGetResponse.json
│ │ ├── accountUpdateResponse.json
│ │ ├── addressCreateResponse.json
│ │ ├── addressGetResponse.json
│ │ ├── addressListResponse.json
│ │ ├── addressUpdateResponse.json
│ │ ├── applicationCreateResponse.json
│ │ ├── applicationGetResponse.json
│ │ ├── applicationListResponse.json
│ │ ├── applicationModifyResponse.json
│ │ ├── brandCreateResponse.json
│ │ ├── brandDeleteResponse.json
│ │ ├── brandGetResponse.json
│ │ ├── brandGetUsecasesResponse.json
│ │ ├── brandListResponse.json
│ │ ├── callCreateResponse.json
│ │ ├── callGetResponse.json
│ │ ├── callListResponse.json
│ │ ├── callUpdateResponse.json
│ │ ├── campaignCreateResponse.json
│ │ ├── campaignDeleteResponse.json
│ │ ├── campaignGetNumberResponse.json
│ │ ├── campaignGetNumbersResponse.json
│ │ ├── campaignGetResponse.json
│ │ ├── campaignImportResponse.json
│ │ ├── campaignListResponse.json
│ │ ├── campaignNumberLinkResponse.json
│ │ ├── campaignNumberUnlinkResponse.json
│ │ ├── campaignUpdateResponse.json
│ │ ├── conferenceDeleteAllResponse.json
│ │ ├── conferenceDeleteResponse.json
│ │ ├── conferenceGetResponse.json
│ │ ├── conferenceListResponse.json
│ │ ├── conferenceMemberDeafCreateResponse.json
│ │ ├── conferenceMemberDeleteResponse.json
│ │ ├── conferenceMemberKickCreateResponse.json
│ │ ├── conferenceMemberMuteCreateResponse.json
│ │ ├── conferenceMemberPlayCreateResponse.json
│ │ ├── conferenceMemberPlayDeleteResponse.json
│ │ ├── conferenceMemberSpeakCreateResponse.json
│ │ ├── conferenceMemberSpeakDeleteResponse.json
│ │ ├── conferenceRecordCreateResponse.json
│ │ ├── endpointCreateResponse.json
│ │ ├── endpointGetResponse.json
│ │ ├── endpointListResponse.json
│ │ ├── endpointUpdateResponse.json
│ │ ├── identityCreateResponse.json
│ │ ├── identityGetResponse.json
│ │ ├── identityListResponse.json
│ │ ├── identityUpdateResponse.json
│ │ ├── liveCallDtmfCreateResponse.json
│ │ ├── liveCallGetResponse.json
│ │ ├── liveCallListGetResponse.json
│ │ ├── liveCallPlayCreateResponse.json
│ │ ├── liveCallRecordCreateResponse.json
│ │ ├── liveCallSpeakCreateResponse.json
│ │ ├── liveCallSpeakDeleteResponse.json
│ │ ├── liveCallStreamCreateResponse.json
│ │ ├── liveCallStreamDeleteAllResponse.json
│ │ ├── liveCallStreamGetAllResponse.json
│ │ ├── lookupGetResponse.json
│ │ ├── maskingSessionCreateResponse.json
│ │ ├── maskingSessionDeleteResponse.json
│ │ ├── maskingSessionGetResponse.json
│ │ ├── maskingSessionListResponse.json
│ │ ├── maskingSessionUpdateResponse.json
│ │ ├── mediaGetMediaResponse.json
│ │ ├── mediaListResponse.json
│ │ ├── messageGetResponse.json
│ │ ├── messageListMediaResponse.json
│ │ ├── messageListResponse.json
│ │ ├── messageSendResponse.json
│ │ ├── multiPartyCallsAddParticipantResponse.json
│ │ ├── multiPartyCallsEndMpcResponse.json
│ │ ├── multiPartyCallsGetParticipantResponse.json
│ │ ├── multiPartyCallsKickMpcParticipantResponse.json
│ │ ├── multiPartyCallsListMpcResponse.json
│ │ ├── multiPartyCallsStartMpcResponse.json
│ │ ├── multiPartyCallsStartParticipantRecordingResponse.json
│ │ ├── multiPartyCallsStartPlayAudioResponse.json
│ │ ├── multiPartyCallsStartRecordingResponse.json
│ │ ├── multiPartyCallsUpdateMpcParticipantResponse.json
│ │ ├── numberCreateResponse.json
│ │ ├── numberGetResponse.json
│ │ ├── numberListResponse.json
│ │ ├── numberUpdateResponse.json
│ │ ├── numberpoolListResponse.json
│ │ ├── numberpoolResponse.json
│ │ ├── phlosMemberMemberActionsResponse.json
│ │ ├── phlosMemberMemberActionsValidationResponse.json
│ │ ├── phlosMemberPhloGetResponse.json
│ │ ├── phlosMemberPhloGetValidationResponse.json
│ │ ├── phoneNumberCreateResponse.json
│ │ ├── phoneNumberListResponse.json
│ │ ├── powerpackAddNumberResponse.json
│ │ ├── powerpackAddTollfreeResponse.json
│ │ ├── powerpackBuyAndNumberResponse.json
│ │ ├── powerpackCountNumbersResponse.json
│ │ ├── powerpackCreatePowerpackResponse.json
│ │ ├── powerpackDeletePowerpackResponse.json
│ │ ├── powerpackDeleteResponse.json
│ │ ├── powerpackFindShortcodeResponse.json
│ │ ├── powerpackFindTollfreeResponse.json
│ │ ├── powerpackGetPowerpackResponse.json
│ │ ├── powerpackListNumbersResponse.json
│ │ ├── powerpackListPowerpackResponse.json
│ │ ├── powerpackListResponse.json
│ │ ├── powerpackListShortcodeResponse.json
│ │ ├── powerpackListTollfreeResponse.json
│ │ ├── powerpackRemoveNumberResponse.json
│ │ ├── powerpackRemoveShortcodeResponse.json
│ │ ├── powerpackRemoveTollfreeResponse.json
│ │ ├── powerpackResponse.json
│ │ ├── powerpackUpdatePowerpackResponse.json
│ │ ├── pricingGetResponse.json
│ │ ├── profileCreateResponse.json
│ │ ├── profileGetResponse.json
│ │ ├── profileListResponse.json
│ │ ├── profileUpdateResponse.json
│ │ ├── recordingGetAddedFilterResponse.json
│ │ ├── recordingGetResponse.json
│ │ ├── recordingListFromFilterResponse.json
│ │ ├── recordingListResponse.json
│ │ ├── sessionGetResponse.json
│ │ ├── sessionListResponse.json
│ │ ├── shortcodeListResponse.json
│ │ ├── shortcodeResponse.json
│ │ ├── subaccountCreateResponse.json
│ │ ├── subaccountGetResponse.json
│ │ ├── subaccountListResponse.json
│ │ ├── subaccountUpdateResponse.json
│ │ ├── tokenCreateResponse.json
│ │ ├── tollfreeVerificationCreateResponse.json
│ │ ├── tollfreeVerificationGetResponse.json
│ │ ├── tollfreeVerificationListResponse.json
│ │ ├── tollfreeVerificationUpdateResponse.json
│ │ ├── transcriptionCreateResponse.json
│ │ ├── transcriptionDeleteResponse.json
│ │ ├── transcriptionGetResponse.json
│ │ ├── verifyCalleridGetResponse.json
│ │ ├── verifyCalleridInitiateResponse.json
│ │ ├── verifyCalleridListResponse.json
│ │ ├── verifyCalleridUpdateResponse.json
│ │ └── verifyCalleridVerifyResponse.json
│ ├── test_accounts.py
│ ├── test_addresses.py
│ ├── test_applications.py
│ ├── test_brand.py
│ ├── test_calls.py
│ ├── test_campaign.py
│ ├── test_client.py
│ ├── test_conferences.py
│ ├── test_endpoints.py
│ ├── test_identities.py
│ ├── test_jwt.py
│ ├── test_lookup.py
│ ├── test_maskingsessions.py
│ ├── test_medias.py
│ ├── test_members.py
│ ├── test_messages.py
│ ├── test_multipartycalls.py
│ ├── test_numbers.py
│ ├── test_phlos.py
│ ├── test_powerpacks.py
│ ├── test_pricings.py
│ ├── test_profile.py
│ ├── test_recordings.py
│ ├── test_signature.py
│ ├── test_subaccounts.py
│ ├── test_token.py
│ ├── test_tollfree_verification.py
│ ├── test_transcriptions.py
│ ├── test_verify.py
│ └── test_verifycallerids.py
└── xml
│ ├── __init__.py
│ ├── test_MultiPartyCallElement.py
│ ├── test_breakElement.py
│ ├── test_conferenceElement.py
│ ├── test_contElement.py
│ ├── test_emphasisElement.py
│ ├── test_getDigitsElement.py
│ ├── test_getInputElement.py
│ ├── test_hangupElement.py
│ ├── test_langElement.py
│ ├── test_messageElement.py
│ ├── test_numberElement.py
│ ├── test_pElement.py
│ ├── test_phonemeElement.py
│ ├── test_playElement.py
│ ├── test_preAnswerElement.py
│ ├── test_prosodyElement.py
│ ├── test_recordElement.py
│ ├── test_redirectElement.py
│ ├── test_responseElement.py
│ ├── test_sElement.py
│ ├── test_sayAsElement.py
│ ├── test_speakElement.py
│ ├── test_streamElement.py
│ ├── test_subElement.py
│ ├── test_userElement.py
│ ├── test_wElement.py
│ └── test_waitElement.py
└── tox.ini
/.github/workflows/unitTests.yml:
--------------------------------------------------------------------------------
1 | name: UnitTests
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 | name: UnitTests
12 | strategy:
13 | matrix:
14 | python-version: [ 3.8, 3.9, 3.11]
15 | os: [macos-latest]
16 | runs-on: ${{ matrix.os }}
17 |
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 | - name: Set up Python ${{ matrix.python-version }}
22 | uses: actions/setup-python@v2
23 | with:
24 | python-version: ${{ matrix.python-version }}
25 | - name: Display Python version
26 | run: python -c "import sys; print(sys.version)"
27 | - name: Dependencies Installation
28 | run: |
29 | pip install tox
30 | - name: Run Tests
31 | run: |
32 | python --version
33 | tox -e py
34 |
35 | coverage:
36 | runs-on: ubuntu-latest
37 | strategy:
38 | matrix:
39 | python-version: [3.11]
40 | steps:
41 | - uses: actions/checkout@v2
42 | - name: Set up Python ${{ matrix.python-version }}
43 | uses: actions/setup-python@v2
44 | with:
45 | python-version: ${{ matrix.python-version }}
46 | - name: Display Python version
47 | run: python -c "import sys; print(sys.version)"
48 | - name: Dependencies Installation
49 | run: |
50 | pip install tox
51 | pip install coverage
52 | - name: Run Tests
53 | run: |
54 | python --version
55 | tox -e py
56 | - name: Upload coverage to Codecov
57 | uses: codecov/codecov-action@v1
58 | with:
59 | flags: unittests
60 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .coverage
2 | build/
3 | cover/
4 | dist/
5 | *.egg-info/
6 | .idea/
7 | *.pyc
8 | *.pyo
9 | ./tests/htmlcov/
10 | .tox/
11 | venv*/
12 | python-sdk-test/
--------------------------------------------------------------------------------
/AUTHORS.md:
--------------------------------------------------------------------------------
1 | # Authors
2 | - [Sreyantha Chary](https://sreyanth.com?ref=github/plivo-python) ([@sreyanth](https://github.com/sreyanth))
3 | - [Aviral Dasgupta](http://www.aviraldg.com) ([@aviraldg](http://github.com/aviraldg))
4 | - [Abhishek](https://github.com/Abhishek-plivo)
5 | - [Dalibor Dukic](https://github.com/kicdu)
6 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.7-alpine
2 |
3 | WORKDIR /usr/src/app
4 | RUN apk update && apk add git vim bash wget make && apk add --update --no-cache g++ gcc libxslt-dev
5 |
6 | # Copy setup script
7 | COPY setup_sdk.sh /usr/src/app
8 | RUN chmod a+x /usr/src/app/setup_sdk.sh
9 |
10 | ENTRYPOINT [ "/usr/src/app/setup_sdk.sh" ]
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | #!groovy
2 |
3 | @Library('plivo_standard_libs@sdks') _
4 |
5 | sdksPipeline ([
6 | buildContainer: 'plivo/jenkins-ci/python-sdk:python-sdk-update'
7 | ])
8 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) 2018, Plivo Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | # Include the license file
2 | include LICENSE.txt
3 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build test run
2 |
3 | build:
4 | docker-compose up --build --remove-orphans
5 |
6 | start:
7 | docker-compose up --build --remove-orphans --detach
8 | # Wait for the container to be running before attaching
9 | @while [ -z "$$(docker-compose ps -q pythonSDK)" ]; do \
10 | sleep 1; \
11 | done
12 | docker attach $$(docker-compose ps -q pythonSDK)
13 |
14 | test:
15 | @[ "${CONTAINER}" ] && \
16 | (docker exec -it $$CONTAINER /bin/bash -c "tox -e py") || \
17 | (tox -e py)
18 |
19 | run:
20 | @[ "${CONTAINER}" ] && \
21 | (docker exec -it $$CONTAINER /bin/bash -c "cd /usr/src/app/python-sdk-test/ && python test.py") || \
22 | (cd /usr/src/app/python-sdk-test/ && python test.py)
--------------------------------------------------------------------------------
/ci/config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | parent: central
3 | serviceName: plivo-python
4 | language: python-sdk
5 | build:
6 | command: |
7 | ./package.sh
8 | postDeployJobs:
9 | prod:
10 | - name: plivo/messaging-qa/pythonSDKSmoke
11 | disabled: false
12 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 |
5 | pythonSDK:
6 | build:
7 | context: .
8 | image: pythonsdk
9 | container_name: pythonSDK
10 | environment:
11 | - PLIVO_AUTH_ID=${PLIVO_AUTH_ID}
12 | - PLIVO_AUTH_TOKEN=${PLIVO_AUTH_TOKEN}
13 | - PLIVO_API_DEV_HOST=${PLIVO_API_DEV_HOST}
14 | - PLIVO_API_PROD_HOST=${PLIVO_API_PROD_HOST}
15 | volumes:
16 | - .:/usr/src/app
17 | stdin_open: true
18 | tty: true
--------------------------------------------------------------------------------
/examples/JWT.py:
--------------------------------------------------------------------------------
1 | from plivo.utils import jwt
2 | import time
3 |
4 | # using valid_from in epoch and lifetime in seconds
5 | token = jwt.AccessToken('{authId}', '{authToken}', '{endpointUsername}', valid_from=time.time(), lifetime=300, uid='{uid}')
6 | # grants(incoming:bool, outgoing:bool)
7 | token.add_voice_grants(True, True)
8 | print(token.to_jwt())
9 |
10 |
11 | # using valid_from and valid_till in epoch
12 | token = jwt.AccessToken('{authId}', '{authToken}', '{endpointUsername}', valid_from=time.time(), valid_till=1588751222)
13 | token.add_voice_grants(False, True)
14 | print(token.to_jwt())
15 |
--------------------------------------------------------------------------------
/package.sh:
--------------------------------------------------------------------------------
1 | rm -r dist/
2 | python setup.py sdist
3 | python setup.py bdist_wheel
4 |
--------------------------------------------------------------------------------
/plivo/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from . import exceptions
3 | from .rest import Client as RestClient
4 | from .rest import phlo
5 | from . import xml as plivoxml
6 |
--------------------------------------------------------------------------------
/plivo/exceptions.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | class PlivoRestError(Exception):
3 | pass
4 |
5 |
6 | class AuthenticationError(PlivoRestError):
7 | pass
8 |
9 |
10 | class InvalidRequestError(PlivoRestError):
11 | pass
12 |
13 |
14 | class PlivoServerError(PlivoRestError):
15 | pass
16 |
17 |
18 | class PlivoXMLError(PlivoRestError):
19 | pass
20 |
21 |
22 | class ResourceNotFoundError(PlivoRestError):
23 | pass
24 |
25 |
26 | class ValidationError(PlivoRestError):
27 | pass
28 |
29 |
30 | class ForbiddenError(PlivoRestError):
31 | pass
32 |
33 | class GeoPermissionError(PlivoRestError):
34 | pass
35 |
--------------------------------------------------------------------------------
/plivo/resources/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from .accounts import Accounts, Subaccounts
3 | from .applications import Applications
4 | from .calls import Calls
5 | from .token import Token
6 | from .conferences import Conferences
7 | from .endpoints import Endpoints
8 | from .messages import Messages
9 | from .numbers import Numbers
10 | from .phlos import Phlos
11 | from .pricings import Pricings
12 | from .recordings import Recordings
13 | from .addresses import Addresses
14 | from .media import Media
15 | from .identities import Identities
16 | from .call_feedback import CallFeedback
17 | from .powerpacks import Powerpacks
18 | from .lookup import Lookup
19 | from .brand import Brand
20 | from .campaign import Campaign
21 | from .profile import Profile
22 | from .multipartycall import MultiPartyCalls, MultiPartyCall, MultiPartyCallParticipant
23 | from .verify import Sessions
24 | from .tollfree_verification import TollfreeVerifications
25 |
--------------------------------------------------------------------------------
/plivo/resources/brand.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from plivo.utils.validators import *
3 |
4 | from ..base import ListResponseObject, PlivoResource, PlivoResourceInterface
5 | from ..exceptions import *
6 | from ..utils import *
7 |
8 | class Brand(PlivoResource):
9 | _name = 'Brand'
10 | _identifier_string = 'brand_id'
11 |
12 | class Brand(PlivoResourceInterface):
13 | _resource_type = Brand
14 |
15 | @validate_args(brand_id=[of_type(six.text_type)])
16 | def get(self, brand_id):
17 | return self.client.request(
18 | 'GET', ('10dlc','Brand', brand_id), response_type=None)
19 |
20 | @validate_args(
21 | type=[optional(of_type(six.text_type))],
22 | status=[optional(of_type(six.text_type))],
23 | limit=[optional(of_type(*six.integer_types))],
24 | offset=[
25 | optional(
26 | all_of(
27 | of_type(*six.integer_types),
28 | check(lambda offset: 0 <= offset, '0 <= offset')))
29 | ])
30 | def list(self, type=None, status=None,
31 | limit=None, offset=None):
32 | return self.client.request(
33 | 'GET', ('10dlc', 'Brand', ),
34 | to_param_dict(self.list, locals()),
35 | response_type=None,
36 | objects_type=None)
37 |
38 | @validate_args(
39 | brand_alias=[required(of_type(six.text_type))],
40 | brand_type=[optional(of_type(six.text_type), is_in(('STANDARD','STARTER')))],
41 | profile_uuid=[required(of_type(six.text_type))],
42 | secondary_vetting=[optional(of_type_exact(bool))],
43 | url=[optional(of_type(six.text_type))],
44 | method=[optional(of_type(six.text_type))])
45 | def create(self,
46 | brand_alias,
47 | brand_type,
48 | profile_uuid,
49 | secondary_vetting=False,
50 | url='',
51 | method='POST'
52 | ):
53 | return self.client.request('POST', ('10dlc', 'Brand'),
54 | to_param_dict(self.create, locals()))
55 |
56 |
57 | @validate_args(brand_id=[required(of_type(six.text_type))])
58 | def get_usecases(self, brand_id):
59 | return self.client.request(
60 | 'GET', ('10dlc','Brand', brand_id, 'usecases'), response_type=None)
61 |
62 | @validate_args(brand_id=[required(of_type(six.text_type))])
63 | def delete(self, brand_id):
64 | return self.client.request(
65 | 'DELETE', ('10dlc','Brand', brand_id), response_type=None)
66 |
--------------------------------------------------------------------------------
/plivo/resources/call_feedback.py:
--------------------------------------------------------------------------------
1 | from ..base import PlivoResourceInterface
2 | from requests import Request
3 | from plivo.exceptions import ValidationError
4 |
5 |
6 | FEEDBACK_API_PATH = "v1/Call/{}/Feedback/"
7 |
8 |
9 | class CallFeedback(PlivoResourceInterface):
10 | def create(self, call_uuid, rating, issues=[], notes=""):
11 | if len(call_uuid) == 0:
12 | raise ValidationError('call_uuid cannot be empty')
13 | if not rating:
14 | raise ValidationError('rating cannot be empty')
15 | request_path = FEEDBACK_API_PATH.format(call_uuid)
16 | params_dict = {}
17 | params_dict['rating'] = rating
18 | if len(issues) > 0:
19 | params_dict['issues'] = issues
20 | if len(notes) > 0:
21 | params_dict['notes'] = notes
22 | params_dict['is_callinsights_request'] = True
23 | params_dict['callinsights_request_path'] = request_path
24 | return self.client.request('POST', ('Call', ), params_dict)
25 |
--------------------------------------------------------------------------------
/plivo/resources/live_calls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from plivo.base import PlivoResource,\
3 | PlivoResourceInterface
4 | from plivo.utils import to_param_dict
5 | from ..utils.validators import *
6 | from plivo.utils import to_param_dict
7 |
8 |
9 | class LiveCall(PlivoResource):
10 | _name = 'LiveCall'
11 | _identifier_string = 'call_uuid'
12 |
13 |
14 | class LiveCalls(PlivoResourceInterface):
15 | _resource_type = LiveCall
16 | _iterable = False
17 |
18 | @validate_args(
19 | limit=[
20 | optional(
21 | all_of(
22 | of_type(*six.integer_types),
23 | check(
24 | lambda limit: 0 < limit <= 20,
25 | message='0 < limit <= 20')))
26 | ],
27 | offset=[
28 | optional(
29 | all_of(
30 | of_type(*six.integer_types),
31 | check(lambda offset: 0 <= offset, message='0 <= offset')))
32 | ],
33 | call_direction=[
34 | optional(of_type(six.text_type), is_in(('inbound', 'outbound')))
35 | ],
36 | from_number=[optional(is_phonenumber())],
37 | to_number=[optional(is_iterable(of_type(six.text_type), sep='<'))],
38 | callback_url=[optional(is_url())],
39 | callback_method=[optional(of_type(six.text_type))],
40 | )
41 | def list_ids(self,
42 | call_direction=None,
43 | from_number=None,
44 | to_number=None,
45 | limit=20,
46 | offset=0,
47 | callback_url=None,
48 | callback_method=None
49 | ):
50 | params = to_param_dict(self.list_ids, locals())
51 | params.update({'status': 'live'})
52 | return self.client.request('GET', ('Call',), params, is_voice_request=True)
53 |
54 | @validate_args(_id=[of_type(six.text_type)],
55 | callback_url=[optional(is_url())],
56 | callback_method=[optional(of_type(six.text_type))])
57 | def get(self,
58 | _id,
59 | callback_url=None,
60 | callback_method=None):
61 | local_object = {}
62 | local_object['status'] = 'live'
63 | if callback_url:
64 | local_object['callback_url'] = callback_url
65 | if callback_method:
66 | local_object['callback_method'] = callback_method
67 | return self.client.request(
68 | 'GET', ('Call', _id), local_object, is_voice_request=True
69 | )
70 |
--------------------------------------------------------------------------------
/plivo/resources/lookup.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from plivo.base import PlivoResourceInterface, ResponseObject
3 |
4 |
5 | LOOKUP_API_ENDPOINT = "https://lookup.plivo.com/v1/Number"
6 |
7 |
8 | class Number(ResponseObject):
9 | def __init__(self, client, data):
10 | super(Number, self).__init__(data)
11 |
12 |
13 | class Lookup(PlivoResourceInterface):
14 | _resource_type = Number
15 |
16 | def get(self, number, info_type='carrier'):
17 | params = {
18 | 'type': info_type,
19 | }
20 | return self.client.request(
21 | 'GET',
22 | (LOOKUP_API_ENDPOINT, number),
23 | data=params,
24 | response_type=Number,
25 | is_lookup_request=True)
26 |
--------------------------------------------------------------------------------
/plivo/resources/media.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from plivo.utils.validators import *
3 |
4 | from ..base import ListResponseObject, PlivoResource, PlivoResourceInterface
5 | from ..exceptions import *
6 | from ..utils import *
7 |
8 |
9 | class Media(PlivoResource):
10 | _name = 'Media'
11 | _identifier_string = 'media_id'
12 |
13 | def get(self):
14 | return self.client.medias.get(self.id)
15 |
16 |
17 | class Media(PlivoResourceInterface):
18 | _resource_type = Media
19 |
20 | @validate_args(
21 | media_file=[optional(of_type_exact(list))])
22 | def upload(self, media_file):
23 | if media_file:
24 | fileList = []
25 | for media_url in media_file:
26 | file_extension = media_url.strip().split('.')[-1].lower()
27 | if file_extension not in ['jpeg', 'jpg', 'png', 'xcf', 'plain', 'pdf', 'mpeg', 'mp4']:
28 | raise ValidationError(
29 | 'File format of the file to be uploaded should be one of JPG, JPEG, PNG or PDF'
30 | )
31 | content_types = {
32 | 'jpeg': 'image/jpeg',
33 | 'jpg': 'image/jpeg',
34 | 'png': 'image/png',
35 | 'pdf': 'application/pdf',
36 | 'xcf': 'image/xcf',
37 | 'text': 'text/plain',
38 | 'mpeg': 'video/mpeg',
39 | 'mp4': 'video/mp4'
40 | }
41 | print(media_url)
42 | import os
43 | files = (
44 | 'file', (media_url.split(os.sep)[-1], open(
45 | media_url, 'rb'), content_types[file_extension])
46 | )
47 | fileList.append(files)
48 | data_to_send = {}
49 | return self.client.request(
50 | 'POST', ('Media', ), data_to_send, files=fileList)
51 |
52 | @validate_args(media_id=[of_type(six.text_type)])
53 | def get(self, media_id):
54 | return self.client.request(
55 | 'GET', ('Media', media_id), response_type=None)
56 |
57 | @validate_args(
58 | limit=[
59 | optional(
60 | all_of(
61 | of_type(*six.integer_types),
62 | check(lambda limit: 0 < limit <= 20, '0 < limit <= 20')))
63 | ],
64 | offset=[
65 | optional(
66 | all_of(
67 | of_type(*six.integer_types),
68 | check(lambda offset: 0 <= offset, '0 <= offset')))
69 | ])
70 | def list(self,
71 | limit=20,
72 | offset=0):
73 | return self.client.request(
74 | 'GET', ('Media', ),
75 | to_param_dict(self.list, locals()),
76 | response_type=None)
77 |
--------------------------------------------------------------------------------
/plivo/resources/nodes.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Node class
4 | """
5 | from plivo.base import PlivoResource
6 | from plivo.utils import to_param_dict
7 | from plivo.utils.validators import *
8 |
9 |
10 | class Node(PlivoResource):
11 | _name = 'Node'
12 | _identifier_string = 'node_id'
13 |
14 | @validate_args(
15 | action=[of_type(six.text_type)])
16 | def update(self,
17 | action,
18 | trigger_source,
19 | to,
20 | role):
21 | return self.client.request('POST', ('phlo', self.phlo_id, self.node_type, self.node_id),
22 | to_param_dict(self.update, locals()))
23 |
24 |
25 | class MultiPartyCall(Node):
26 | _name = 'MultiPartyCall'
27 | _identifier_string = 'node_id'
28 |
29 | def call(self,
30 | trigger_source,
31 | to,
32 | role):
33 | return self.update('call', trigger_source, to, role)
34 |
35 | def warm_transfer(self,
36 | trigger_source,
37 | to,
38 | role='agent'):
39 | return self.update('warm_transfer', trigger_source, to, role)
40 |
41 | def cold_transfer(self,
42 | trigger_source,
43 | to,
44 | role='agent'):
45 | return self.update('cold_transfer', trigger_source, to, role)
46 |
47 | def member(self, member_id):
48 | self.member_id = member_id
49 | data = {
50 | 'member_id': member_id,
51 | 'phlo_id': self.phlo_id,
52 | 'node_id': self.node_id,
53 | 'node_type': self.node_type
54 | }
55 | return Member(self.client, data)
56 |
57 |
58 | class Member(PlivoResource):
59 | _name = 'Member'
60 | _identifier_string = 'member_id'
61 |
62 | def abort_transfer(self):
63 | return self.update('abort_transfer')
64 |
65 | def resume_call(self):
66 | return self.update('resume_call')
67 |
68 | def voicemail_drop(self):
69 | return self.update('voicemail_drop')
70 |
71 | def hangup(self):
72 | return self.update('hangup')
73 |
74 | def hold(self):
75 | return self.update('hold')
76 |
77 | def unhold(self):
78 | return self.update('unhold')
79 |
80 | def mute(self):
81 | return self.update('mute')
82 |
83 | def unmute(self):
84 | return self.update('unmute')
85 |
86 | def update(self,
87 | action):
88 | return self.client.request('POST', ('phlo', self.phlo_id, self.node_type, self.node_id, 'members', self.member_id),
89 | to_param_dict(self.update, locals()))
90 |
--------------------------------------------------------------------------------
/plivo/resources/pricings.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Pricing class - along with its list class
4 | """
5 |
6 | from plivo.base import PlivoResource, PlivoResourceInterface
7 | from plivo.utils import to_param_dict
8 | from plivo.utils.validators import *
9 |
10 |
11 | class Pricing(PlivoResource):
12 | _name = 'Pricing'
13 | _identifier_string = 'country_iso'
14 |
15 | def get(self):
16 | return self.client.pricing.get(self.id)
17 |
18 |
19 | class Pricings(PlivoResourceInterface):
20 | _resource_type = Pricing
21 |
22 | @validate_args(country_iso=[regex(r'^[A-Z]{2}$')])
23 | def get(self, country_iso):
24 | return self.client.request(
25 | 'GET', ('Pricing', ),
26 | to_param_dict(self.get, locals()),
27 | response_type=Pricing)
28 |
--------------------------------------------------------------------------------
/plivo/resources/queued_calls.py:
--------------------------------------------------------------------------------
1 | from plivo.base import PlivoResource, PlivoResourceInterface
2 |
3 | from ..utils.validators import *
4 |
5 |
6 | class QueuedCall(PlivoResource):
7 | _name = 'QueuedCall'
8 | _identifier_string = 'call_uuid'
9 |
10 |
11 | class QueuedCalls(PlivoResourceInterface):
12 | _resource_type = QueuedCall
13 | _iterable = False
14 |
15 | @validate_args(
16 | limit=[
17 | optional(
18 | all_of(
19 | of_type(*six.integer_types),
20 | check(
21 | lambda limit: 0 < limit <= 20,
22 | message='0 < limit <= 20')))
23 | ],
24 | offset=[
25 | optional(
26 | all_of(
27 | of_type(*six.integer_types),
28 | check(lambda offset: 0 <= offset, message='0 <= offset')))
29 | ],
30 | callback_url=[optional(is_url())],
31 | callback_method=[optional(of_type(six.text_type))],)
32 | def list_ids(self, limit=20, offset=0, callback_url=None, callback_method=None):
33 | return self.client.request('GET', ('Call', ), {
34 | 'status': 'queued',
35 | 'limit': limit,
36 | 'offset': offset,
37 | 'callback_url': callback_url,
38 | 'callback_method': callback_method
39 | }, is_voice_request=True)
40 |
41 | @validate_args(_id=[of_type(six.text_type)],
42 | callback_url=[optional(is_url())],
43 | callback_method=[optional(of_type(six.text_type))],)
44 | def get(self,
45 | _id,
46 | callback_url=None,
47 | callback_method=None):
48 | local_object={}
49 | local_object['status'] = 'queued'
50 | if callback_url:
51 | local_object['callback_url'] = callback_url
52 | if callback_method:
53 | local_object['callback_method'] = callback_method
54 |
55 | return self.client.request('GET', ('Call', _id), local_object, is_voice_request=True)
56 |
--------------------------------------------------------------------------------
/plivo/resources/token.py:
--------------------------------------------------------------------------------
1 | import string
2 |
3 | from plivo.base import (PlivoResourceInterface)
4 | from plivo.utils.validators import *
5 |
6 |
7 | class Token(PlivoResourceInterface):
8 | @validate_args(
9 | iss=[required(of_type(six.text_type))],
10 | sub=[optional(of_type(six.text_type))],
11 | nbf=[optional(of_type(six.text_type))],
12 | exp=[optional(of_type(six.text_type))],
13 | incoming_allow=[optional(of_type(bool, string))],
14 | outgoing_allow=[optional(of_type(bool, string))],
15 | app=[optional(of_type(six.text_type))]
16 | )
17 | def create(self, iss, sub=None, nbf=None, exp=None, incoming_allow=None, outgoing_allow=None, app=None):
18 | if incoming_allow is True and sub is None:
19 | raise ValueError('sub is required when incoming_allow is true')
20 | else:
21 | params = {'iss': iss}
22 |
23 | if sub:
24 | params['sub'] = sub
25 | if nbf:
26 | params['nbf'] = nbf
27 | if exp:
28 | params['exp'] = exp
29 | if incoming_allow or outgoing_allow:
30 | params['per'] = {}
31 | params['per']['voice'] = {}
32 | if incoming_allow:
33 | params['per']['voice']['incoming_allow'] = incoming_allow
34 | if outgoing_allow:
35 | params['per']['voice']['outgoing_allow'] = outgoing_allow
36 | if app:
37 | params['app'] = app
38 |
39 | return self.client.request('POST', ('JWT', 'Token',), params, is_voice_request=True)
40 |
--------------------------------------------------------------------------------
/plivo/resources/transcription.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Recording class - along with its list class
4 | """
5 |
6 | from plivo.base import (ListResponseObject, PlivoResource,
7 | PlivoResourceInterface)
8 | from plivo.resources.accounts import Subaccount
9 | from plivo.utils import is_valid_time_comparison, to_param_dict
10 | from plivo.utils.validators import *
11 |
12 |
13 | class Transcription(PlivoResource):
14 | _name = 'Transcription'
15 | _identifier_string = 'transcription_id'
16 |
17 | def get_transcription(self):
18 | return self.client.transcriptions.get_transcription(self.id, **to_param_dict(self.get_transcription(), locals()))
19 |
20 | def create_transcription(self):
21 | return self.client.transcriptions.create_transcription(self.id, **to_param_dict(self.create_transcription(), locals()))
22 |
23 | def delete_transcription(self):
24 | return self.client.transcriptions.delete_transcription(self.id, **to_param_dict(self.delete_transcription(), locals()))
25 |
26 |
27 | class Transcriptions(PlivoResourceInterface):
28 | _resource_type = Transcription
29 |
30 | @validate_args(transcription_id=[of_type(six.text_type)]
31 | )
32 | def get_transcription(self, transcription_id, type=None):
33 | if not type:
34 | return self.client.request(
35 | 'GET', ('Transcription', transcription_id), is_voice_request=True)
36 | else:
37 | return self.client.request(
38 | 'GET', ('Transcription', transcription_id), to_param_dict(self.get_transcription, locals()), is_voice_request=True)
39 |
40 | def create_transcription(self, recording_id, transcription_callback_url=None):
41 | return self.client.request(
42 | 'POST', ('Transcription', recording_id), to_param_dict(self.create_transcription, locals()), is_voice_request=True)
43 |
44 | def delete_transcription(self, transcription_id):
45 | return self.client.request(
46 | 'DELETE', ('Transcription', transcription_id), is_voice_request=True)
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/plivo/rest/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/plivo/plivo-python/4f29e49de8acd7fb4ec547cb2a163ed667ace122/plivo/rest/.DS_Store
--------------------------------------------------------------------------------
/plivo/rest/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from .client import Client
3 |
--------------------------------------------------------------------------------
/plivo/rest/phlo.py:
--------------------------------------------------------------------------------
1 | from .phlo_client import PhloClient as RestClient
--------------------------------------------------------------------------------
/plivo/rest/phlo_client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Phlo client, used for Phlo API requests.
4 | """
5 | from plivo.resources import Phlos
6 | from plivo.rest.base_client import BaseClient
7 | from requests import Request
8 |
9 | PHLO_API = 'https://phlorunner.plivo.com'
10 | PHLO_API_BASE_URI = '/'.join([PHLO_API, 'v1'])
11 |
12 |
13 | class PhloClient(BaseClient):
14 | def __init__(self, auth_id=None, auth_token=None, proxies=None, timeout=5):
15 | """
16 | The Plivo API client.
17 |
18 | Deals with all the API requests to be made.
19 | """
20 | BaseClient.__init__(self, auth_id, auth_token, proxies, timeout)
21 |
22 | self.phlo_base_uri = PHLO_API_BASE_URI
23 | self.phlo = Phlos(self)
24 |
25 | def create_request(self, method, path=None, data=None):
26 | path = path or []
27 |
28 | req = Request(method, '/'.join([self.phlo_base_uri] +
29 | list([str(p) for p in path])) + '/',
30 | **({
31 | 'params': data
32 | } if method == 'GET' else {
33 | 'json': data
34 | }))
35 | return self.session.prepare_request(req)
--------------------------------------------------------------------------------
/plivo/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import inspect
3 | import re
4 | from datetime import datetime
5 |
6 | from hmac import new as hnew
7 | from hashlib import sha256
8 | from .signature_v3 import validate_v3_signature
9 |
10 | try:
11 | from urllib.parse import urlparse, urlunparse
12 | except ImportError:
13 | from urlparse import urlparse, urlunparse
14 |
15 | try:
16 | from base64 import encodebytes as base64_encode
17 | except ImportError:
18 | from base64 import encodestring as base64_encode
19 |
20 | try:
21 | from inspect import getfullargspec as getargspec
22 | except ImportError:
23 | from inspect import getargspec as getargspec
24 |
25 | def validate_signature(uri, nonce, signature, auth_token=''):
26 | """
27 | Validates requests made by Plivo to your servers.
28 |
29 | :param uri: Your server URL
30 | :param nonce: X-Plivo-Signature-V2-Nonce
31 | :param signature: X-Plivo-Signature-V2 header
32 | :param auth_token: Plivo Auth token
33 | :return: True if the request matches signature, False otherwise
34 | """
35 |
36 | auth_token = bytes(auth_token.encode('utf-8'))
37 | nonce = bytes(nonce.encode('utf-8'))
38 | signature = bytes(signature.encode('utf-8'))
39 |
40 | parsed_uri = urlparse(uri.encode('utf-8'))
41 | base_url = urlunparse((parsed_uri.scheme.decode('utf-8'),
42 | parsed_uri.netloc.decode('utf-8'),
43 | parsed_uri.path.decode('utf-8'), '', '',
44 | '')).encode('utf-8')
45 |
46 | return base64_encode(hnew(auth_token, base_url + nonce, sha256)
47 | .digest()).strip() == signature
48 |
49 |
50 | def is_valid_time_comparison(time):
51 | if isinstance(time, datetime):
52 | return True
53 | return False
54 |
55 |
56 | def is_valid_subaccount(subaccount):
57 | subaccount_string = str(subaccount)
58 | if len(subaccount_string) == 20 and subaccount_string[:2] == 'SA':
59 | return True
60 | return False
61 |
62 |
63 | def is_valid_mainaccount(mainaccount):
64 | mainaccount_string = str(mainaccount)
65 | if len(mainaccount_string) == 20 and mainaccount_string[:2] == 'MA':
66 | return True
67 | return False
68 |
69 |
70 | def to_param_dict(func, vals, exclude_none=True, func_args_check=True):
71 | args = getargspec(func)[0]
72 | arg_names = list(args)
73 | # The bit of regex magic below is for arguments that are keywords in
74 | # Python, like from. These can't be used directly, so our convention is to
75 | # add "_" suffixes to them. This strips them out.
76 | pd = {
77 | re.sub(r'^(.*)_+$', r'\1', key): value
78 | for key, value in vals.items()
79 | if key != 'self' and (key in arg_names or func_args_check==False) and (
80 | value is not None or exclude_none is False)
81 | }
82 | return pd
83 |
--------------------------------------------------------------------------------
/plivo/utils/interactive.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import validate_args, optional, of_type_exact, validate_list_items, validate_dict_items
2 |
3 | class Header:
4 | @validate_args(
5 | type=[optional(of_type_exact(str, type(None)))],
6 | text=[optional(of_type_exact(str, type(None)))],
7 | media=[optional(of_type_exact(str, type(None)))]
8 | )
9 | def __init__(self, type=None, text=None, media=None):
10 | self.type = type
11 | self.text = text
12 | self.media = media
13 |
14 | class Body:
15 | @validate_args(
16 | text=[optional(of_type_exact(str, type(None)))]
17 | )
18 | def __init__(self, text=None):
19 | self.text = text
20 |
21 | class Footer:
22 | @validate_args(
23 | text=[optional(of_type_exact(str, type(None)))]
24 | )
25 | def __init__(self, text=None):
26 | self.text = text
27 |
28 | class Row:
29 | @validate_args(
30 | id=[optional(of_type_exact(str, type(None)))],
31 | title=[optional(of_type_exact(str, type(None)))],
32 | description=[optional(of_type_exact(str, type(None)))]
33 | )
34 | def __init__(self, id=None, title=None, description=None):
35 | self.id = id
36 | self.title = title
37 | self.description = description
38 |
39 | class Section:
40 | @validate_args(
41 | title=[optional(of_type_exact(str, type(None)))],
42 | rows=[optional(validate_list_items(Row))]
43 | )
44 | def __init__(self, title=None, rows=None):
45 | self.title = title
46 | self.rows = rows if rows is not None else []
47 |
48 | class Btn:
49 | @validate_args(
50 | id=[optional(of_type_exact(str, type(None)))],
51 | title=[optional(of_type_exact(str, type(None)))],
52 | cta_url=[optional(of_type_exact(str, type(None)))]
53 | )
54 | def __init__(self, id=None, title=None, cta_url=None):
55 | self.id = id
56 | self.title = title
57 | self.cta_url = cta_url
58 |
59 | class Action:
60 | @validate_args(
61 | buttons=[optional(validate_list_items(Btn))],
62 | sections=[optional(validate_list_items(Section))]
63 | )
64 | def __init__(self, buttons=None, sections=None):
65 | self.buttons = buttons if buttons is not None else []
66 | self.sections = sections if sections is not None else []
67 |
68 | class Interactive:
69 | @validate_args(
70 | type=[optional(of_type_exact(str, type(None)))],
71 | header=[optional(validate_dict_items(Header))],
72 | body=[optional(validate_dict_items(Body))],
73 | footer=[optional(validate_dict_items(Footer))],
74 | action=[optional(validate_dict_items(Action))]
75 | )
76 | def __init__(self, type=None, header=None, body=None, footer=None, action=None):
77 | self.type = type
78 | # Assign directly the validated dictionary or default to None if not provided
79 | self.header = header
80 | self.body = body
81 | self.footer = footer
82 | self.action = action
83 |
--------------------------------------------------------------------------------
/plivo/utils/jwt.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 | import jwt, time
3 | from plivo.utils.validators import *
4 |
5 | """
6 | Class to represent plivo token for endpoint authentication
7 | """
8 | class AccessToken:
9 | auth_id = ''
10 | username = ''
11 | valid_from = 0
12 | lifetime = 86400
13 | key = ''
14 | grants = {}
15 | uid = 0
16 |
17 | @validate_args(
18 | auth_id=[is_account_id()],
19 | auth_token=[optional(of_type(six.text_type))],
20 | username=[all_of(
21 | of_type(six.text_type),
22 | check(lambda username: len(username) > 0, 'empty username')
23 | )],
24 | valid_from=[optional(of_type(*six.integer_types))],
25 | lifetime=[
26 | optional(
27 | all_of(
28 | of_type(*six.integer_types),
29 | check(lambda lifetime: 180 <= lifetime <= 86400,
30 | '180 < lifetime <= 86400')))
31 | ],
32 | valid_till=[optional(of_type(*six.integer_types))],
33 | )
34 | def __init__(self,
35 | auth_id,
36 | auth_token,
37 | username,
38 | valid_from=None,
39 | lifetime=None,
40 | valid_till=None,
41 | uid=None):
42 | self.auth_id = auth_id
43 | self.username = username
44 | if valid_from:
45 | self.valid_from = int(valid_from)
46 | else:
47 | self.valid_from = int(time.time())
48 | if lifetime:
49 | self.lifetime = int(lifetime)
50 | if valid_till is not None:
51 | raise ValidationError("use either lifetime or valid_till")
52 | elif valid_till:
53 | self.lifetime = valid_till - self.valid_from
54 | if self.lifetime < 0:
55 | raise ValidationError(
56 | "validity expires %s seconds before it starts" %
57 | self.lifetime)
58 | if self.lifetime < 180 or self.lifetime > 86400:
59 | raise ValidationError(
60 | "validity of %s seconds is out of permitted range [180, 86400]" %
61 | self.lifetime)
62 |
63 | self.key = auth_token
64 |
65 | if uid:
66 | self.uid = uid
67 | else:
68 | self.uid = "%s-%s" % (username, time.time())
69 |
70 | @validate_args(
71 | incoming=[optional(of_type_exact(bool))],
72 | outgoing=[optional(of_type_exact(bool))],
73 | )
74 | def add_voice_grants(self, incoming=False, outgoing=False):
75 | self.grants['voice'] = {
76 | 'incoming_allow': incoming,
77 | 'outgoing_allow': outgoing
78 | }
79 |
80 | def to_jwt(self):
81 | headers = {'typ': 'JWT', 'cty': 'plivo;v=1'}
82 | algorithm = 'HS256'
83 | claims = {
84 | 'jti': self.uid,
85 | 'iss': self.auth_id,
86 | 'sub': self.username,
87 | 'nbf': self.valid_from,
88 | 'exp': self.valid_from + self.lifetime,
89 | 'grants': self.grants
90 | }
91 | return jwt.encode(claims, self.key, algorithm, headers).decode('utf-8')
92 |
--------------------------------------------------------------------------------
/plivo/utils/location.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import validate_args, required, of_type_exact
2 |
3 | class Location:
4 | @validate_args(
5 | latitude=[required(of_type_exact(str))],
6 | longitude=[required(of_type_exact(str))],
7 | name=[required(of_type_exact(str))],
8 | address=[required(of_type_exact(str))]
9 | )
10 | def __init__(self, latitude, longitude, name, address):
11 | self.latitude = latitude
12 | self.longitude = longitude
13 | self.name = name
14 | self.address = address
15 |
--------------------------------------------------------------------------------
/plivo/utils/template.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import *
2 | from plivo.utils.location import *
3 |
4 | class Parameter:
5 | @validate_args(
6 | type=[required(of_type_exact(str))],
7 | text=[optional(of_type_exact(str, type(None)))],
8 | media=[optional(of_type_exact(str))],
9 | payload=[optional(of_type_exact(str))],
10 | currency=[optional(of_type_exact(dict))],
11 | date_time=[optional(of_type_exact(dict))],
12 | location=[optional(validate_dict_items(Location))],
13 | parameter_name=[optional(of_type_exact(str))],
14 | )
15 | def __init__(self, type, text=None, media=None, payload=None, currency=None, date_time=None, location=None, parameter_name=None):
16 | self.type = type
17 | self.text = text
18 | self.media = media
19 | self.payload = payload
20 | self.currency = Currency(**currency) if currency else None
21 | self.date_time = DateTime(**date_time) if date_time else None
22 | self.location = location
23 | self.parameter_name = parameter_name
24 |
25 | class Component:
26 | @validate_args(
27 | type=[required(of_type_exact(str))],
28 | sub_type=[optional(of_type_exact(str, type(None)))],
29 | index=[optional(of_type_exact(str, type(None)))],
30 | parameters=[optional(validate_list_items(Parameter))],
31 | )
32 | def __init__(self, type, sub_type=None, index=None, parameters=None):
33 | self.type = type
34 | self.sub_type = sub_type
35 | self.index = index
36 | self.parameters = parameters if parameters is not None else []
37 |
38 | class Template:
39 | @validate_args(
40 | name=[required(of_type_exact(str))],
41 | language=[required(of_type_exact(str))],
42 | components=[optional(validate_list_items(Component))],
43 | )
44 | def __init__(self, name, language, components=None):
45 | self.name = name
46 | self.language = language
47 | self.components = components if components is not None else []
48 |
49 |
50 | class Currency:
51 | @validate_args(
52 | fallback_value=[required(of_type_exact(str))],
53 | currency_code=[required(of_type_exact(str))],
54 | amount_1000=[required(of_type_exact(int))],
55 | )
56 | def __init__(self, fallback_value, currency_code, amount_1000):
57 | self.fallback_value=fallback_value
58 | self.currency_code = currency_code
59 | self.amount_1000 = amount_1000
60 |
61 |
62 | class DateTime:
63 | @validate_args(
64 | fallback_value=[required(of_type_exact(str))],
65 | )
66 | def __init__(self, fallback_value):
67 | self.fallback_value = fallback_value
68 |
--------------------------------------------------------------------------------
/plivo/version.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | __version__ = '4.59.1'
3 |
--------------------------------------------------------------------------------
/plivo/xml/DTMFElement.py:
--------------------------------------------------------------------------------
1 | from plivo.xml import PlivoXMLElement, map_type
2 | from plivo.utils.validators import *
3 |
4 |
5 | class DTMFElement(PlivoXMLElement):
6 | _name = 'DTMF'
7 | _nestable = []
8 |
9 | @property
10 | def async_(self):
11 | return self.__async
12 |
13 | @async_.setter
14 | def async_(self, value):
15 | self.__async = bool(value) if value is not None else None
16 |
17 | @validate_args(
18 | value=[of_type_exact(bool)],
19 | )
20 | def set_async(self, value):
21 | self.async_ = value
22 | return self
23 |
24 | def __init__(
25 | self,
26 | content,
27 | async_=None,
28 | ):
29 | super(DTMFElement, self).__init__()
30 |
31 | self.content = content
32 | self.async_ = async_
33 |
34 | def to_dict(self):
35 | d = {
36 | 'async': self.async_,
37 | }
38 | return {
39 | k: six.text_type(map_type(v))
40 | for k, v in d.items() if v is not None
41 | }
42 |
--------------------------------------------------------------------------------
/plivo/xml/PlivoXMLElement.py:
--------------------------------------------------------------------------------
1 | from lxml import etree
2 | import six
3 | from plivo.exceptions import PlivoXMLError
4 |
5 |
6 | class PlivoXMLElement(object):
7 | def __init__(self):
8 | self.content = ''
9 | self.children = []
10 |
11 | def add(self, element):
12 | if not isinstance(element, PlivoXMLElement):
13 | raise PlivoXMLError('element must be a PlivoXMLElement')
14 |
15 | if element._name not in self._nestable:
16 | raise PlivoXMLError(
17 | '{} is not nestable in {} (allowed: {})'.format(
18 | element._name, self._name, self._nestable))
19 | self.children.append(element)
20 | return self
21 |
22 | def continue_speak(self, body=None):
23 | return body.replace('', ' ').replace('', ' ')
24 |
25 | def to_string(self, pretty=True):
26 | s = self.continue_speak(etree.tostring(self._to_element(), pretty_print=pretty, encoding='unicode'))
27 |
28 | if not isinstance(s, str):
29 | s = s.encode('utf-8')
30 | return s
31 |
32 | def _to_element(self, parent=None):
33 | e = etree.SubElement(
34 | parent, self._name,
35 | **self.to_dict()) if parent is not None else etree.Element(
36 | self._name, **self.to_dict())
37 | if self.content:
38 | try:
39 | if six.PY2 and isinstance(self.content, str):
40 | e.text = self.content.decode()
41 | elif six.PY3 and isinstance(self.content, bytes):
42 | e.text = self.content.decode()
43 | else:
44 | e.text = self.content
45 | except:
46 | e.text = self.content
47 | for child in self.children:
48 | child._to_element(parent=e)
49 | return e
50 |
--------------------------------------------------------------------------------
/plivo/xml/__init__.py:
--------------------------------------------------------------------------------
1 | from .xmlUtils import map_type
2 | from .PlivoXMLElement import PlivoXMLElement
3 | from .ConferenceElement import ConferenceElement
4 | from .DTMFElement import DTMFElement
5 | from .MultiPartyCallElement import MultiPartyCallElement
6 | from .hangupElement import HangupElement
7 | from .messageElement import MessageElement
8 | from .numberElement import NumberElement
9 | from .playElement import PlayElement
10 | from .waitElement import WaitElement
11 | from .recordElement import RecordElement
12 | from .redirectElement import RedirectElement
13 | from .userElement import UserElement
14 | from .breakElement import BreakElement
15 | from .langElement import LangElement
16 | from .emphasisElement import EmphasisElement
17 | from .speakElement import SpeakElement
18 | from .getDigitsElement import GetDigitsElement
19 | from .getInputElement import GetInputElement
20 | from .preAnswerElement import PreAnswerElement
21 | from .DialElement import DialElement
22 | from .ResponseElement import ResponseElement
23 | from .pElement import PElement
24 | from .phonemeElement import PhonemeElement
25 | from .prosodyElement import ProsodyElement
26 | from .sElement import SElement
27 | from .sayAsElement import SayAsElement
28 | from .subElement import SubElement
29 | from .wElement import WElement
30 | from .contElement import ContElement
31 | from .streamElement import StreamElement
--------------------------------------------------------------------------------
/plivo/xml/breakElement.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import *
2 | from plivo.xml import PlivoXMLElement, map_type
3 |
4 |
5 | class BreakElement(PlivoXMLElement):
6 | _name = 'break'
7 | _nestable = []
8 |
9 | @property
10 | def strength(self):
11 | return self.__strength
12 |
13 | @strength.setter
14 | def strength(self, value):
15 | self.__strength = six.text_type(
16 | value) if value is not None else None
17 |
18 | @validate_args(
19 | value=[of_type(six.text_type)],
20 | )
21 | def set_strength(self, value):
22 | self.strength = value
23 | return self
24 |
25 | @property
26 | def time(self):
27 | return self.__time
28 |
29 | @time.setter
30 | def time(self, value):
31 | self.__time = six.text_type(
32 | value) if value is not None else None
33 |
34 | @validate_args(
35 | value=[of_type(six.text_type)],
36 | )
37 | def set_time(self, value):
38 | self.time = value
39 | return self
40 |
41 | def __init__(
42 | self,
43 | content=None,
44 | strength=None,
45 | time=None,
46 | ):
47 |
48 | super(BreakElement, self).__init__()
49 | self.content = content
50 | self.strength = strength
51 | self.time = time
52 |
53 | def to_dict(self):
54 | d = {
55 | 'strength': self.strength,
56 | 'time': self.time,
57 | }
58 |
59 | return {
60 | k: six.text_type(map_type(v))
61 | for k, v in d.items() if v is not None
62 | }
63 |
--------------------------------------------------------------------------------
/plivo/xml/hangupElement.py:
--------------------------------------------------------------------------------
1 | from plivo.xml import PlivoXMLElement, map_type
2 | from plivo.utils.validators import *
3 |
4 |
5 | class HangupElement(PlivoXMLElement):
6 | _name = 'Hangup'
7 | _nestable = []
8 |
9 | @property
10 | def reason(self):
11 | return self.__reason
12 |
13 | @reason.setter
14 | def reason(self, value):
15 | self.__reason = six.text_type(value) if value is not None else None
16 |
17 | @validate_args(
18 | value=[of_type(six.text_type)],
19 | )
20 | def set_reason(self, value):
21 | self.reason = value
22 | return self
23 |
24 | @property
25 | def schedule(self):
26 | return self.__schedule
27 |
28 | @schedule.setter
29 | def schedule(self, value):
30 | self.__schedule = int(value) if value is not None else None
31 |
32 | @validate_args(
33 | value=[of_type(*six.integer_types)],
34 | )
35 | def set_schedule(self, value):
36 | self.schedule = value
37 | return self
38 |
39 | def __init__(
40 | self,
41 | reason=None,
42 | schedule=None,
43 | ):
44 | super(HangupElement, self).__init__()
45 |
46 | self.reason = reason
47 | self.schedule = schedule
48 |
49 | def to_dict(self):
50 | d = {
51 | 'reason': self.reason,
52 | 'schedule': self.schedule,
53 | }
54 | return {
55 | k: six.text_type(map_type(v))
56 | for k, v in d.items() if v is not None
57 | }
58 |
--------------------------------------------------------------------------------
/plivo/xml/messageElement.py:
--------------------------------------------------------------------------------
1 | from plivo.xml import PlivoXMLElement, map_type
2 | from plivo.utils.validators import *
3 |
4 |
5 | class MessageElement(PlivoXMLElement):
6 | _name = 'Message'
7 | _nestable = []
8 |
9 | @property
10 | def src(self):
11 | return self.__src
12 |
13 | @src.setter
14 | def src(self, value):
15 | self.__src = six.text_type(value) if value is not None else None
16 |
17 | @validate_args(
18 | value=[of_type(six.text_type)],
19 | )
20 | def set_src(self, value):
21 | self.src = value
22 | return self
23 |
24 | @property
25 | def dst(self):
26 | return self.__dst
27 |
28 | @dst.setter
29 | def dst(self, value):
30 | self.__dst = six.text_type(value) if value is not None else None
31 |
32 | @validate_args(
33 | value=[of_type(six.text_type)],
34 | )
35 | def set_dst(self, value):
36 | self.dst = value
37 | return self
38 |
39 | @property
40 | def type(self):
41 | return self.__type
42 |
43 | @type.setter
44 | def type(self, value):
45 | self.__type = six.text_type(value) if value is not None else None
46 |
47 | @validate_args(
48 | value=[of_type(six.text_type)],
49 | )
50 | def set_type(self, value):
51 | self.type = value
52 | return self
53 |
54 | @property
55 | def callback_url(self):
56 | return self.__callback_url
57 |
58 | @callback_url.setter
59 | def callback_url(self, value):
60 | self.__callback_url = six.text_type(
61 | value) if value is not None else None
62 |
63 | @validate_args(
64 | value=[of_type(six.text_type)],
65 | )
66 | def set_callback_url(self, value):
67 | self.callback_url = value
68 | return self
69 |
70 | @property
71 | def callback_method(self):
72 | return self.__callback_method
73 |
74 | @callback_method.setter
75 | def callback_method(self, value):
76 | self.__callback_method = six.text_type(
77 | value) if value is not None else None
78 |
79 | @validate_args(
80 | value=[of_type(six.text_type)],
81 | )
82 | def set_callback_method(self, value):
83 | self.callback_method = value
84 | return self
85 |
86 | def __init__(
87 | self,
88 | content,
89 | src=None,
90 | dst=None,
91 | type=None,
92 | callback_url=None,
93 | callback_method=None,
94 | ):
95 | super(MessageElement, self).__init__()
96 |
97 | self.content = content
98 | self.src = src
99 | self.dst = dst
100 | self.type = type
101 | self.callback_url = callback_url
102 | self.callback_method = callback_method
103 |
104 | def to_dict(self):
105 | d = {
106 | 'src': self.src,
107 | 'dst': self.dst,
108 | 'type': self.type,
109 | 'callbackUrl': self.callback_url,
110 | 'callbackMethod': self.callback_method,
111 | }
112 | return {
113 | k: six.text_type(map_type(v))
114 | for k, v in d.items() if v is not None
115 | }
116 |
--------------------------------------------------------------------------------
/plivo/xml/numberElement.py:
--------------------------------------------------------------------------------
1 | from plivo.xml import PlivoXMLElement, map_type
2 | from plivo.utils.validators import *
3 |
4 |
5 | class NumberElement(PlivoXMLElement):
6 | _name = 'Number'
7 | _nestable = []
8 |
9 | @property
10 | def send_digits(self):
11 | return self.__send_digits
12 |
13 | @send_digits.setter
14 | def send_digits(self, value):
15 | self.__send_digits = six.text_type(
16 | value) if value is not None else None
17 |
18 | @validate_args(
19 | value=[of_type(six.text_type)],
20 | )
21 | def set_send_digits(self, value):
22 | self.send_digits = value
23 | return self
24 |
25 | @property
26 | def send_on_preanswer(self):
27 | return self.__send_on_preanswer
28 |
29 | @send_on_preanswer.setter
30 | def send_on_preanswer(self, value):
31 | self.__send_on_preanswer = bool(value) if value is not None else None
32 |
33 | @validate_args(
34 | value=[of_type_exact(bool)],
35 | )
36 | def set_send_on_preanswer(self, value):
37 | self.send_on_preanswer = value
38 | return self
39 |
40 | @property
41 | def send_digits_mode(self):
42 | return self.__send_digits_mode
43 |
44 | @send_digits_mode.setter
45 | def send_digits_mode(self, value):
46 | self.__send_digits_mode = six.text_type(value) if value is not None else None
47 |
48 | @validate_args(
49 | value=[of_type(six.text_type)],
50 | )
51 | def set_send_digits_mode(self, value):
52 | self.send_digits_mode = value
53 | return self
54 |
55 | def __init__(
56 | self,
57 | content,
58 | send_digits=None,
59 | send_on_preanswer=None,
60 | send_digits_mode=None):
61 | super(NumberElement, self).__init__()
62 |
63 | self.content = str(content)
64 | self.send_digits = send_digits
65 | self.send_on_preanswer = send_on_preanswer
66 | self.send_digits_mode = send_digits_mode
67 |
68 | def to_dict(self):
69 | d = {
70 | 'sendDigits': self.send_digits,
71 | 'sendOnPreanswer': self.send_on_preanswer,
72 | 'sendDigitsMode': self.send_digits_mode,
73 | }
74 | return {
75 | k: six.text_type(map_type(v))
76 | for k, v in d.items() if v is not None
77 | }
78 |
--------------------------------------------------------------------------------
/plivo/xml/phonemeElement.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import *
2 | from plivo.xml import PlivoXMLElement, map_type
3 |
4 |
5 | class PhonemeElement(PlivoXMLElement):
6 | _name = 'phoneme'
7 | _nestable = []
8 |
9 | @property
10 | def alphabet(self):
11 | return self.__alphabet
12 |
13 | @alphabet.setter
14 | def alphabet(self, value):
15 | self.__alphabet = six.text_type(
16 | value) if value is not None else None
17 |
18 | @validate_args(
19 | value=[of_type(six.text_type)],
20 | )
21 | def set_alphabet(self, value):
22 | self.alphabet = value
23 | return self
24 |
25 | @property
26 | def ph(self):
27 | return self.__ph
28 |
29 | @ph.setter
30 | def ph(self, value):
31 | self.__ph = six.text_type(
32 | value) if value is not None else None
33 |
34 | @validate_args(
35 | value=[of_type(six.text_type)],
36 | )
37 | def set_ph(self, value):
38 | self.ph = value
39 | return self
40 |
41 | def __init__(
42 | self,
43 | content=None,
44 | alphabet=None,
45 | ph=None,
46 | ):
47 |
48 | super(PhonemeElement, self).__init__()
49 | self.content = content
50 | self.alphabet = alphabet
51 | self.ph = ph
52 |
53 | def to_dict(self):
54 | d = {
55 | 'alphabet': self.alphabet,
56 | 'ph': self.ph,
57 | }
58 |
59 | return {
60 | k: six.text_type(map_type(v))
61 | for k, v in d.items() if v is not None
62 | }
63 |
--------------------------------------------------------------------------------
/plivo/xml/playElement.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import *
2 | from plivo.xml import PlivoXMLElement, map_type
3 |
4 |
5 | class PlayElement(PlivoXMLElement):
6 | _name = 'Play'
7 | _nestable = []
8 |
9 | @property
10 | def loop(self):
11 | return self.__loop
12 |
13 | @loop.setter
14 | def loop(self, value):
15 | self.__loop = int(value) if value is not None else None
16 |
17 | @validate_args(
18 | value=[of_type(*six.integer_types)],
19 | )
20 | def set_loop(self, value):
21 | self.loop = value
22 | return self
23 |
24 | def __init__(
25 | self,
26 | content,
27 | loop=None,
28 | ):
29 | super(PlayElement, self).__init__()
30 |
31 | self.content = content
32 | self.loop = loop
33 |
34 | def to_dict(self):
35 | d = {
36 | 'loop': self.loop,
37 | }
38 | return {
39 | k: six.text_type(map_type(v))
40 | for k, v in d.items() if v is not None
41 | }
42 |
--------------------------------------------------------------------------------
/plivo/xml/redirectElement.py:
--------------------------------------------------------------------------------
1 | import six
2 |
3 | from plivo.utils.validators import *
4 | from plivo.xml import PlivoXMLElement, map_type
5 |
6 |
7 | class RedirectElement(PlivoXMLElement):
8 | _name = 'Redirect'
9 | _nestable = []
10 |
11 | @property
12 | def method(self):
13 | return self.__method
14 |
15 | @method.setter
16 | def method(self, value):
17 | self.__method = six.text_type(value) if value is not None else None
18 |
19 | @validate_args(
20 | value=[of_type(six.text_type)],
21 | )
22 | def set_method(self, value):
23 | self.method = value
24 | return self
25 |
26 | def __init__(
27 | self,
28 | content,
29 | method=None,
30 | ):
31 | super(RedirectElement, self).__init__()
32 |
33 | self.content = content
34 | self.method = method
35 |
36 | def to_dict(self):
37 | d = {
38 | 'method': self.method,
39 | }
40 | return {
41 | k: six.text_type(map_type(v))
42 | for k, v in d.items() if v is not None
43 | }
44 |
--------------------------------------------------------------------------------
/plivo/xml/sayAsElement.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import *
2 | from plivo.xml import PlivoXMLElement, map_type
3 |
4 |
5 | class SayAsElement(PlivoXMLElement):
6 | _name = 'say-as'
7 | _nestable = []
8 |
9 | @property
10 | def interpret_as(self):
11 | return self.__interpret_as
12 |
13 | @interpret_as.setter
14 | def interpret_as(self, value):
15 | self.__interpret_as = six.text_type(
16 | value) if value is not None else None
17 |
18 | @validate_args(
19 | value=[of_type(six.text_type)],
20 | )
21 | def set_interpret_as(self, value):
22 | self.interpret_as = value
23 | return self
24 |
25 | @property
26 | def format(self):
27 | return self.__format
28 |
29 | @format.setter
30 | def format(self, value):
31 | self.__format = six.text_type(
32 | value) if value is not None else None
33 |
34 | @validate_args(
35 | value=[of_type(six.text_type)],
36 | )
37 | def set_format(self, value):
38 | self.format = value
39 | return self
40 |
41 | def __init__(
42 | self,
43 | content,
44 | interpret_as=None,
45 | format=None,
46 | ):
47 |
48 | super(SayAsElement, self).__init__()
49 | self.content = content
50 | self.interpret_as = interpret_as
51 | self.format = format
52 |
53 | def to_dict(self):
54 | d = {
55 | 'interpret-as': self.interpret_as,
56 | 'format': self.format,
57 | }
58 | return {
59 | k: six.text_type(map_type(v))
60 | for k, v in d.items() if v is not None
61 | }
62 |
--------------------------------------------------------------------------------
/plivo/xml/subElement.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import *
2 | from plivo.xml import PlivoXMLElement, map_type
3 |
4 |
5 | class SubElement(PlivoXMLElement):
6 | _name = 'sub'
7 | _nestable = []
8 |
9 | @property
10 | def alias(self):
11 | return self.__alias
12 |
13 | @alias.setter
14 | def alias(self, value):
15 | self.__alias = six.text_type(
16 | value) if value is not None else None
17 |
18 | @validate_args(
19 | value=[of_type(six.text_type)],
20 | )
21 | def set_alias(self, value):
22 | self.alias = value
23 | return self
24 |
25 | def __init__(
26 | self,
27 | content=None,
28 | alias=None,
29 | ):
30 | super(SubElement, self).__init__()
31 |
32 | self.content = content
33 | self.alias = alias
34 |
35 | def to_dict(self):
36 | d = {
37 | 'alias': self.alias,
38 | }
39 |
40 | return {
41 | k: six.text_type(map_type(v))
42 | for k, v in d.items() if v is not None
43 | }
44 |
--------------------------------------------------------------------------------
/plivo/xml/userElement.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import *
2 | from plivo.xml import PlivoXMLElement, map_type
3 |
4 |
5 | class UserElement(PlivoXMLElement):
6 | _name = 'User'
7 | _nestable = []
8 |
9 | @property
10 | def send_digits(self):
11 | return self.__send_digits
12 |
13 | @send_digits.setter
14 | def send_digits(self, value):
15 | self.__send_digits = six.text_type(
16 | value) if value is not None else None
17 |
18 | @validate_args(
19 | value=[of_type(six.text_type)],
20 | )
21 | def set_send_digits(self, value):
22 | self.send_digits = value
23 | return self
24 |
25 | @property
26 | def send_on_preanswer(self):
27 | return self.__send_on_preanswer
28 |
29 | @send_on_preanswer.setter
30 | def send_on_preanswer(self, value):
31 | self.__send_on_preanswer = bool(value) if value is not None else None
32 |
33 | @validate_args(
34 | value=[of_type_exact(bool)],
35 | )
36 | def set_send_on_preanswer(self, value):
37 | self.send_on_preanswer = value
38 | return self
39 |
40 | @property
41 | def sip_headers(self):
42 | return self.__sip_headers
43 |
44 | @sip_headers.setter
45 | def sip_headers(self, value):
46 | self.__sip_headers = six.text_type(
47 | value) if value is not None else None
48 |
49 | @validate_args(
50 | value=[of_type(six.text_type)],
51 | )
52 | def set_sip_headers(self, value):
53 | self.sip_headers = value
54 | return self
55 |
56 | def __init__(
57 | self,
58 | content,
59 | send_digits=None,
60 | send_on_preanswer=None,
61 | sip_headers=None,
62 | ):
63 | super(UserElement, self).__init__()
64 |
65 | self.content = content
66 | self.send_digits = send_digits
67 | self.send_on_preanswer = send_on_preanswer
68 | self.sip_headers = sip_headers
69 |
70 | def to_dict(self):
71 | d = {
72 | 'sendDigits': self.send_digits,
73 | 'sendOnPreanswer': self.send_on_preanswer,
74 | 'sipHeaders': self.sip_headers,
75 | }
76 | return {
77 | k: six.text_type(map_type(v))
78 | for k, v in d.items() if v is not None
79 | }
80 |
--------------------------------------------------------------------------------
/plivo/xml/waitElement.py:
--------------------------------------------------------------------------------
1 | from plivo.utils.validators import *
2 | from plivo.xml import PlivoXMLElement, map_type
3 |
4 |
5 | class WaitElement(PlivoXMLElement):
6 | _name = 'Wait'
7 | _nestable = []
8 |
9 | @property
10 | def length(self):
11 | return self.__length
12 |
13 | @length.setter
14 | def length(self, value):
15 | self.__length = int(value) if value is not None else None
16 |
17 | @validate_args(
18 | value=[of_type(*six.integer_types)],
19 | )
20 | def set_length(self, value):
21 | self.length = value
22 | return self
23 |
24 | @property
25 | def silence(self):
26 | return self.__silence
27 |
28 | @silence.setter
29 | def silence(self, value):
30 | self.__silence = bool(value) if value is not None else None
31 |
32 | @validate_args(
33 | value=[of_type_exact(bool)],
34 | )
35 | def set_silence(self, value):
36 | self.silence = value
37 | return self
38 |
39 | @property
40 | def min_silence(self):
41 | return self.__min_silence
42 |
43 | @min_silence.setter
44 | def min_silence(self, value):
45 | self.__min_silence = int(value) if value is not None else None
46 |
47 | @validate_args(
48 | value=[of_type(*six.integer_types)],
49 | )
50 | def set_min_silence(self, value):
51 | self.min_silence = value
52 | return self
53 |
54 | @property
55 | def beep(self):
56 | return self.__beep
57 |
58 | @beep.setter
59 | def beep(self, value):
60 | self.__beep = bool(value) if value is not None else None
61 |
62 | @validate_args(
63 | value=[of_type_exact(bool)],
64 | )
65 | def set_beep(self, value):
66 | self.beep = value
67 | return self
68 |
69 | def __init__(
70 | self,
71 | length=None,
72 | silence=None,
73 | min_silence=None,
74 | beep=None,
75 | ):
76 | super(WaitElement, self).__init__()
77 |
78 | self.length = length
79 | self.silence = silence
80 | self.min_silence = min_silence
81 | self.beep = beep
82 |
83 | def to_dict(self):
84 | d = {
85 | 'length': self.length,
86 | 'silence': self.silence,
87 | 'minSilence': self.min_silence,
88 | 'beep': self.beep,
89 | }
90 | return {
91 | k: six.text_type(map_type(v))
92 | for k, v in d.items() if v is not None
93 | }
94 |
--------------------------------------------------------------------------------
/plivo/xml/xmlUtils.py:
--------------------------------------------------------------------------------
1 | import six
2 |
3 |
4 | def map_type(val):
5 | if isinstance(val, bool):
6 | return six.text_type(val).lower()
7 | return six.text_type(val)
8 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | decorator==5.1.1
2 | lxml==4.2.3
3 | requests==2.20.0
4 | six==1.10.0
5 | PyJWT==2.1.0
6 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal = 1
3 |
4 | [metadata]
5 | description-file = README.md
6 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import find_packages, setup
2 |
3 | long_description = '''\
4 | The Plivo Python SDK makes it simpler to integrate communications into your
5 | Python applications using the Plivo REST API. Using the SDK, you will be able
6 | to make voice calls, send SMS and generate Plivo XML to control your call flows.
7 |
8 | See https://github.com/plivo/plivo-python for more information.
9 | '''
10 |
11 | setup(
12 | name='plivo',
13 | version='4.59.1',
14 | description='A Python SDK to make voice calls & send SMS using Plivo and to generate Plivo XML',
15 | long_description=long_description,
16 | url='https://github.com/plivo/plivo-python',
17 | author='The Plivo SDKs Team',
18 | author_email='sdks@plivo.com',
19 | license='MIT',
20 | classifiers=[
21 | 'Development Status :: 5 - Production/Stable',
22 | 'Intended Audience :: Developers',
23 | 'Intended Audience :: Telecommunications Industry',
24 | 'License :: OSI Approved :: MIT License',
25 | 'Operating System :: OS Independent',
26 | 'Programming Language :: Python',
27 | 'Programming Language :: Python :: 2',
28 | 'Programming Language :: Python :: 2.7',
29 | 'Programming Language :: Python :: 3',
30 | 'Programming Language :: Python :: 3.4',
31 | 'Programming Language :: Python :: 3.5',
32 | 'Programming Language :: Python :: 3.6',
33 | 'Programming Language :: Python :: 3.7',
34 | 'Programming Language :: Python :: 3.8',
35 | 'Programming Language :: Python :: 3.9',
36 | 'Programming Language :: Python :: 3.11',
37 | 'Programming Language :: Python :: 3.13',
38 | 'Topic :: Software Development :: Libraries :: Python Modules',
39 | 'Topic :: Communications :: Telephony',
40 | ],
41 | install_requires=[
42 | 'requests >= 2, < 3',
43 | 'six >= 1, < 2',
44 | 'decorator >= 5',
45 | 'lxml >= 3',
46 | 'PyJWT'
47 | ],
48 | keywords=['plivo', 'plivo xml', 'voice calls', 'sms'],
49 | include_package_data=True,
50 | packages=find_packages(exclude=['tests', 'tests.*']), )
51 |
--------------------------------------------------------------------------------
/setup_sdk.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 | testDir="python-sdk-test"
5 | GREEN="\033[0;32m"
6 | NC="\033[0m"
7 |
8 | if [ ! $PLIVO_API_PROD_HOST ] || [ ! $PLIVO_API_DEV_HOST ] || [ ! $PLIVO_AUTH_ID ] || [ ! $PLIVO_AUTH_TOKEN ]; then
9 | echo "Environment variables not properly set! Please refer to Local Development section in README!"
10 | exit 126
11 | fi
12 |
13 | cd /usr/src/app
14 |
15 | echo "Setting plivo-api endpoint to dev..."
16 | find /usr/src/app/plivo/rest/ -type f -exec sed -i "s/$PLIVO_API_PROD_HOST/$PLIVO_API_DEV_HOST/g" {} \;
17 | find /usr/src/app/tests/ -type f -exec sed -i "s/$PLIVO_API_PROD_HOST/$PLIVO_API_DEV_HOST/g" {} \;
18 |
19 | if [ ! -d $testDir ]; then
20 | echo "Creating test dir..."
21 | mkdir -p $testDir
22 | fi
23 |
24 | if [ ! -f $testDir/test.py ]; then
25 | echo "Creating test file..."
26 | cd $testDir
27 | echo 'import sys' > test.py
28 | echo 'sys.path.append("../")' >> test.py
29 | echo 'import plivo' >> test.py
30 | cd -
31 | fi
32 |
33 | echo "Installing dependencies for testing..."
34 | pip install -r requirements.txt
35 | pip install tox coverage # For unit tests
36 | /bin/bash package.sh
37 |
38 | echo -e "\n\nSDK setup complete! You can test changes either on host or inside the docker container:"
39 | echo -e "\ta. To test your changes ON HOST:"
40 | echo -e "\t\t1. Add your test code in /$testDir/test.py"
41 | echo -e "\t\t2. Run your test file using: $GREEN make run CONTAINER=$HOSTNAME$NC"
42 | echo -e "\t\t3. Run unit tests using: $GREEN make test CONTAINER=$HOSTNAME$NC"
43 | echo
44 | echo -e "\tb. To test your changes INSIDE CONTAINER:"
45 | echo -e "\t\t1. Run a terminal in the container using: $GREEN docker exec -it $HOSTNAME /bin/bash$NC"
46 | echo -e "\t\t2. Add your test code in /usr/src/app/$testDir/test.py"
47 | echo -e "\t\t3. Run your test file using: $GREEN make run$NC"
48 | echo -e "\t\t4. Run unit tests using: $GREEN make test$NC"
49 |
50 | # To keep the container running post setup
51 | /bin/bash
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from .base import *
3 | from .resources import *
4 | from .decorators import *
5 | from .xml import *
--------------------------------------------------------------------------------
/tests/decorators.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import functools
3 | import io
4 | import json
5 | import os
6 |
7 |
8 | def with_response(status_code, method_name=None):
9 | def wrapper(func):
10 | @functools.wraps(func)
11 | def decorator(self, *args, **kwargs):
12 | name = method_name or func.__name__.replace('test_', '')
13 | name = self.__class__.__name__.replace('Test', '') + name.replace(
14 | '_', ' ').title().replace(' ', '')
15 | name = name[0].lower() + name[1:] + 'Response'
16 |
17 | path = os.path.abspath(
18 | os.path.join(
19 | os.path.dirname(__file__), 'resources', 'fixtures',
20 | name + '.json'))
21 |
22 | try:
23 | with io.open(path, encoding='utf-8') as f:
24 | self.expected_response = json.load(f)
25 | self.client.set_expected_response(
26 | status_code=status_code,
27 | data_to_return=self.expected_response)
28 | except IOError:
29 | if 'delete' in func.__name__:
30 | self.client.set_expected_response(
31 | data_to_return=None, status_code=status_code)
32 |
33 | func(self, *args, **kwargs)
34 |
35 | return decorator
36 |
37 | return wrapper
38 |
--------------------------------------------------------------------------------
/tests/resources/__init__.py:
--------------------------------------------------------------------------------
1 | from .test_applications import *
2 | from .test_accounts import *
3 | from .test_calls import *
4 | from .test_client import *
5 | from .test_conferences import *
6 | from .test_endpoints import *
7 | from .test_messages import *
8 | from .test_powerpacks import *
9 | from .test_medias import *
10 | from .test_multipartycalls import *
11 | from .test_numbers import *
12 | from .test_pricings import *
13 | from .test_recordings import *
14 | from .test_signature import *
15 | from .test_subaccounts import *
16 | from .test_brand import *
17 | from .test_campaign import *
18 | from .test_verify import *
--------------------------------------------------------------------------------
/tests/resources/fixtures/accountGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account_type": "standard",
3 | "address": "",
4 | "api_id": "95e1df78-3f08-11e7-8bc8-065f6a74a84a",
5 | "auth_id": "MAXXXXXXXXXXXXXXXXXX",
6 | "auto_recharge": false,
7 | "billing_mode": "prepaid",
8 | "cash_credits": "4.88860",
9 | "city": "",
10 | "name": "Sherlock Holmes",
11 | "resource_uri": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/",
12 | "state": "",
13 | "timezone": "Asia/Kolkata"
14 | }
15 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/accountUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "964edb6e-3f08-11e7-920b-0600a1193e9b",
3 | "message": "changed"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/addressCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "6b2784b3-b537-42be-89d1-f652783ed642",
3 | "message": "Your request has been accepted."
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/addressGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account": "MAXXXXXXXXXXXXXXXXXX",
3 | "address_line1": "128",
4 | "address_line2": "RUE DU COMMANDANT GUILBAUD",
5 | "alias": "test_address",
6 | "api_id": "08361d92-0b59-11e8-aa7e-02ad5072be3e",
7 | "city": "PARIS",
8 | "country_iso": "FR",
9 | "document_details": {
10 | "address_line1": "128",
11 | "address_line2": "RUE DU COMMANDANT GUILBAUD",
12 | "city": "PARIS",
13 | "first_name": "Bruce",
14 | "last_name": "Wayne",
15 | "postal_code": "75016",
16 | "region": "PARIS",
17 | "salutation": "Mr"
18 | },
19 | "first_name": "Bruce",
20 | "id": "20220771838737",
21 | "last_name": "Wayne",
22 | "postal_code": "75016",
23 | "region": "PARIS",
24 | "salutation": "Mr",
25 | "subaccount": null,
26 | "url": "https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Verification/Address/20220771838737/",
27 | "validation_status": "accepted",
28 | "verification_status": "pending"
29 | }
30 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/addressListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "af8b199a-0b58-11e8-b939-06755d68f0ca",
3 | "meta": {
4 | "limit": 1,
5 | "next": "https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Verification/Address/?limit=1&offset=1",
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 22
9 | },
10 | "objects": [
11 | {
12 | "account": "MAXXXXXXXXXXXXXXXXXX",
13 | "address_line1": "128",
14 | "address_line2": "RUE DU COMMANDANT GUILBAUD",
15 | "alias": "test_address",
16 | "city": "PARIS",
17 | "country_iso": "FR",
18 | "document_details": {
19 | "address_line1": "128",
20 | "address_line2": "RUE DU COMMANDANT GUILBAUD",
21 | "city": "PARIS",
22 | "first_name": "Bruce",
23 | "last_name": "Wayne",
24 | "postal_code": "75016",
25 | "region": "PARIS",
26 | "salutation": "Mr"
27 | },
28 | "first_name": "Bruce",
29 | "id": "20220771838737",
30 | "last_name": "Wayne",
31 | "postal_code": "75016",
32 | "region": "PARIS",
33 | "salutation": "Mr",
34 | "subaccount": null,
35 | "url": "https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Verification/Address/20220771838737/",
36 | "validation_status": "accepted",
37 | "verification_status": "pending"
38 | }
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/addressUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "6b2784b3-b537-42be-89d1-f652783ed642",
3 | "message": "Your request has been accepted.",
4 | "status": "success"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/applicationCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "99f9d6f6-3f08-11e7-9fd1-06660ad2b8e6",
3 | "app_id": "20468599130939380",
4 | "message": "created"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/applicationGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer_method": "POST",
3 | "answer_url": "http://www.google.com/",
4 | "api_id": "9ae358d0-3f08-11e7-b6f4-061564b78b75",
5 | "app_id": "20468599130939380",
6 | "app_name": "0.8522478089992022",
7 | "default_app": false,
8 | "default_endpoint_app": false,
9 | "enabled": true,
10 | "fallback_answer_url": "",
11 | "fallback_method": "POST",
12 | "hangup_method": "POST",
13 | "hangup_url": "http://www.google.com/",
14 | "message_method": "POST",
15 | "message_url": "",
16 | "public_uri": false,
17 | "resource_uri": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/Application/20468599130939380/",
18 | "sip_uri": "sip:20468599130939380@app.plivo.com",
19 | "sub_account": null
20 | }
21 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/applicationModifyResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "9b43ea74-3f08-11e7-8bc8-065f6a74a84a",
3 | "message": "changed"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/brandCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "7772d11a-0725-11ed-82e9-0242ac110004",
3 | "brand_id": "B43KNAS",
4 | "message": "Request to create brand was received and is being processed."
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/brandDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "Brand Deactivated",
3 | "brand_id": "BRPXS6E"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/brandGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "e1474046-0723-11ed-ab02-0242ac110004",
3 | "brand": {
4 | "address": {
5 | "city": "New York",
6 | "country": "IN",
7 | "postal_code": "10001",
8 | "state": "NY",
9 | "street": "123"
10 | },
11 | "authorized_contact": {
12 | "email": "test@plivo.com",
13 | "first_name": "John",
14 | "last_name": "Doe",
15 | "phone": "919074079045",
16 | "seniority": "admin",
17 | "title": "Doe"
18 | },
19 | "brand_id": "BOZ5T2X",
20 | "brand_type": "STARTER",
21 | "ein_issuing_country": "IN",
22 | "entity_type": "INDIVIDUAL",
23 | "profile_uuid": "6e9a16c7-27ae-44b4-8b1f-e6b9b007426b",
24 | "registration_status": "COMPLETED",
25 | "vertical": "ENERGY"
26 | }
27 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/brandGetUsecasesResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "use_cases": [
3 | {
4 | "name": "Account Notification",
5 | "code": "ACCOUNT_NOTIFICATION",
6 | "details": "Notification sent to account holders about changes in accounts"
7 | },
8 | {
9 | "name": "Customer Care",
10 | "code": "CUSTOMER_CARE",
11 | "details": "Customer care interactions by the support and other customer-facing teams"
12 | },
13 | {
14 | "name": "Delivery Notification",
15 | "code": "DELIVERY_NOTIFICATION",
16 | "details": "Updates about the delivery of products and services"
17 | },
18 | {
19 | "name": "Fraud Alert",
20 | "code": "FRAUD_ALERT",
21 | "details": "Notifications of suspicious behavior identified the business"
22 | },
23 | {
24 | "name": "Higher Education",
25 | "code": "HIGHER_EDUCATION",
26 | "details": "Messages sent by colleges, universities, and other educational institutions"
27 | },
28 | {
29 | "name": "Low Volume",
30 | "code": "LOW_VOLUME",
31 | "details": "A combination of two to five standard usage cases - for low throughput requirements"
32 | },
33 | {
34 | "name": "Marketing",
35 | "code": "MARKETING",
36 | "details": "Communications related to time-bound events and sales"
37 | },
38 | {
39 | "name": "Mixed",
40 | "code": "MIXED",
41 | "details": "A combination of two to five standard usage cases"
42 | },
43 | {
44 | "name": "Polling Voting",
45 | "code": "POLLING_VOTING",
46 | "details": "Surveys, polling, and voting campaigns used for non-political purposes"
47 | },
48 | {
49 | "name": "Public Service Announcement",
50 | "code": "PUBLIC_SERVICE_ANNOUNCEMENT",
51 | "details": "Messages aimed at creating awareness about important topics"
52 | },
53 | {
54 | "name": "Security Alert",
55 | "code": "SECURITY_ALERT",
56 | "details": "Notifications that alert users about a potential breach of systems"
57 | }
58 | ],
59 | "brand_id": "BRPXS6E",
60 | "api_id": "e1474046-0723-11ed-ab02-0242ac110004"
61 | }
62 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/callCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "call fired",
3 | "request_uuid": "9834029e-58b6-11e1-b8b7-a5bd0e4e126f",
4 | "api_id": "97ceeb52-58b6-11e1-86da-77300b68f8bb"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/callGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "answer_time": null,
3 | "api_id": "95727cf4-3eeb-11e7-8edf-02ed609bd62b",
4 | "bill_duration": 0,
5 | "billed_duration": 0,
6 | "call_direction": "outbound",
7 | "call_duration": 0,
8 | "call_uuid": "4d04c52e-cea3-4458-bbdb-0bfc314ee7cd",
9 | "end_time": "2017-05-22 17:49:40+05:30",
10 | "from_number": "+919879879876",
11 | "initiation_time": "2017-05-22 17:49:30+05:30",
12 | "parent_call_uuid": null,
13 | "resource_uri": "/v1/Account/MAJHUDTEYWLSIUYTDBCZ/Call/4d04c52e-cea3-4458-bbdb-0bfc314ee7cd/",
14 | "to_number": "919999999999",
15 | "total_amount": "0.00000",
16 | "total_rate": "0.03570"
17 | }
18 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/callListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "8299d094-dc72-11e5-b56c-22000ae90795",
3 | "meta": {
4 | "limit": 20,
5 | "next": null,
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 4
9 | },
10 | "objects": [{
11 | "answer_time": "2015-07-26 15:45:02+05:30",
12 | "api_id": "06ae0f8f-dc72-11e5-b56c-22000ae90795",
13 | "bill_duration": 924,
14 | "billed_duration": 960,
15 | "call_direction": "outbound",
16 | "call_duration": 924,
17 | "call_uuid": "eba53b9e-8fbd-45c1-9444-696d2172fbc8",
18 | "end_time": "2015-07-26 15:45:14+05:30",
19 | "from_number": "+14158572518",
20 | "initiation_time": "2015-07-26 15:44:49+05:30",
21 | "parent_call_uuid": null,
22 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Call/eba53b9e-8fbd-45c1-9444-696d2172fbc8/",
23 | "to_number": "14153268174",
24 | "total_amount": "0.13600",
25 | "total_rate": "0.00850"
26 | },
27 | {
28 | "answer_time": "2015-07-26 16:45:02+05:30",
29 | "api_id": "06ae0f8f-dc72-11e5-b56c-22000ae90795",
30 | "bill_duration": 924,
31 | "billed_duration": 960,
32 | "call_direction": "outbound",
33 | "call_duration": 924,
34 | "call_uuid": "eba53b9e-8fbd-45c1-9444-696d2172fbc8",
35 | "end_time": "2015-07-26 16:45:14+05:30",
36 | "from_number": "+14158572518",
37 | "initiation_time": "2015-07-26 16:44:49+05:30",
38 | "parent_call_uuid": null,
39 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Call/eba53b9e-8fbd-45c1-9444-696d2172fbc8/",
40 | "to_number": "14153268174",
41 | "total_amount": "0.13600",
42 | "total_rate": "0.00850"
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/callUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "call transfered",
3 | "api_id": "95727cf4-3eeb-11e7-86da-adf28403fe48"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "c520bd82-0725-11ed-82e9-0242ac110004",
3 | "campaign_id": "CAOHTU5",
4 | "message": "Request to create campaign was received and is being processed."
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "Campaign Deactivated",
3 | "campaign_id": "CUU5RCB"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignGetNumberResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "ca143ac8-072d-11ed-ab02-0242ac110004",
3 | "error": "The number xxxxxx is not linked to this campaign"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignGetNumbersResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "e50136b2-b168-11ec-80b6-0242ac110003",
3 | "campaign_alias": "marketing messages",
4 | "campaign_id": "CRIGC80",
5 | "phone_numbers": [
6 | {
7 | "number": "14845007032",
8 | "status": "PROCESSING"
9 | },
10 | {
11 | "number": "14844963797",
12 | "status": "COMPLETED"
13 | }
14 | ],
15 | "usecase": "MIXED"
16 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "f687a17e-0725-11ed-ab02-0242ac110004",
3 | "campaign": {
4 | "brand_id": "BOZ5T2X",
5 | "campaign_id": "CY5NVUA",
6 | "mno_metadata": {
7 | "AT&T": {
8 | "tpm": 15
9 | },
10 | "T-Mobile": {
11 | "brand_tier": "SOLE_PROPRIETOR"
12 | },
13 | "US Cellular": {
14 | "tpm": 15
15 | },
16 | "Verizon Wireless": {
17 | "tpm": 15
18 | }
19 | },
20 | "registration_status": "ACTIVE",
21 | "reseller_id": "",
22 | "sub_usecase": "2FA,MARKETING",
23 | "usecase": "STARTER",
24 | "campaign_source": "plivo"
25 | }
26 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignImportResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "2c6c5e16-090a-11ed-bb48-0242ac110004",
3 | "campaign_id": "CNTQ0OD",
4 | "message": "Request to import campaign was received and is being processed."
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignNumberLinkResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "5cd66c88-ba16-11ec-8e19-0242ac110003",
3 | "error": "The number xxxx is already requested for linking"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignNumberUnlinkResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "efd83afc-072d-11ed-ab02-0242ac110004",
3 | "error": "The number xxxxx is not a valid number"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/campaignUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "campaign": {
3 | "campaign_id": "CXNSG9W",
4 | "registration_status": "FAILED",
5 | "reseller_id": "",
6 | "brand_id": "BS2TTMI",
7 | "usecase": "MARKETING",
8 | "mno_metadata": {
9 | "AT&T": {
10 | "tpm": 4500
11 | },
12 | "T-Mobile": {
13 | "brand_tier": "TOP"
14 | },
15 | "US Cellular": {
16 | "tpm": 4500
17 | },
18 | "Verizon Wireless": {
19 | "tpm": 4500
20 | }
21 | },
22 | "sample1": "updated sample1 asdsdasdfasdsdasdf 2",
23 | "sample2": "sample message sdasdasdasdsdasdasda 2",
24 | "description": "campaign descriptioncampaign descriptioncampaign descriptioncampaign descriptioncampaign descriptioncampaign descriptioncampaign descriptioncampaign descriptioncampaign description",
25 | "campaign_attributes": {
26 | "embedded_link": false,
27 | "embedded_phone": false,
28 | "age_gated": false,
29 | "direct_lending": false,
30 | "subscriber_optin": false,
31 | "subscriber_optout": false,
32 | "subscriber_help": false,
33 | "affiliate_marketing": false
34 | },
35 | "message_flow": "message flowmessage flowmessage flowmessage flowmessage flowmessage flowmessage flowmessage flowmessage flow",
36 | "help_message": "help message 2help message 2help message 2help message 2help message 2help message 2help message 2help message 2",
37 | "help_keywords": "HELP UPDATE"
38 | }
39 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceDeleteAllResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "all conferences hung up",
3 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "conference hung up",
3 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "conference_name": "My Conf Room",
3 | "conference_run_time": "590",
4 | "conference_member_count": "1",
5 | "members": [{
6 | "muted": false,
7 | "member_id": "17",
8 | "deaf": false,
9 | "from": "1456789903",
10 | "to": "1677889900",
11 | "caller_name": "John",
12 | "direction": "inbound",
13 | "call_uuid": "acfbf0b5-12e0-4d74-85f7-fce15f8f07ec",
14 | "join_time": "590"
15 | }],
16 | "api_id": "816e903e-58c4-11e1-86da-adf28403fe48"
17 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48",
3 | "conferences": [
4 | "My Conf Room"
5 | ]
6 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceMemberDeafCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "deaf",
3 | "member_id": "10",
4 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceMemberDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "hangup",
3 | "member_id": "10",
4 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceMemberKickCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "kicked",
3 | "member_id": "10",
4 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceMemberMuteCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "muted",
3 | "member_id": "10",
4 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceMemberPlayCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "play queued into conference",
3 | "api_id": "4e44bd4e-f830-11e6-b886-067c5485c240",
4 | "member_id": "[u'160005', u'160004', u'160003', u'160002']"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceMemberPlayDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "playing in conference stopped",
3 | "member_id": "10",
4 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceMemberSpeakCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "speak queued into conference",
3 | "api_id": "8dd6820e-fe83-11e6-b6f4-061564b78b75",
4 | "member_id": "[u'all']"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceMemberSpeakDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "speak stopped",
3 | "member_id": "10",
4 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/conferenceRecordCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "2867b6e2-58c3-11e1-86da-adf28403fe48",
3 | "message": "conference recording started",
4 | "recording_id": "93bc7c6a-3b2b-11e3",
5 | "url": "http://s3.amazonaws.com/recordings_2013/93bc7c6a-3b2b-11e3.mp3"
6 | }
7 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/endpointCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "username": "zumba131031145958",
3 | "alias": "zumba",
4 | "message": "created",
5 | "endpoint_id": "37371860103666",
6 | "api_id": "1c13de4c-423d-11e3-9899-22000abfa5d5"
7 | }
8 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/endpointGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "alias": "callme",
3 | "application": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Application/33406267401237901/",
4 | "endpoint_id": "32866729519064",
5 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Endpoint/32866729519064/",
6 | "sip_contact": "sip:callme140703093224@122.172.71.207:57563;ob",
7 | "sip_expires": "2014-07-21 19:26:08",
8 | "sip_registered": "true",
9 | "sip_uri": "sip:callme140703093944@phone.plivo.com",
10 | "sip_user_agent": "Telephone 1.1.4",
11 | "sub_account": null,
12 | "username": "callme140703093944"
13 | }
14 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/endpointListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "30a0c8c2-110c-11e4-bd8a-12313f016a39",
3 | "meta": {
4 | "limit": 20,
5 | "next": null,
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 2
9 | },
10 | "objects": [
11 | {
12 | "alias": "callme",
13 | "application": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Application/33406267401237901/",
14 | "endpoint_id": "32866729519064",
15 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Endpoint/32866729519064/",
16 | "sip_contact": "sip:callme140703093224@122.172.71.207:57563;ob",
17 | "sip_expires": "2014-07-21 19:26:08",
18 | "sip_registered": "true",
19 | "sip_uri": "sip:callme140703093944@phone.plivo.com",
20 | "sip_user_agent": "Telephone 1.1.4",
21 | "sub_account": null,
22 | "username": "callme140703093944"
23 | },
24 | {
25 | "alias": "polycom",
26 | "application": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Application/37961981447734951/",
27 | "endpoint_id": "17551316589618",
28 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Endpoint/17551316589618/",
29 | "sip_registered": "false",
30 | "sip_uri": "sip:polycom140506175228@phone.plivo.com",
31 | "sub_account": null,
32 | "username": "polycom140506175448"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/endpointUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "changed",
3 | "api_id": "d8f9ea6c-58cc-11e1-86da-adf28403fe48"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/identityCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "a9318c3e-3fad-47d3-b78a-4d38d2288ff5",
3 | "message": "Your request has been accepted."
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/identityGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account": "MAXXXXXXXXXXXXXXXXXX",
3 | "alias": null,
4 | "api_id": "6e951a10-0b5a-11e8-a416-06f8d2f9b24c",
5 | "country_iso": "FR",
6 | "document_details": {
7 | "first_name": "Bruce",
8 | "id_number": "33522",
9 | "id_type": "passport",
10 | "last_name": "Wayne",
11 | "nationality": "FR",
12 | "salutation": "Mr"
13 | },
14 | "first_name": "Bruce",
15 | "id": "24856289978366",
16 | "id_number": "33522",
17 | "id_type": "passport",
18 | "last_name": "Wayne",
19 | "nationality": "FR",
20 | "salutation": "Mr",
21 | "subaccount": null,
22 | "url": "https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Verification/Identity/24856289978366/",
23 | "validation_status": "pending",
24 | "verification_status": "pending"
25 | }
26 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/identityListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "3c294e0c-0b5a-11e8-9ad8-064c8d7b2d26",
3 | "meta": {
4 | "limit": 1,
5 | "next": "https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Verification/Identity/?limit=1&offset=1",
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 6
9 | },
10 | "objects": [
11 | {
12 | "account": "MAXXXXXXXXXXXXXXXXXX",
13 | "alias": null,
14 | "country_iso": "FR",
15 | "document_details": {
16 | "first_name": "Bruce",
17 | "id_number": "33522",
18 | "id_type": "passport",
19 | "last_name": "Wayne",
20 | "nationality": "FR",
21 | "salutation": "Mr"
22 | },
23 | "first_name": "Bruce",
24 | "id": "24856289978366",
25 | "id_number": "33522",
26 | "id_type": "passport",
27 | "last_name": "Wayne",
28 | "nationality": "FR",
29 | "salutation": "Mr",
30 | "subaccount": null,
31 | "url": "https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Verification/Identity/24856289978366/",
32 | "validation_status": "pending",
33 | "verification_status": "pending"
34 | }
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/identityUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "3a869c12-f65a-42e9-a455-9919a42dbd89",
3 | "message": "Your request has been accepted.",
4 | "status": "success"
5 | }
6 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallDtmfCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "digits sent",
3 | "api_id": "07abfd94-58c0-11e1-86da-adf28403fe48"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "18f3bbb0-3ef1-11e7-a68e-02d2f90c026e",
3 | "call_status": "in-progress",
4 | "call_uuid": "d0a87a1a-b0e9-4ab2-ac07-c22ee87cd04a",
5 | "caller_name": "",
6 | "direction": "outbound",
7 | "from": "+918687888990",
8 | "request_uuid": "d0a87a1a-b0e9-4ab2-ac07-c22ee87cd04a",
9 | "session_start": "2017-05-22 13:17:49.050872",
10 | "to": "919798990001"
11 | }
12 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallListGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "b251cbd6-3ef0-11e7-a51d-0245fa790d9e",
3 | "calls": [
4 | "5bd78c3c-5020-4a32-a495-3af5a765ded5"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallPlayCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "play started",
3 | "api_id": "69487be8-3ef4-11e7-a51d-0245fa790d9e"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallRecordCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "http://s3.amazonaws.com/recordings_2013/48dfaf60-3b2a-11e3.mp3",
3 | "message": "call recording started",
4 | "recording_id": "48dfaf60-3b2a-11e3",
5 | "api_id": "c7b69074-58be-11e1-86da-adf28403fe48"
6 | }
7 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallSpeakCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "speak started",
3 | "api_id": "4d14465e-3ef5-11e7-a68e-02d2f90c026e"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallSpeakDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "speak stopped",
3 | "api_id": "908173d0-3ef5-11e7-a68e-02d2f90c026e"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallStreamCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "ff09383e-246f-11ed-a1fe-0242ac110004",
3 | "message": "audio streaming started",
4 | "stream_id": "30852c23-ee79-4eb4-b7b9-cd360545965b"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallStreamDeleteAllResponse.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/tests/resources/fixtures/liveCallStreamGetAllResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "8d1d27f0-24f8-11ed-8311-0242ac11000b",
3 | "meta": {
4 | "count": 1,
5 | "limit": 20,
6 | "next": null,
7 | "offset": 0,
8 | "previous": null
9 | },
10 | "objects": [
11 | {
12 | "call_uuid": "4f045f7a-b04a-4364-8523-74e6072f4f72",
13 | "end_time": null,
14 | "service_url": "ws://3ee3-106-51-87-58.ngrok.io",
15 | "start_time": null,
16 | "status": "initiated",
17 | "status_callback_url": "",
18 | "stream_id": "c436abf8-e8a1-4d96-9aa8-b9143f7f3517"
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/lookupGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "a35a2e7a-fd27-42e6-910c-33382f43240e",
3 | "phone_number": "+14154305555",
4 | "country": {
5 | "name": "United States",
6 | "iso2": "US",
7 | "iso3": "USA"
8 | },
9 | "format": {
10 | "e164": "+14154305555",
11 | "national": "(415) 430-5555",
12 | "international": "+1 415-430-5555",
13 | "rfc3966": "tel:+1-415-430-5555"
14 | },
15 | "carrier": {
16 | "mobile_country_code": "310",
17 | "mobile_network_code": "150",
18 | "name": "Cingular Wireless",
19 | "type": "mobile",
20 | "ported": "yes"
21 | },
22 | "resource_uri": "/v1/Number/+14154305555?type=carrier"
23 | }
24 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/maskingSessionCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "7fef62d3-a451-40ef-95e7-b4ad9969aa1e",
3 | "session_uuid": "bc0a20bb-9f09-4116-b3f8-709def3a89df",
4 | "virtual_number": "+916361728680",
5 | "message": "Session created",
6 | "session": {
7 | "first_party": "917708772011",
8 | "second_party": "919976106830",
9 | "virtual_number": "916361728680",
10 | "status": "active",
11 | "initiate_call_to_first_party": false,
12 | "session_uuid": "bc0a20bb-9f09-4116-b3f8-709def3a89df",
13 | "callback_url": "https://s3.amazonaws.com/static.plivo.com/callback.xml",
14 | "callback_method": "GET",
15 | "created_time": "2023-07-12 15:52:14.772699 +0000 UTC",
16 | "modified_time": "2023-07-12 15:52:14.772699 +0000 UTC",
17 | "expiry_time": "2023-07-12 17:32:14.772699 +0000 UTC",
18 | "duration": 6000,
19 | "amount": 0,
20 | "call_time_limit": 14400,
21 | "ring_timeout": 120,
22 | "first_party_play_url": "https://s3.amazonaws.com/plivosamplexml/play_url.xml",
23 | "second_party_play_url": "https://s3.amazonaws.com/plivosamplexml/play_url.xml",
24 | "record": false,
25 | "record_file_format": "mp3",
26 | "recording_callback_url": "https://s3.amazonaws.com/static.plivo.com/callback.xml",
27 | "recording_callback_method": "GET",
28 | "interaction": null,
29 | "total_call_amount": 0,
30 | "total_call_count": 0,
31 | "total_call_billed_duration": 0,
32 | "total_session_amount": 0,
33 | "last_interaction_time": "",
34 | "is_pin_authentication_required": true,
35 | "generate_pin": false,
36 | "generate_pin_length": 4,
37 | "first_party_pin": "1234",
38 | "second_party_pin": "1235",
39 | "pin_prompt_play": "https://s3.amazonaws.com/plivosamplexml/pin_prompt_play_url.xml",
40 | "pin_retry": 2,
41 | "pin_retry_wait": 5,
42 | "incorrect_pin_play": "https://s3.amazonaws.com/plivosamplexml/incorrect_play_url.xml",
43 | "unknown_caller_play": "https://s3.amazonaws.com/plivosamplexml/unknown_play_url.xml"
44 | }
45 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/maskingSessionDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "f91f459a-283d-4850-9b33-ad914dcb64c0",
3 | "message": "Session Deleted"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/maskingSessionGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "b503c0b9-a419-406f-8e49-9856844600ab",
3 | "response": {
4 | "first_party": "917708772011",
5 | "second_party": "919976106830",
6 | "virtual_number": "916361728680",
7 | "status": "active",
8 | "initiate_call_to_first_party": false,
9 | "session_uuid": "c2146ba4-798d-49b0-8580-53851a16e055",
10 | "callback_url": "https://s3.amazonaws.com/static.plivo.com/callback.xml",
11 | "callback_method": "GET",
12 | "created_time": "2023-07-05 10:25:40.877364 +0000 UTC",
13 | "modified_time": "2023-07-05 10:25:40.877364 +0000 UTC",
14 | "expiry_time": "2023-07-05 12:05:40.877364 +0000 UTC",
15 | "duration": 6000,
16 | "amount": 0,
17 | "call_time_limit": 14400,
18 | "ring_timeout": 120,
19 | "first_party_play_url": "https://s3.amazonaws.com/plivosamplexml/play_url.xml",
20 | "second_party_play_url": "https://s3.amazonaws.com/plivosamplexml/play_url.xml",
21 | "record": false,
22 | "record_file_format": "mp3",
23 | "recording_callback_url": "https://s3.amazonaws.com/static.plivo.com/callback.xml",
24 | "recording_callback_method": "GET",
25 | "interaction": null,
26 | "total_call_amount": 0,
27 | "total_call_count": 0,
28 | "total_call_billed_duration": 0,
29 | "total_session_amount": 0,
30 | "last_interaction_time": ""
31 | }
32 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/maskingSessionUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "b5506536-83d0-498f-929f-4427cb6ca391",
3 | "message": "Session updated",
4 | "session": {
5 | "first_party": "917708772011",
6 | "second_party": "919976106830",
7 | "virtual_number": "916361728680",
8 | "status": "active",
9 | "initiate_call_to_first_party": false,
10 | "session_uuid": "7b5c5e17-e1e9-4ccd-a480-42f5c97fbe96",
11 | "callback_url": "https://s3.amazonaws.com/static.plivo.com/callback.xml",
12 | "callback_method": "GET",
13 | "created_time": "2023-07-06 10:53:32.814078 +0000 +0000",
14 | "modified_time": "2023-07-06 10:53:45.106122 +0000 UTC",
15 | "expiry_time": "2023-07-06 11:03:45.106117 +0000 UTC",
16 | "duration": 612,
17 | "amount": 0,
18 | "call_time_limit": 14600,
19 | "ring_timeout": 120,
20 | "first_party_play_url": "https://s3.amazonaws.com/plivosamplexml/play_url.xml",
21 | "second_party_play_url": "https://s3.amazonaws.com/plivosamplexml/play_url.xml",
22 | "record": true,
23 | "record_file_format": "mp3",
24 | "recording_callback_url": "https://s3.amazonaws.com/static.plivo.com/callback.xml",
25 | "recording_callback_method": "GET",
26 | "interaction": null,
27 | "total_call_amount": 0,
28 | "total_call_count": 0,
29 | "total_call_billed_duration": 0,
30 | "total_session_amount": 0,
31 | "last_interaction_time": ""
32 | }
33 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/mediaGetMediaResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "292437c0-e5a3-11e9-b521-0242ac110003",
3 | "content_type": "image/gif",
4 | "file_name": "SampleFile.png",
5 | "media_id": "91f8f9ce-e236-474f-a2b8-f75d9c35988a",
6 | "size": 700670,
7 | "upload_time": "2020-02-17T07:53:36.643522Z",
8 | "media_url": "https://media.plivo.com/Account/MAODZKMDFJMJU3MTEYNG/Media/91f8f9ce-e236-474f-a2b8-f75d9c35988a"
9 | }
10 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/mediaListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "95e98e4a-e5a4-11e9-b521-0242ac110003",
3 | "meta": {
4 | "limit": 20,
5 | "next": "/v1/Account//Media?offset=20&limit=20",
6 | "offset": 0,
7 | "previous": "/v1/Account//Media?offset=0&limit=20",
8 | "total_count": 44
9 | },
10 | "objects": [{
11 | "content_type": "image/gif",
12 | "media_id": "91f8f9ce-e236-474f-a2b8-f75d9c35988a",
13 | "media_url": "http://127.0.0.1:80/media/MAODZKMDFJMJU3MTEYNG/f734eeec-e59f-11e9-89dc-0242ac110003/91f8f9ce-e236-474f-a2b8-f75d9c35988a",
14 | "message_uuid": "f734eeec-e59f-11e9-89dc-0242ac110003",
15 | "size": 766424
16 | },
17 | {
18 | "content_type": "image/jpeg",
19 | "media_id": "455a2f85-acd5-4bb7-9a6a-a7b7341cd592",
20 | "media_url": "http://127.0.0.1:80/media/MAODZKMDFJMJU3MTEYNG/f734eeec-e59f-11e9-89dc-0242ac110003/455a2f85-acd5-4bb7-9a6a-a7b7341cd592",
21 | "message_uuid": "f734eeec-e59f-11e9-89dc-0242ac110003",
22 | "size": 47343
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/messageGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "95747262-3f08-11e7-8bc8-065f6a74a84a",
3 | "error_code": null,
4 | "from_number": "911231231230",
5 | "message_direction": "outbound",
6 | "message_state": "sent",
7 | "message_time": "2017-05-22 21:36:14+05:30",
8 | "message_type": "sms",
9 | "message_uuid": "5b40a428-bfc7-4daf-9d06-726c558bf3b8",
10 | "resource_uri": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/Message/5b40a428-bfc7-4daf-9d06-726c558bf3b8/",
11 | "to_number": "911231231231",
12 | "total_amount": "0.00250",
13 | "total_rate": "0.00250",
14 | "units": 1,
15 | "message_sent_time": "2024-08-21 18:28:49.244057+05:30",
16 | "message_updated_time": "2024-08-21 18:28:51.94772+05:30",
17 | "error_message": ""
18 | }
19 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/messageListMediaResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "035eeada-6df1-11e6-b608-06a72a185e87",
3 | "message_uuid": "message_uuid",
4 | "objects": [
5 | {
6 | "content_type": "application/pdf",
7 | "media_id": "0178eb8a-461a-4fd1-bc37-13eebfdc0676",
8 | "media_url": "https://media.plivo.com/Account/{auth_id}/Message/24d742b9-9b12-4397-93a7-da496bc874d9/Media/0178eb8a-461a-4fd1-bc37-13eebfdc0676",
9 | "message_uuid": "24d742b9-9b12-4397-93a7-da496bc874d9",
10 | "size": 433994
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/messageSendResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "948b53a2-3f08-11e7-b6f4-061564b78b75",
3 | "message": "message(s) queued",
4 | "message_uuid": [
5 | "5b40a428-bfc7-4daf-9d06-726c558bf3b8"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsAddParticipantResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "bfe372c0-b451-11ea-815a-1094bbeb5c2c",
3 | "calls": [
4 | {
5 | "to": "917702643094",
6 | "from": "918888888888",
7 | "call_uuid": "0b7b4242-8ee8-4872-b447-81b4ce972eae"
8 | },
9 | {
10 | "to": "919629342168",
11 | "from": "918888888888",
12 | "call_uuid": "67c882e3-833b-4eb8-bdbc-6efcb806938a"
13 | }
14 | ],
15 | "message": "add participant action initiated",
16 | "request_uuid": "8420cdb1-f1d8-44a4-8c2a-556d156f1ffa"
17 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsEndMpcResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "6cbdc5b1-9aa9-11ea-ad7f-0242ac110005",
3 | "message": "MPC: Voice kick member(s) succeeded",
4 | "request_uuid": "75fecf73-7f77-404f-adc6-7d4a73d9a40d"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsGetParticipantResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "07a25e47-c1e3-11ea-ae24-0242ac110004",
3 | "billed_amount": 0.00500,
4 | "billed_duration": 60,
5 | "call_uuid": "90de6710-9404-40d1-ba31-f26d2f7c533f",
6 | "coach_mode": null,
7 | "duration": 30,
8 | "end_mpc_on_exit": false,
9 | "exit_cause": "Participant Call Hangup",
10 | "exit_time": "2020-07-09 07:25:07+00:00",
11 | "hold": null,
12 | "join_time": "2020-07-09 07:24:37+00:00",
13 | "member_id": "49",
14 | "mpc_uuid": "18905d56-79c8-41d4-a840-25feff71070e",
15 | "mute": null,
16 | "resource_uri": "/v1/Account/MA123456789012345678/MultiPartyCall/uuid_18905d56-79c8-41d4-a840-25feff71070e/Participant/49/",
17 | "role": "customer",
18 | "start_mpc_on_enter": true
19 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsKickMpcParticipantResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "6cbdc5b1-9aa9-11ea-ad7f-0242ac110005",
3 | "message": "MPC: Voice kick member(s) succeeded",
4 | "request_uuid": "75fecf73-7f77-404f-adc6-7d4a73d9a40d"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsStartMpcResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "6cbdc5b1-9aa9-11ea-ad7f-0242ac110005",
3 | "message": "MPC: Voice started",
4 | "request_uuid": "75fecf73-7f77-404f-adc6-7d4a73d9a40d"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsStartParticipantRecordingResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "e05b5263-45dc-11eb-9014-0242ac110003",
3 | "message": "MPC: test_mpc_1 record started",
4 | "recording_id": "e06ac332-45dc-11eb-94fe-06dd7f581a50",
5 | "recording_url": "https://media.plivo.com/v1/Account/MAOTE1OWE0MDK0MTLHYW/Recording/e06ac332-45dc-11eb-94fe-06dd7f581a50.mp3"
6 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsStartPlayAudioResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "325a5d1c-4380-11ec-b094-0242ac11000f",
3 | "message": "play queued into MPC",
4 | "mpcMemberId": [
5 | "48"
6 | ],
7 | "mpcName": "MyMPC"
8 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsStartRecordingResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "6cbdc5b1-9aa9-11ea-ad7f-0242ac110005",
3 | "message": "MPC: Voice started recording",
4 | "request_uuid": "75fecf73-7f77-404f-adc6-7d4a73d9a40d"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/multiPartyCallsUpdateMpcParticipantResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "6cbdc5b1-9aa9-11ea-ad7f-0242ac110005",
3 | "message": {
4 | "coach_mode": "MPC: %s coach_mode enable/disable succeeded",
5 | "mute": "MPC: %s mute/unmute member(s) succeeded"
6 | },
7 | "request_uuid": "75fecf73-7f77-404f-adc6-7d4a73d9a40d"
8 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/numberCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "changed",
3 | "api_id": "5a9fcb68-582d-11e1-86da-6ff39efcb949"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/numberGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "added_on": "2014-02-14",
3 | "active": false,
4 | "alias": null,
5 | "api_id": "88625e5e-1c92-11e4-80aa-12313f048015",
6 | "application": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Application/29986316244302815/",
7 | "carrier": "Plivo",
8 | "monthly_rental_rate": "0.80000",
9 | "number": "17609915566",
10 | "number_type": "local",
11 | "city": "USA",
12 | "cnam_lookup": "enabled",
13 | "compliance_application_id": null,
14 | "compliance_status": null,
15 | "country": "United States",
16 | "mms_enabled": false,
17 | "mms_rate": "0.00000",
18 | "tendlc_campaign_id": null,
19 | "tendlc_registration_status": "UNREGISTERED",
20 | "toll_free_sms_verification": null,
21 | "renewal_date": "2014-03-14",
22 | "region": "California, UNITED STATES",
23 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Number/17609915566/",
24 | "sms_enabled": true,
25 | "sms_rate": "0.00000",
26 | "sub_account": null,
27 | "voice_enabled": true,
28 | "voice_rate": "0.00850"
29 | }
30 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/numberUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "changed",
3 | "api_id": "5a9fcb68-582d-11e1-86da-6ff39efcb949"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/numberpoolListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "21a04c42-d229-11e9-b61e-0242ac110007",
3 | "meta": {
4 | "limit": 20,
5 | "next": "",
6 | "offset": 0,
7 | "previous": "",
8 | "total_count": 1
9 | },
10 | "objects": [{
11 | "account_phone_number_resource": "/v1/Account/MAODZKMDFJMJU3MTEYNG/Number/15799140348/",
12 | "added_on": "2019-09-03T08:50:09.578928Z",
13 | "country_iso2": "CA",
14 | "number": "15799140348",
15 | "number_pool_uuid": "659c7f88-c819-46e2-8af4-2d8a84249099",
16 | "type": "fixed"
17 | }]
18 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/numberpoolResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account_phone_number_resource": "/v1/Account/MAODZKMDFJMJU3MTEYNG/Number/15799140348/",
3 | "added_on": "2019-09-03T08:50:09.578928Z",
4 | "api_id": "81ca9d16-d229-11e9-b61e-0242ac110007",
5 | "country_iso2": "CA",
6 | "number": "15799140348",
7 | "numberpool_uuid": "659c7f88-c819-46e2-8af4-2d8a84249099",
8 | "type": "fixed"
9 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/phlosMemberMemberActionsResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "status": ""
3 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/phlosMemberMemberActionsValidationResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "status": ""
3 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/phlosMemberPhloGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "status": ""
3 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/phlosMemberPhloGetValidationResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "status": ""
3 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/phoneNumberCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "aa52882c-1c88-11e4-bd8a-12313f016a39",
3 | "message": "created",
4 | "numbers": [
5 | {
6 | "number": "14154009186",
7 | "status": "Success"
8 | }
9 | ],
10 | "status": "fulfilled"
11 | }
12 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/phoneNumberListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "859428b0-1c88-11e4-a2d1-22000ac5040c",
3 | "meta": {
4 | "limit": 20,
5 | "next": null,
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 9
9 | },
10 | "objects": [
11 | {
12 | "country": "UNITED STATES",
13 | "lata": 722,
14 | "monthly_rental_rate": "0.80000",
15 | "number": "14154009186",
16 | "type": "fixed",
17 | "prefix": "415",
18 | "rate_center": "SNFC CNTRL",
19 | "region": "United States",
20 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/PhoneNumber/14154009186/",
21 | "restriction": null,
22 | "restriction_text": null,
23 | "setup_rate": "0.00000",
24 | "sms_enabled": true,
25 | "sms_rate": "0.00800",
26 | "voice_enabled": true,
27 | "voice_rate": "0.00500",
28 | "prerequisites": [{"proof_required": true,
29 | "proof_type": [ "Any" ],
30 | "scope": "country",
31 | "type": "address"}]
32 | },
33 | {
34 | "country": "UNITED STATES",
35 | "lata": 722,
36 | "monthly_rental_rate": "0.80000",
37 | "number": "14154009187",
38 | "type": "fixed",
39 | "prefix": "415",
40 | "rate_center": "SNFC CNTRL",
41 | "region": "United States",
42 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/PhoneNumber/14154009187/",
43 | "restriction": null,
44 | "restriction_text": null,
45 | "setup_rate": "0.00000",
46 | "sms_enabled": true,
47 | "sms_rate": "0.00800",
48 | "voice_enabled": true,
49 | "voice_rate": "0.00500"
50 | }
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackAddNumberResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account_phone_number_resource": "/v1/Account//Number//",
3 | "added_on": "2019-10-09T11:24:35.085797Z",
4 | "api_id": "612982e8-0a87-11ea-b072-0242ac110007",
5 | "country_iso2": "CA",
6 | "number": "15799140336",
7 | "uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
8 | "number_pool_uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
9 | "number_pool": "/v1/Account/MAODZKMDFJMJU3MTEYNG/NumberPool/ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f/",
10 | "type": "fixed"
11 | }
12 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackAddTollfreeResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account_phone_number_resource": "/v1/Account//Number//",
3 | "added_on": "2019-10-09T11:24:35.085797Z",
4 | "api_id": "612982e8-0a87-11ea-b072-0242ac110007",
5 | "country_iso2": "CA",
6 | "number": "15799140336",
7 | "uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
8 | "number_pool_uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
9 | "number_pool": "/v1/Account/MAODZKMDFJMJU3MTEYNG/NumberPool/ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f/",
10 | "type": "fixed"
11 | }
12 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackBuyAndNumberResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account_phone_number_resource": "/v1/Account//Number//",
3 | "added_on": "2019-10-09T11:24:35.085797Z",
4 | "api_id": "612982e8-0a87-11ea-b072-0242ac110007",
5 | "country_iso2": "CA",
6 | "number": "14845071864",
7 | "uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
8 | "number_pool_uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
9 | "number_pool": "/v1/Account/MAODZKMDFJMJU3MTEYNG/NumberPool/ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f/",
10 | "type": "fixed"
11 | }
12 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackCountNumbersResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account_phone_number_resource": "/v1/Account//Number//",
3 | "added_on": "2019-10-09T11:24:35.085797Z",
4 | "api_id": "612982e8-0a87-11ea-b072-0242ac110007",
5 | "country_iso2": "CA",
6 | "uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
7 | "number_pool_uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
8 | "number_pool": "/v1/Account/MAODZKMDFJMJU3MTEYNG/NumberPool/ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f/",
9 | "api_id": "0dacbefa-0a87-11ea-b072-0242ac110007",
10 | "meta": {
11 | "limit": 20,
12 | "next": "",
13 | "offset": 0,
14 | "previous": "",
15 | "total_count": 6
16 | },
17 | "objects": [
18 | {
19 | "account_phone_number_resource": "/v1/Account/{auth_id}/Number/{your_number}/",
20 | "added_on": "2019-10-09T11:24:35.085797Z",
21 | "country_iso2": "US",
22 | "number": "{your_number}",
23 | "number_pool_uuid": "{number_pool_uuid}",
24 | "type": "fixed"
25 | },
26 | {
27 | "account_phone_number_resource": "/v1/Account/{auth_id}/Number/{your_number}/",
28 | "added_on": "2019-10-09T11:24:35.085797Z",
29 | "country_iso2": "US",
30 | "number": "{your_number}",
31 | "number_pool_uuid": "{number_pool_uuid}",
32 | "type": "fixed"
33 | },
34 | {
35 | "account_phone_number_resource": "/v1/Account/{auth_id}/Number/{your_number}/",
36 | "added_on": "2019-10-09T11:24:35.085797Z",
37 | "country_iso2": "CA",
38 | "number": "{your_number}",
39 | "number_pool_uuid": "{number_pool_uuid}",
40 | "type": "fixed"
41 | }
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackCreatePowerpackResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "4b2c83c4-09ff-11ea-b072-0242ac110007",
3 | "application_id": "20342783288007824",
4 | "application_type": "XML",
5 | "created_on": "2019-10-09T11:10:59.666461Z",
6 | "local_connect": true,
7 | "name": "test",
8 | "number_pool": "/v1/Account/{auth_id}/NumberPool//",
9 | "sticky_sender": true,
10 | "uuid": ""
11 | }
12 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackDeletePowerpackResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "uuid": "dfsd-fsdfsd-345dfsd-fsdfs-sdfsd",
3 | "name": "My Powerpack",
4 | "smart_sender": true,
5 | "local_connect": false,
6 | "application_type": "XML",
7 | "application_id": 123912833468,
8 | "number_pool": "/v1/Account/{auth_id}/NumberPool//",
9 | "created_on": "2019-07-15T12:22:00Z"
10 | }
11 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "964edb6e-3f08-11e7-920b-0600a1193e9b",
3 | "response": "success"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackFindShortcodeResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "614b2776-0a88-11ea-b072-0242ac110007",
3 | "number_pool": "/v1/Account/{auth_id}/NumberPool//",
4 | "uuid": "dfsd-fsdfsd-345dfsd-fsdfs-sdfsd",
5 | "meta": {
6 | "limit": 20,
7 | "next": "",
8 | "offset": 0,
9 | "previous": "",
10 | "total_count": 1
11 | },
12 | "objects": [
13 | {
14 | "added_on": "2019-10-09T11:10:59.741978Z",
15 | "country_iso2": "US",
16 | "number_pool_uuid": "{number_pool_uuid}",
17 | "shortcode": "444444"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackFindTollfreeResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "614b2776-0a88-11ea-b072-0242ac110007",
3 | "number_pool": "/v1/Account/{auth_id}/NumberPool//",
4 | "uuid": "dfsd-fsdfsd-345dfsd-fsdfs-sdfsd",
5 | "meta": {
6 | "limit": 20,
7 | "next": "",
8 | "offset": 0,
9 | "previous": "",
10 | "total_count": 1
11 | },
12 | "objects": [
13 | {
14 | "added_on": "2019-10-09T11:10:59.741978Z",
15 | "country_iso2": "US",
16 | "number_pool_uuid": "{number_pool_uuid}",
17 | "tollfree": "18772209942"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackGetPowerpackResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "uuid": "5ec4c8c9-cd74-42b5-9e41-0d7670d6bb46",
3 | "name": "My Powerpack",
4 | "smart_sender": true,
5 | "local_connect": false,
6 | "application_type": "XML",
7 | "application_id": 123912833468,
8 | "number_pool": "/v1/Account/{auth_id}/NumberPool//",
9 | "created_on": "2019-07-15T12:22:00Z"
10 | }
11 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackListNumbersResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "0dacbefa-0a87-11ea-b072-0242ac110007",
3 | "uuid": "d35f2e82-d387-427f-8594-6fa07613c43a",
4 | "number_pool": "/v1/Account/{auth_id}/NumberPool/d35f2e82-d387-427f-8594-6fa07613c43a/",
5 | "meta": {
6 | "limit": 20,
7 | "next": "",
8 | "offset": 0,
9 | "previous": "",
10 | "total_count": 3
11 | },
12 | "objects": [
13 | {
14 | "account_phone_number_resource": "/v1/Account/{auth_id}/Number/{your_number}/",
15 | "added_on": "2019-10-09T11:24:35.085797Z",
16 | "country_iso2": "US",
17 | "number": "{your_number}",
18 | "number_pool_uuid": "d35f2e82-d387-427f-8594-6fa07613c43a",
19 | "type": "fixed"
20 | },
21 | {
22 | "account_phone_number_resource": "/v1/Account/{auth_id}/Number/{your_number}/",
23 | "added_on": "2019-10-09T11:24:35.085797Z",
24 | "country_iso2": "US",
25 | "number": "{your_number}",
26 | "number_pool_uuid": "d35f2e82-d387-427f-8594-6fa07613c43a",
27 | "type": "fixed"
28 | },
29 | {
30 | "account_phone_number_resource": "/v1/Account/{auth_id}/Number/{your_number}/",
31 | "added_on": "2019-10-09T11:24:35.085797Z",
32 | "country_iso2": "CA",
33 | "number": "{your_number}",
34 | "number_pool_uuid": "d35f2e82-d387-427f-8594-6fa07613c43a",
35 | "type": "fixed"
36 | }
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackListPowerpackResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "e44c159e-0a02-11ea-b072-0242ac110007",
3 | "meta": {
4 | "limit": 20,
5 | "next": "/api/v1/account/xxxxxxx/Powerpack?offset=20&limit=20",
6 | "offset": 0,
7 | "total_count": 53
8 | },
9 | "objects": [
10 | {
11 | "application_id": "",
12 | "application_type": "",
13 | "created_on": "2019-10-09T11:10:59.666461Z",
14 | "local_connect": true,
15 | "name": "test",
16 | "number_pool": "/v1/Account/xxxxxxxxx/NumberPool//",
17 | "sticky_sender": true,
18 | "uuid": ""
19 | },
20 | {
21 | "application_id": "",
22 | "application_type": "",
23 | "created_on": "2019-10-09T17:03:31.837944Z",
24 | "local_connect": false,
25 | "name": "p23",
26 | "number_pool": "/v1/Account/xxxxxxxx/NumberPool//",
27 | "sticky_sender": false,
28 | "uuid": ""
29 | },
30 | {
31 | "application_id": "",
32 | "application_type": "",
33 | "created_on": "2019-10-09T16:54:34.0117Z",
34 | "local_connect": false,
35 | "name": "p22",
36 | "number_pool": "/v1/Account/xxxxxxxx/NumberPool//",
37 | "sticky_sender": false,
38 | "uuid": ""
39 | }
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "ff25223a-1c9f-11e4-80aa-12313f048015",
3 | "meta": {
4 | "limit": 20,
5 | "next": null,
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 0
9 | },
10 | "objects": [
11 | {
12 | "application_id": "33660394121755210",
13 | "application_type": "XML",
14 | "created_on": "2019-09-03T08:50:09.510692Z",
15 | "local_connect": false,
16 | "name": "vishnu_sep_01",
17 | "number_pool": "/v1/Account/MAODZKMDFJMJU3MTEYNG/NumberPool/659c7f88-c819-46e2-8af4-2d8a84249099/",
18 | "sticky_sender": true,
19 | "uuid": "86bbb125-97bb-4d72-89fd-81d5c515b015"
20 | },
21 | {
22 | "application_id": "",
23 | "application_type": "",
24 | "created_on": "2019-09-03T18:35:19.548601Z",
25 | "local_connect": true,
26 | "name": "Neel_ppk_sdk-14",
27 | "number_pool": "/v1/Account/MAODZKMDFJMJU3MTEYNG/NumberPool/13611cea-d86d-4da9-b70a-37f47478b5c0/",
28 | "sticky_sender": true,
29 | "uuid": "70f8c51f-2700-4067-9101-f177a98ec65d"
30 | }
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackListShortcodeResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "614b2776-0a88-11ea-b072-0242ac110007",
3 | "uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
4 | "number_pool": "/v1/Account/xxxxxxxxx/NumberPool/ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f/",
5 | "meta": {
6 | "limit": 20,
7 | "offset": 0,
8 | "next": "",
9 | "previous": "",
10 | "total_count": 1
11 | },
12 | "objects": [
13 | {
14 | "added_on": "2019-10-09T11:10:59.741978Z",
15 | "country_iso2": "US",
16 | "number_pool_uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
17 | "shortcode": "{your_shortcode}"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackListTollfreeResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "614b2776-0a88-11ea-b072-0242ac110007",
3 | "uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
4 | "number_pool": "/v1/Account/xxxxxxxxx/NumberPool/ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f/",
5 | "meta": {
6 | "limit": 20,
7 | "offset": 0,
8 | "next": "",
9 | "previous": "",
10 | "total_count": 1
11 | },
12 | "objects": [
13 | {
14 | "added_on": "2019-10-09T11:10:59.741978Z",
15 | "country_iso2": "US",
16 | "number_pool_uuid": "ca5fd1f2-26c0-43e9-a7e4-0dc426e9dd2f",
17 | "tollfree": "{your_tollfree}"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackRemoveNumberResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "uuid": "d35f2e82-d387-427f-8594-6fa07613c43a",
3 | "name": "My Powerpack",
4 | "smart_sender": true,
5 | "local_connect": false,
6 | "application_type": "XML",
7 | "application_id": 123912833468,
8 | "number_pool": "/v1/Account/{auth_id}/NumberPool//",
9 | "created_on": "2019-07-15T12:22:00Z"
10 | }
11 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackRemoveShortcodeResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "uuid": "d35f2e82-d387-427f-8594-6fa07613c43a",
3 | "name": "My Powerpack",
4 | "smart_sender": true,
5 | "local_connect": false,
6 | "application_type": "XML",
7 | "application_id": 123912833468,
8 | "number_pool": "/v1/Account/{auth_id}/NumberPool//",
9 | "created_on": "2019-07-15T12:22:00Z"
10 | }
11 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackRemoveTollfreeResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "uuid": "d35f2e82-d387-427f-8594-6fa07613c43a",
3 | "name": "My Powerpack",
4 | "smart_sender": true,
5 | "local_connect": false,
6 | "application_type": "XML",
7 | "application_id": 123912833468,
8 | "number_pool": "/v1/Account/{auth_id}/NumberPool//",
9 | "created_on": "2019-07-15T12:22:00Z"
10 | }
11 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "b2e24102-d228-11e9-b61e-0242ac110007",
3 | "application_id": "33660394121755210",
4 | "application_type": "XML",
5 | "created_on": "2019-09-03T08:50:09.510692Z",
6 | "local_connect": false,
7 | "name": "vishnu_sep_01",
8 | "number_pool": "/v1/Account/MAODZKMDFJMJU3MTEYNG/NumberPool/659c7f88-c819-46e2-8af4-2d8a84249099/",
9 | "sticky_sender": true,
10 | "uuid": "86bbb125-97bb-4d72-89fd-81d5c515b015"
11 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/powerpackUpdatePowerpackResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "4b2c83c4-09ff-11ea-b072-0242ac110007",
3 | "uuid": "d35f2e82-d387-427f-8594-6fa07613c43a",
4 | "application_id": "20342783288007824",
5 | "application_type": "XML",
6 | "created_on": "2019-10-09T11:10:59.666461Z",
7 | "local_connect": true,
8 | "name": "test",
9 | "number_pool": "/v1/Account/{auth_id}/NumberPool/d35f2e82-d387-427f-8594-6fa07613c43a/",
10 | "sticky_sender": true,
11 | "uuid": ""
12 | }
13 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/pricingGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "25b3d816-1c9f-11e4-bd8a-12313f016a39",
3 | "country": "United States",
4 | "country_code": 1,
5 | "country_iso": "US",
6 | "message": {
7 | "inbound": {
8 | "rate": "0.00000"
9 | },
10 | "outbound": {
11 | "rate": "0.00650"
12 | },
13 | "outbound_networks_list": [
14 | {
15 | "group_name": "US",
16 | "rate": "0.00650"
17 | },
18 | {
19 | "group_name": "US",
20 | "rate": "0.00650"
21 | }
22 | ]
23 | },
24 | "phone_numbers": {
25 | "local": {
26 | "rate": "0.80000"
27 | },
28 | "tollfree": {
29 | "rate": "1.00000"
30 | }
31 | },
32 | "voice": {
33 | "inbound": {
34 | "ip": {
35 | "rate": "0.00300"
36 | },
37 | "local": {
38 | "rate": "0.00850"
39 | },
40 | "tollfree": {
41 | "rate": "0.02100"
42 | }
43 | },
44 | "outbound": {
45 | "ip": {
46 | "rate": "0.00300"
47 | },
48 | "local": {
49 | "rate": "0.01200"
50 | },
51 | "rates": [
52 | {
53 | "prefix": [
54 | "1"
55 | ],
56 | "rate": "0.01200"
57 | },
58 | {
59 | "prefix": [
60 | "1340"
61 | ],
62 | "rate": "0.02400"
63 | },
64 | {
65 | "prefix": [
66 | "1808"
67 | ],
68 | "rate": "0.03400"
69 | },
70 | {
71 | "prefix": [
72 | "1907"
73 | ],
74 | "rate": "0.17900"
75 | },
76 | {
77 | "prefix": [
78 | "1900"
79 | ],
80 | "rate": "0.60300"
81 | }
82 | ],
83 | "tollfree": {
84 | "rate": "0.00300"
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/profileCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "99ab47ae-b01c-11ec-bc21-0242ac110002",
3 | "profile_uuid": "43d0616e-d50a-445a-a84e-310a089f0618"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/profileGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "63287a98-b018-11ec-bc21-0242ac110002",
3 | "profile": {
4 | "alt_business_id_type": "NONE",
5 | "authorized_contact": {
6 | "name": " "
7 | },
8 | "company_name": "ABC Inc.",
9 | "customer_type": "RESELLER",
10 | "ein": "111111111",
11 | "ein_issuing_country": "US",
12 | "entity_type": "PUBLIC_PROFIT",
13 | "profile_alias": "vishnu1",
14 | "profile_type": "SECONDARY",
15 | "profile_uuid": "201faedc-7df9-4840-9ab1-3997ce3f7cf4",
16 | "stock_symbol": "ABC",
17 | "vertical": "ENERGY"
18 | }
19 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/profileUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "fd1fdade-17cd-11ed-b25b-0242ac110004",
3 | "profile": {
4 | "address": {
5 | "city": "New York",
6 | "country": "IN",
7 | "postal_code": "10001",
8 | "state": "NY",
9 | "street": "123"
10 | },
11 | "alt_business_id_type": "NONE",
12 | "authorized_contact": {
13 | "email": "test@plivo.com",
14 | "first_name": "John",
15 | "last_name": "Doe",
16 | "phone": "919539113734",
17 | "seniority": "admin",
18 | "title": "Doe"
19 | },
20 | "company_name": "ABC Inc.",
21 | "customer_type": "DIRECT",
22 | "ein": "123456789",
23 | "ein_issuing_country": "US",
24 | "entity_type": "PRIVATE",
25 | "primary_profile": "0b8a783c-9906-4c84-8ace-cb88413a1da6",
26 | "profile_alias": "used_in_automation_01",
27 | "profile_type": "SECONDARY",
28 | "profile_uuid": "09322f43-fe16-4525-b8e4-4229c867795d",
29 | "vertical": "ENERGY",
30 | "website": "www.google.com"
31 | }
32 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/recordingGetAddedFilterResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_time":"2022-04-12 16:08:53.523657+05:30",
3 | "call_uuid":"f72eea2a-446b-4412-a17f-3b17083bd25a",
4 | "conference_name":"",
5 | "from_number":"+919768368717",
6 | "monthly_recording_storage_amount": 0.0008,
7 | "recording_duration_ms":"7560.00000",
8 | "recording_end_ms":"1649759930398.00000",
9 | "recording_format":"mp3",
10 | "recording_id":"d405c4eb-d562-4399-af32-6ff3c57fa55x",
11 | "recording_start_ms":"1649759922838.00000",
12 | "recording_storage_duration": 209,
13 | "recording_storage_rate": 0.0004,
14 | "recording_type":"call",
15 | "recording_url":"https://media.plivo.com/v1/Account/MAZTCXYJFKZJK3N2Q3YT/Recording/d405c4eb-d562-4399-af32-6ff3c57fa559.mp3",
16 | "resource_uri":"/v1/Account/MAZTCXYJFKZJK3N2Q3YT/Recording/d405c4eb-d562-4399-af32-6ff3c57fa559/",
17 | "to_number":"sip:ajay6121801985815245533110@phone.plivo.com",
18 | "rounded_recording_duration": 120
19 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/recordingGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_time": "2014-08-05 16:15:15.852059+05:30",
3 | "api_id": "7abf0744-1ca0-11e4-a2d1-22000ac5040c",
4 | "call_uuid": "c2c128e2-1c8c-11e4-9bff-1db8a9db0432",
5 | "conference_name": "noname",
6 | "monthly_recording_storage_amount": 0.0008,
7 | "recording_duration_ms": "345100.00000",
8 | "recording_end_ms": "1407235509007.00000",
9 | "recording_format": "mp3",
10 | "recording_id": "c2186400-1c8c-11e4-a664-0026b945b52x",
11 | "recording_start_ms": "1407235163907.00000",
12 | "recording_storage_duration": 209,
13 | "recording_storage_rate": 0.0004,
14 | "recording_type": "conference",
15 | "recording_url": "http://s3.amazonaws.com/recordings_2013/c2186400-1c8c-11e4-a664-0026b945b52x.mp3",
16 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Recording/c2186400-1c8c-11e4-a664-0026b945b52x/",
17 | "rounded_recording_duration": 120
18 | }
19 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/recordingListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "ff25223a-1c9f-11e4-80aa-12313f048015",
3 | "meta": {
4 | "limit": 3,
5 | "next": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Recording/?limit=3&offset=3",
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 948
9 | },
10 | "objects": [
11 | {
12 | "add_time": "2014-08-05 16:15:15.852059+05:30",
13 | "call_uuid": "c2c128e2-1c8c-11e4-9bff-1db8a9db0432",
14 | "conference_name": "noname",
15 | "monthly_recording_storage_amount": 0.0008,
16 | "recording_duration_ms": "345100.00000",
17 | "recording_end_ms": "1407235509007.00000",
18 | "recording_format": "mp3",
19 | "recording_id": "c2186400-1c8c-1124-a664-0026b945b522",
20 | "recording_start_ms": "1407235163907.00000",
21 | "recording_storage_duration": 209,
22 | "recording_storage_rate": 0.0004,
23 | "recording_type": "conference",
24 | "recording_url": "http://s3.amazonaws.com/recordings_2013/c2186400-1c8c-1124-a664-0026b945b522.mp3",
25 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Recording/c2186400-1c8c-1124-a664-0026b945b522/",
26 | "rounded_recording_duration": 120
27 | },
28 | {
29 | "add_time": "2014-08-05 16:05:21.993853+05:30",
30 | "call_uuid": "fc773e88-1c8b-11e4-b25a-0fe7bcc54670",
31 | "conference_name": "noname",
32 | "monthly_recording_storage_amount": 0.0008,
33 | "recording_duration_ms": "90700.00000",
34 | "recording_end_ms": "1407234920253.00000",
35 | "recording_format": "mp3",
36 | "recording_id": "fc2716b0-1c8b-11e4-bwad-842b2b17453e",
37 | "recording_start_ms": "1407234829553.00000",
38 | "recording_storage_duration": 209,
39 | "recording_storage_rate": 0.0004,
40 | "recording_type": "conference",
41 | "recording_url": "http://s3.amazonaws.com/recordings_2013/fc2716b0-1c8b-11e4-bwad-842b2b17453e.mp3",
42 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Recording/fc2716b0-1c8b-11e4-bwad-842b2b17453e/",
43 | "rounded_recording_duration": 120
44 | },
45 | {
46 | "add_time": "2014-08-05 15:51:56.582492+05:30",
47 | "call_uuid": "3eb4c16e-1c8a-11e4-978e-0fe7bcc54670",
48 | "conference_name": "noname",
49 | "monthly_recording_storage_amount": 0.0008,
50 | "recording_duration_ms": "34100.00000",
51 | "recording_end_ms": "1407234115543.00000",
52 | "recording_format": "mp3",
53 | "recording_id": "3e701c9e-1c8a-11e4-bwad-842b2b17453e",
54 | "recording_start_ms": "1407234081443.00000",
55 | "recording_storage_duration": 209,
56 | "recording_storage_rate": 0.0004,
57 | "recording_type": "conference",
58 | "recording_url": "http://s3.amazonaws.com/recordings_2013/3e701c9e-1c8a-11e4-bwad-842b2b17453e.mp3",
59 | "resource_uri": "/v1/Account/MANWVLYTK4ZWU1YTY4ZT/Recording/3e701c9e-1c8a-11e4-bwad-842b2b17453e/",
60 | "rounded_recording_duration": 120
61 | }
62 | ]
63 | }
64 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/sessionGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "8faf830c-4be8-485a-9235-045495b03148",
3 | "session_uuid": "5c533d15-1975-4f20-80be-40174142ea37",
4 | "app_uuid": "eeb90c7b-9367-4457-8644-47007661bff5",
5 | "recipient": "918681951370",
6 | "channel": "sms",
7 | "status": "expired",
8 | "count": 1,
9 | "attempt_details": [
10 | {
11 | "channel": "sms",
12 | "attempt_uuid": "c1ed6b11-783d-4efd-8b45-d372e02d2943",
13 | "status": "failed",
14 | "time": "2023-07-18T08:46:14.865388Z"
15 | }
16 | ],
17 | "charges": {
18 | "total_charge": "0",
19 | "validation_charge": "0.0000",
20 | "attempt_charges": [
21 | {
22 | "attempt_uuid": "c1ed6b11-783d-4efd-8b45-d372e02d2943",
23 | "channel": "sms",
24 | "charge": "0.00000"
25 | }
26 | ]
27 | },
28 | "created_at": "2023-07-18T08:46:14.851205Z",
29 | "updated_at": "2023-07-18T08:46:14.865388Z"
30 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/shortcodeListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "cd5fde12-d229-11e9-b61e-0242ac110007",
3 | "meta": {
4 | "limit": 20,
5 | "next": "",
6 | "offset": 0,
7 | "previous": "",
8 | "total_count": 1
9 | },
10 | "objects": [{
11 | "added_on": "2019-09-03T08:50:09.578928Z",
12 | "country_iso2": "CA",
13 | "number_pool_uuid": "659c7f88-c819-46e2-8af4-2d8a84249099",
14 | "shortcode": "444444"
15 | }]
16 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/shortcodeResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "added_on": "2019-09-03T08:50:09.578928Z",
3 | "country_iso2": "CA",
4 | "number_pool_uuid": "659c7f88-c819-46e2-8af4-2d8a84249099",
5 | "shortcode": "444444"
6 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/subaccountCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "97c8d1de-3f08-11e7-b6f4-061564b78b75",
3 | "auth_id": "SANDLHYZBIZMU4ZDEXNM",
4 | "auth_token": "MTMzZTZjNzdiNDVmY2VhZDQyNTUwYWVjNzI2OThk",
5 | "message": "created"
6 | }
7 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/subaccountGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "account": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/",
3 | "api_id": "98b2d7ca-3f08-11e7-b886-067c5485c240",
4 | "auth_id": "SAODNKNDDMY2EXY2JKMG",
5 | "auth_token": "YjE4NWEyNzgzODkyNGI2NjdmZmZhZTdjNzlkYTE1",
6 | "created": "2017-05-22",
7 | "enabled": false,
8 | "modified": null,
9 | "name": "0.7542345556290114",
10 | "new_auth_token": "YjE4NWEyNzgzODkyNGI2NjdmZmZhZTdjNzlkYTE1",
11 | "resource_uri": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/Subaccount/SAODNKNDDMY2EXY2JKMG/"
12 | }
13 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/subaccountListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "98389d2a-3f08-11e7-b886-067c5485c240",
3 | "meta": {
4 | "limit": 20,
5 | "next": null,
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 3
9 | },
10 | "objects": [
11 | {
12 | "account": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/",
13 | "auth_id": "SAODNKNDDMY2EXY2JKMG",
14 | "auth_token": "YjE4NWEyNzgzODkyNGI2NjdmZmZhZTdjNzlkYTE1",
15 | "created": "2017-05-22",
16 | "enabled": false,
17 | "modified": null,
18 | "name": "0.7542345556290114",
19 | "new_auth_token": "YjE4NWEyNzgzODkyNGI2NjdmZmZhZTdjNzlkYTE1",
20 | "resource_uri": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/Subaccount/SAODNKNDDMY2EXY2JKMG/"
21 | },
22 | {
23 | "account": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/",
24 | "auth_id": "SANDBKY2YXMDU3MDLJNT",
25 | "auth_token": "OWVjODk1NzFjNzY1MTJiNDVkNTlmMGUyNjMyNWRh",
26 | "created": "2017-05-22",
27 | "enabled": false,
28 | "modified": null,
29 | "name": "0.11472037419916115",
30 | "new_auth_token": "OWVjODk1NzFjNzY1MTJiNDVkNTlmMGUyNjMyNWRh",
31 | "resource_uri": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/Subaccount/SANDBKY2YXMDU3MDLJNT/"
32 | },
33 | {
34 | "account": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/",
35 | "auth_id": "SANDLHYZBIZMU4ZDEXNM",
36 | "auth_token": "MTMzZTZjNzdiNDVmY2VhZDQyNTUwYWVjNzI2OThk",
37 | "created": "2017-05-22",
38 | "enabled": false,
39 | "modified": null,
40 | "name": "0.0636850567965852",
41 | "new_auth_token": "MTMzZTZjNzdiNDVmY2VhZDQyNTUwYWVjNzI2OThk",
42 | "resource_uri": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/Subaccount/SANDLHYZBIZMU4ZDEXNM/"
43 | }
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/subaccountUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "992d65c6-3f08-11e7-b886-067c5485c240",
3 | "message": "changed"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/tokenCreateResponse.json:
--------------------------------------------------------------------------------
1 | {"api_id": "5cbad7b4-19f4-11ed-8b03-0242ac110005",
2 | "token": "eyJhbGciOiJIUzI1NiIsImN0eSI6InBsaXZvO3Y9MSIsInR5cCI6IkpXVCJ9.eyJhcHAiOiIiLCJleHAiOjE2NjAzNjM2ODMsImlzcyI6Ik1BTURWTFpKWTJaR1k1TVdVMVpKIiwibmJmIjoxNjYwMjc3MjgzLCJwZXIiOnsidm9pY2UiOnsiaW5jb21pbmdfYWxsb3ciOmZhbHNlLCJvdXRnb2luZ19hbGxvdyI6dHJ1ZX19LCJzdWIiOiIifQ.LAwFEuotTmbZeGWBhfNT4X2KbRapYF23BrkwVfmr5A4"
3 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/tollfreeVerificationCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "5a9fcb68-582d-11e1-86da-6ff39efcb949",
3 | "message": "Tollfree verification request for 18339404937 submitted succesfully",
4 | "uuid": "f19c4773-4ae6-4b75-92ea-9cf3ea4227d6"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/tollfreeVerificationGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "4e1f954c-baf3-11ec-bafe-0242ac110003",
3 | "additional_information": "",
4 | "callback_method": "POST",
5 | "callback_url": "http://plivobin-prod-usw1.plivops.com/1e4jvpt1",
6 | "created": "2023-10-12T15:28:10.216507Z",
7 | "extra_data": "",
8 | "message_sample": "1.Your Plivo verification code is xxxx. 2.Dear , you have signed up on Plivo successfully.",
9 | "number": "18449605287",
10 | "optin_image_url": "https://www.plivo.com",
11 | "optin_type": "MOBILE_QR_CODE",
12 | "profile_uuid": "0ead82e0-fc80-4dc3-888b-7778932cf134",
13 | "error_message": "Demo Testing Sanity",
14 | "status": "REJECTED",
15 | "last_modified": "2023-10-13T08:24:26.619565Z",
16 | "usecase": "2FA",
17 | "usecase_summary": "1.We send 2FA codes to customers when they signup. 2.Dear , you have signed up on Plivo successfully.",
18 | "uuid": "312b3119-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
19 | "volume": "100"
20 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/tollfreeVerificationListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "4e15f360-72fe-11ee-8538-e20bbbfb283e",
3 | "meta": {
4 | "count": 2,
5 | "limit": 10,
6 | "next": null,
7 | "offset": 10,
8 | "previous": "/v1/Account/MAXXXXXXXXXXXXXXXXXX/TollfreeVerification/?limit=10&offset=0"
9 | },
10 | "objects": [
11 | {
12 | "additional_information": "",
13 | "callback_method": "POST",
14 | "callback_url": "http://plivobin-prod-usw1.plivops.com/1e4jvpt1",
15 | "created": "2023-10-12T15:28:10.216507Z",
16 | "extra_data": "",
17 | "message_sample": "1.Your Plivo verification code is xxxx. 2.Dear , you have signed up on Plivo successfully.",
18 | "number": "18449605287",
19 | "optin_image_url": "https://www.plivo.com",
20 | "optin_type": "MOBILE_QR_CODE",
21 | "profile_uuid": "0ead82e0-fc80-4dc3-888b-7778932cf134",
22 | "error_message": "Demo Testing Sanity",
23 | "status": "REJECTED",
24 | "last_modified": "2023-10-13T08:24:26.619565Z",
25 | "usecase": "2FA",
26 | "usecase_summary": "1.We send 2FA codes to customers when they signup. 2.Dear , you have signed up on Plivo successfully.",
27 | "uuid": "312b3119-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
28 | "volume": "100"
29 | },
30 | {
31 | "additional_information": "",
32 | "callback_method": "POST",
33 | "callback_url": "http://plivobin-prod-usw1.plivops.com/1e4jvpt1",
34 | "created": "2023-10-12T12:06:46.527653Z",
35 | "extra_data": "",
36 | "message_sample": "1.Your Plivo verification code is xxxx. 2.Dear , you have signed up on Plivo successfully.",
37 | "number": "18449605287",
38 | "optin_image_url": "https://www.plivo.com",
39 | "optin_type": "MOBILE_QR_CODE",
40 | "profile_uuid": "0ead82e0-fc80-4dc3-888b-7778932cf134",
41 | "error_message": "Demo Testing Sanity",
42 | "status": "REJECTED",
43 | "last_modified": "2023-10-12T15:27:56.052433Z",
44 | "usecase": "2FA",
45 | "usecase_summary": "1.We send 2FA codes to customers when they signup. 2.Dear , you have signed up on Plivo successfully.",
46 | "uuid": "96ec880d-b7ee-4eb5-7c9a-3ff28826e77c",
47 | "volume": "100"
48 | }
49 | ]
50 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/tollfreeVerificationUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "4e1f954c-baf3-11ec-bafe-0242ac110003",
3 | "message": "Tollfree verification request for 18339404937 updated succesfully"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/transcriptionCreateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "c9db3f38-55e8-4d97-93b2-1ece5a342528",
3 | "message": "transcription in progress"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/transcriptionDeleteResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "47ab0f0d-a7db-4f56-8200-6555cd3194e8",
3 | "message": "request accepted"
4 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/transcriptionGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "f83b30a3-228c-4676-813e-985fcdf61201",
3 | "cost": 0.05,
4 | "rate": 0.05,
5 | "recording_duration_ms": 22780,
6 | "recording_start_ms": 1729761222174,
7 | "status": "success",
8 | "transcription": "\nSpeaker 0: Scan just to be safe. If you notice any error messages, please let me know immediately. They can help us diagnose the issue better. If it continues to freeze, we might need to look into your system performance. I can guide you through checking your task manager if that helps.\n\nSometimes, background processes can use up a lot of resources. I under"
9 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/verifyCalleridGetResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "alias": "test",
3 | "api_id": "ee7c3cb1-c921-42c9-832b-950fb8344b9b",
4 | "country": "IN",
5 | "created_at": "2023-09-22T14:11:03.091534Z",
6 | "modified_at": "2023-09-22T14:11:03.091534Z",
7 | "phone_number": "+919768368718",
8 | "subaccount": "",
9 | "verification_uuid": "0f978b20-9e2b-4cfe-99fe-f7087c03b8e1"
10 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/verifyCalleridInitiateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "2a5e81d7-deb3-46cd-ac34-c05ca9139b6f",
3 | "message": "Verification code is sent to number +919768368717 which is valid for 15 minutes",
4 | "verification_uuid": "407796a6-1f3e-4607-a9d9-5a5376b59a7b"
5 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/verifyCalleridListResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "api_id": "3b21c7d7-09f7-489b-b753-659814a676bf",
3 | "meta": {
4 | "limit": 20,
5 | "next": null,
6 | "offset": 0,
7 | "previous": null,
8 | "total_count": 4
9 | },
10 | "objects": [
11 | {
12 | "alias": "abhishek",
13 | "country": "IN",
14 | "created_at": "2023-09-25T14:40:38.68729Z",
15 | "modified_at": "2023-09-25T14:40:38.68729Z",
16 | "phone_number": "+919653244280",
17 | "resource_uri": "/v1/Account/MADCHANDRESH02TANK06/VerifiedCallerId/919653244280",
18 | "subaccount": "",
19 | "verification_uuid": "01be6b07-b106-46e2-8dfc-096d8e22cc0e"
20 | },
21 | {
22 | "alias": "abhishek",
23 | "country": "IN",
24 | "created_at": "2023-09-25T13:10:39.968133Z",
25 | "modified_at": "2023-09-25T13:10:39.968133Z",
26 | "phone_number": "+919768368717",
27 | "resource_uri": "/v1/Account/MADCHANDRESH02TANK06/VerifiedCallerId/919768368717",
28 | "subaccount": "",
29 | "verification_uuid": "2e68eb73-4d54-4391-bc98-71cd380911a4"
30 | },
31 | {
32 | "alias": "test",
33 | "country": "IN",
34 | "created_at": "2023-09-22T14:11:03.091534Z",
35 | "modified_at": "2023-09-22T14:11:03.091534Z",
36 | "phone_number": "+919768368718",
37 | "resource_uri": "/v1/Account/MADCHANDRESH02TANK06/VerifiedCallerId/919768368718",
38 | "subaccount": "",
39 | "verification_uuid": "0f978b20-9e2b-4cfe-99fe-f7087c03b8e1"
40 | },
41 | {
42 | "alias": "Test2",
43 | "country": "",
44 | "created_at": "2023-08-30T07:47:43.87171Z",
45 | "modified_at": "2023-08-30T07:47:43.87171Z",
46 | "phone_number": "+917691021365",
47 | "resource_uri": "/v1/Account/MADCHANDRESH02TANK06/VerifiedCallerId/917691021365",
48 | "subaccount": "SAMTU0Y2FKNGETYZDKNI",
49 | "verification_uuid": "20265c57-2d8e-46fe-8fa8-e8ab4ee58a8c"
50 | }
51 | ]
52 | }
--------------------------------------------------------------------------------
/tests/resources/fixtures/verifyCalleridUpdateResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "alias": "testAbhishek",
3 | "api_id": "6b143cb3-9c8a-42ad-b6b7-412ebd5c60a9",
4 | "country": "IN",
5 | "created_at": "2023-09-22T14:11:03.091534Z",
6 | "modified_at": "2023-09-22T14:11:03.091534Z",
7 | "phone_number": "+919768368718",
8 | "subaccount": "SAMTU0Y2FKNGETYZDKNI",
9 | "verification_uuid": "0f978b20-9e2b-4cfe-99fe-f7087c03b8e1"
10 | }
11 |
--------------------------------------------------------------------------------
/tests/resources/fixtures/verifyCalleridVerifyResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "alias": "abhishek",
3 | "api_id": "584a97aa-ca1d-44f2-9dd3-e58fbacd6649",
4 | "channel": "call",
5 | "country": "IN",
6 | "created_at": "2023-09-25T13:10:39.968133341Z",
7 | "phone_number": "+919768368717",
8 | "verification_uuid": "2e68eb73-4d54-4391-bc98-71cd380911a4"
9 | }
--------------------------------------------------------------------------------
/tests/resources/test_brand.py:
--------------------------------------------------------------------------------
1 | from plivo import exceptions
2 | from tests.base import PlivoResourceTestCase
3 | from tests.decorators import with_response
4 |
5 | class BrandTest(PlivoResourceTestCase):
6 | @with_response(200)
7 | def test_create(self):
8 | response = self.client.brand.create(
9 | brand_alias = "brand name sample",
10 | brand_type="STARTER",
11 | profile_uuid="201faedc-7df9-4840-9ab1-3997ce3f7cf4",
12 | secondary_vetting=False,
13 | url="http://example.come/test",
14 | method="POST")
15 | self.assertEqual('POST', self.client.current_request.method)
16 | self.assertUrlEqual(
17 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/10dlc/Brand/',
18 | self.client.current_request.url)
19 |
20 | @with_response(200)
21 | def test_get(self):
22 | response = self.client.brand.get(brand_id='BRPXS6E')
23 | self.client.set_expected_response(
24 | status_code=202, data_to_return=response)
25 | # Verifying the endpoint hit
26 | self.assertUrlEqual(
27 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/10dlc/Brand/BRPXS6E/',
28 | self.client.current_request.url)
29 |
30 | # Verifying the method used
31 | self.assertEqual('GET', self.client.current_request.method)
32 |
33 | @with_response(200)
34 | def test_list(self):
35 | res = self.client.brand.list(limit=2, offset=0)
36 | # Test if ListResponseObject's __iter__ is working correctly
37 | self.assertGreater(len(list(res.brands)), 0)
38 | # Verifying the endpoint hit
39 | self.assertUrlEqual(
40 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/10dlc/Brand/?limit=2&offset=0',
41 | self.client.current_request.url)
42 | # Verifying the method used
43 | self.assertEqual('GET', self.client.current_request.method)
44 |
45 | @with_response(200)
46 | def test_get_usecases(self):
47 | response = self.client.brand.get_usecases(brand_id='BRPXS6E')
48 | self.client.set_expected_response(
49 | status_code=202, data_to_return=response)
50 | # Verifying the endpoint hit
51 | self.assertUrlEqual(
52 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/10dlc/Brand/BRPXS6E/usecases/',
53 | self.client.current_request.url)
54 |
55 | # Verifying the method used
56 | self.assertEqual('GET', self.client.current_request.method)
57 |
58 | @with_response(200)
59 | def test_delete(self):
60 | response = self.client.brand.delete(brand_id='BRPXS6E')
61 | self.client.set_expected_response(
62 | status_code=202, data_to_return=response)
63 | # Verifying the endpoint hit
64 | self.assertUrlEqual(
65 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/10dlc/Brand/BRPXS6E/',
66 | self.client.current_request.url)
67 |
68 | # Verifying the method used
69 | self.assertEqual('DELETE', self.client.current_request.method)
70 |
--------------------------------------------------------------------------------
/tests/resources/test_client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from unittest import TestCase
3 |
4 |
5 | class ClientTest(TestCase):
6 | def test_subaccount(self):
7 | from plivo.utils import is_valid_subaccount
8 | self.assertTrue(is_valid_subaccount('SA' + 'X' * 18))
9 |
--------------------------------------------------------------------------------
/tests/resources/test_endpoints.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from tests import PlivoResourceTestCase
3 | from tests.decorators import with_response
4 |
5 |
6 | class EndpointTest(PlivoResourceTestCase):
7 | @with_response(200)
8 | def test_create(self):
9 | self.client.endpoints.create(
10 | username='test', password='test', alias='test')
11 | self.assertEqual(self.client.current_request.method, 'POST')
12 | self.assertUrlEqual(
13 | self.get_voice_url('Endpoint'), self.client.current_request.url)
14 |
15 | @with_response(200)
16 | def test_list(self):
17 | endpoints = self.client.endpoints.list()
18 | # Test if ListResponseObject's __iter__ is working correctly
19 | self.assertEqual(len(list(endpoints)), 2)
20 | self.assertEqual(self.client.current_request.method, 'GET')
21 | self.assertUrlEqual(
22 | self.get_voice_url('Endpoint', limit=20, offset=0), self.client.current_request.url)
23 |
24 | @with_response(200)
25 | def test_get(self):
26 | uuid = '4d04c52e-cea3-4458-bbdb-0bfc314ee7cd'
27 | endpoint = self.client.endpoints.get(uuid)
28 | self.assertResponseMatches(endpoint)
29 | self.assertEqual(self.client.current_request.method, 'GET')
30 | self.assertUrlEqual(
31 | self.get_voice_url('Endpoint', uuid) + 'endpoint_id=' + uuid, self.client.current_request.url)
32 |
33 | @with_response(202)
34 | def test_update(self):
35 | uuid = '4d04c52e-cea3-4458-bbdb-0bfc314ee7cd'
36 | self.client.endpoints.update(uuid, alias='test')
37 | self.assertEqual(self.client.current_request.method, 'POST')
38 | self.assertUrlEqual(
39 | self.get_voice_url('Endpoint', uuid), self.client.current_request.url)
40 |
41 | @with_response(204)
42 | def test_delete(self):
43 | uuid = '4d04c52e-cea3-4458-bbdb-0bfc314ee7cd'
44 | self.client.endpoints.delete(uuid)
45 | self.assertEqual(self.client.current_request.method, 'DELETE')
46 | self.assertUrlEqual(
47 | self.get_voice_url('Endpoint', uuid), self.client.current_request.url)
48 |
--------------------------------------------------------------------------------
/tests/resources/test_jwt.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import plivo
4 | import time
5 | from tests.base import PlivoResourceTestCase
6 | from plivo.utils import jwt
7 |
8 |
9 | class AccessTokenTest(PlivoResourceTestCase):
10 | def test_jwt_constructor(self):
11 | self.assertRaisesRegexp(TypeError, "", jwt.AccessToken,
12 | 'ADADADADADADADADADA',
13 | 'qwerty')
14 |
15 | def test_jwt_constructor_auth_id(self):
16 | self.assertRaisesRegexp(plivo.exceptions.ValidationError,
17 | "auth_id should match format .*",
18 | jwt.AccessToken,
19 | 'ADADADADADADADADADA', 'qwerty', 'username')
20 |
21 | def test_jwt_constructor_auth_id(self):
22 | self.assertRaisesRegexp(plivo.exceptions.ValidationError,
23 | "auth_id should match format .*",
24 | jwt.AccessToken,
25 | 'ADADADADADADADADADA', 'qwerty', 'username')
26 |
27 | def test_jwt_constructor_lifetime(self):
28 | self.assertRaisesRegexp(plivo.exceptions.ValidationError,
29 | ".* lifetime .*",
30 | jwt.AccessToken,
31 | 'MADADADADADADADADADA',
32 | 'qwerty',
33 | 'username',
34 | valid_from=int(time.time()),
35 | lifetime=123)
36 |
37 | def test_jwt_constructor_validity(self):
38 | self.assertRaisesRegexp(plivo.exceptions.ValidationError,
39 | "use either lifetime or valid_till",
40 | jwt.AccessToken,
41 | 'MADADADADADADADADADA',
42 | 'qwerty',
43 | 'username',
44 | valid_from=int(time.time()),
45 | valid_till=int(time.time()) - 100,
46 | lifetime=1200)
47 | self.assertRaisesRegexp(plivo.exceptions.ValidationError,
48 | "validity expires .* seconds before it starts",
49 | jwt.AccessToken,
50 | 'MADADADADADADADADADA',
51 | 'qwerty',
52 | 'username',
53 | valid_from=int(time.time()),
54 | valid_till=int(time.time()) - 100)
55 |
56 | def test_jwt(self):
57 | token = jwt.AccessToken('MADADADADADADADADADA', 'qwerty', 'username', valid_from=12121212, lifetime=300, uid='username-12345')
58 | token.add_voice_grants(True, True)
59 | self.assertEqual(True, token.grants['voice']['incoming_allow'])
60 | self.assertNotEqual(False, token.grants['voice']['outgoing_allow'])
61 |
--------------------------------------------------------------------------------
/tests/resources/test_lookup.py:
--------------------------------------------------------------------------------
1 | from plivo import exceptions
2 | from tests.base import PlivoResourceTestCase
3 | from tests.decorators import with_response
4 |
5 |
6 | class LookupTest(PlivoResourceTestCase):
7 | @with_response(200)
8 | def test_get(self):
9 | number = '+14154305555'
10 | resp = self.client.lookup.get(number)
11 | self.assertResponseMatches(resp)
12 | self.assertEqual(self.client.current_request.method, 'GET')
13 |
--------------------------------------------------------------------------------
/tests/resources/test_medias.py:
--------------------------------------------------------------------------------
1 | from plivo import exceptions
2 | from tests.base import PlivoResourceTestCase
3 | from tests.decorators import with_response
4 |
5 |
6 | class MediaTest(PlivoResourceTestCase):
7 | @with_response(200)
8 | def test_get_media(self):
9 | media_id = 'media_id'
10 | media = self.client.media.get(media_id)
11 | self.assertResponseMatches(media)
12 | self.assertUrlEqual(self.client.current_request.url,
13 | self.get_url('Media', media_id))
14 | self.assertEqual(self.client.current_request.method, 'GET')
15 |
16 | @with_response(200)
17 | def test_list(self):
18 | media = self.client.media.list()
19 | self.assertEqual(len(list(media)), 2)
20 | self.assertEqual(self.client.current_request.method, 'GET')
21 |
--------------------------------------------------------------------------------
/tests/resources/test_members.py:
--------------------------------------------------------------------------------
1 | from plivo.exceptions import ResourceNotFoundError, ValidationError,\
2 | PlivoServerError
3 | from tests.base import PlivoPhlosResourceTestCase
4 | from tests.decorators import with_response
5 |
6 |
7 | class PhlosMemberTest(PlivoPhlosResourceTestCase):
8 |
9 | @with_response(404)
10 | def test_phlo_get_invalid_phlo_id_failing(self):
11 | """
12 | Should fail for invalid phlo id
13 | """
14 | with self.assertRaises(ValidationError):
15 | self.client.phlo.get(None)
16 |
17 | with self.assertRaises(PlivoServerError):
18 | self.client.phlo.get(12345)
19 |
20 | with self.assertRaises(PlivoServerError):
21 | self.client.phlo.get('40b2fa01-39a1-43c8-9f6c-xxxxxxxxxxxx')
22 |
23 | with self.assertRaises(PlivoServerError):
24 | phlo_get = self.client.phlo.get('40b2fa01-39a1-43c8-9f6c-7e6a219afe43')
25 | phlo_get.node('conference_bridge', '5c698012954a4399a455eadd')
26 |
27 | with self.assertRaises(PlivoServerError):
28 | phlo_get = self.client.phlo.get('40b2fa01-39a1-43c8-9f6c-7e6a219afe43')
29 | phlo_get.multi_party_call('5c698012954a4399a455eadd')
30 |
31 | with self.assertRaises(PlivoServerError):
32 | phlo_get = self.client.phlo.get('40b2fa01-39a1-43c8-9f6c-7e6a219afe43')
33 | phlo_get.run()
34 |
35 | @with_response(404)
36 | def test_member_actions(self):
37 | """
38 | Should fail for invalid member actions
39 | """
40 | with self.assertRaises(ResourceNotFoundError):
41 | self.client.phlo.member(
42 | '40b2fa01-39a1-43c8-9f6c-7e6a219afe43',
43 | '5c698012954a4399a455eadd',
44 | '656432-xxxxx-xxxxx-xxxxx',
45 | 'hold'
46 | )
47 |
48 | with self.assertRaises(ResourceNotFoundError):
49 | self.client.phlo.member(
50 | 12345,
51 | '5c698012954a4399a455eadd',
52 | '656432-xxxxx-xxxxx-xxxxx',
53 | 'hold'
54 | )
55 |
56 | @with_response(400)
57 | def test_member_actions_validation(self):
58 | with self.assertRaises(ValidationError):
59 | self.client.phlo.member(
60 | '40b2fa01-39a1-43c8-9f6c-7e6a219afe43',
61 | '5c698012954a4399a455eadd',
62 | '656432-xxxxx-xxxxx-xxxxx',
63 | 'hold'
64 | )
65 |
66 | with self.assertRaises(ValidationError):
67 | self.client.phlo.member(
68 | '40b2fa01-39a1-43c8-9f6c-7e6a219afe43',
69 | '5c698012954a4399a455eadd',
70 | '656432-xxxxx-xxxxx-xxxxx',
71 | 'mute'
72 | )
73 |
--------------------------------------------------------------------------------
/tests/resources/test_pricings.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import plivo
4 | from tests.base import PlivoResourceTestCase
5 | from tests.decorators import with_response
6 |
7 |
8 | class PricingTest(PlivoResourceTestCase):
9 | def test_pricing_get_invalid_params(self):
10 | with self.assertRaises(plivo.exceptions.ValidationError):
11 | self.client.pricing.get('USA')
12 |
13 | @with_response(200)
14 | def test_get(self):
15 | us_pricing = self.client.pricing.get('US')
16 | self.assertResponseMatches(us_pricing, )
17 |
18 | # Verifying the endpoint hit
19 | self.assertEqual(
20 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Pricing/?country_iso=US',
21 | self.client.current_request.url)
22 |
23 | # Verifying the method used
24 | self.assertEqual('GET', self.client.current_request.method)
25 |
26 | # Verifying the object type returned
27 | self.assertEqual(plivo.resources.pricings.Pricing,
28 | us_pricing.__class__)
29 |
30 | # Verifying if the Account specific changes and parsing happened
31 | self.assertEqual('US', us_pricing.id)
32 |
--------------------------------------------------------------------------------
/tests/resources/test_signature.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import plivo
4 | from tests.base import PlivoResourceTestCase
5 |
6 |
7 | class SignatureTest(PlivoResourceTestCase):
8 | def test_signature(self):
9 | self.assertEqual(True,
10 | plivo.utils.validate_signature(
11 | 'https://answer.url', '12345',
12 | 'ehV3IKhLysWBxC1sy8INm0qGoQYdYsHwuoKjsX7FsXc=',
13 | 'my_auth_token'))
14 |
15 | self.assertEqual(False,
16 | plivo.utils.validate_signature(
17 | 'https://answer.url', '12345',
18 | 'ehV3IKhLysWBxC1sy8INm0qGoQYdYsHwuoKjsX7FsXc=',
19 | 'my_auth_tokens'))
20 |
--------------------------------------------------------------------------------
/tests/resources/test_token.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from tests import PlivoResourceTestCase
3 | from tests.decorators import with_response
4 |
5 |
6 | class TokenTest(PlivoResourceTestCase):
7 | @with_response(200)
8 | def test_create(self):
9 | self.client.token.create("MAXXXXXXXXXXXXXXXXXX")
10 | self.assertEqual(self.client.current_request.method, 'POST')
11 | self.assertUrlEqual(
12 | self.get_voice_url('JWT/Token'), self.client.current_request.url)
13 |
--------------------------------------------------------------------------------
/tests/resources/test_transcriptions.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from datetime import datetime
4 |
5 | import plivo
6 | from tests.base import PlivoResourceTestCase
7 | from tests.decorators import with_response
8 |
9 |
10 | class TranscriptionTest(PlivoResourceTestCase):
11 | @with_response(200)
12 | def test_get(self):
13 |
14 | transcription = self.client.transcriptions.get_transcription('e12d05fe-6979-485c-83dc-9276114dba3b')
15 |
16 | self.assertResponseMatches(transcription)
17 |
18 | # Verifying the endpoint hit
19 | self.assertEqual(
20 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Transcription/e12d05fe-6979-485c-83dc-9276114dba3b/',
21 | self.client.current_request.url)
22 |
23 | # Verifying the method used
24 | self.assertEqual('GET', self.client.current_request.method)
25 |
26 | self.assertEqual('\nSpeaker 0: Scan just to be safe. If you notice any error messages, please let me know immediately. They can help us diagnose the issue better. If it continues to freeze, we might need to look into your system performance. I can guide you through checking your task manager if that helps.\n\nSometimes, background processes can use up a lot of resources. I under', transcription.transcription)
27 |
28 | @with_response(201)
29 | def test_create(self):
30 | self.client.transcriptions.create_transcription(
31 | recording_id='8605287e-1e1a-4341-8235-23574357d6f1')
32 |
33 | # self.assertResponseMatches(transcription)
34 |
35 | # Verifying the endpoint hit
36 | # self.assertUrlEqual(
37 | # self.get_voice_url('Transcription', '8605287e-1e1a-4341-8235-23574357d6f1'), self.client.current_request.url)
38 | self.assertEqual(
39 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Transcription/8605287e-1e1a-4341-8235-23574357d6f1/',
40 | self.client.current_request.url)
41 |
42 | # Verifying the method used
43 | self.assertEqual('POST', self.client.current_request.method)
44 |
45 | # self.assertEqual('transcription in progress',transcription.message)
46 |
47 | @with_response(202)
48 | def test_delete(self):
49 | transcription = self.client.transcriptions.delete_transcription(
50 | '8605287e-1e1a-4341-8235-23574357d6f1')
51 |
52 | self.assertResponseMatches(transcription)
53 |
54 | # Verifying the endpoint hit
55 | self.assertEqual(
56 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Transcription/8605287e-1e1a-4341-8235-23574357d6f1/',
57 | self.client.current_request.url)
58 |
59 | # Verifying the method used
60 | self.assertEqual('DELETE', self.client.current_request.method)
61 |
62 | self.assertEqual('request accepted', transcription.message)
--------------------------------------------------------------------------------
/tests/resources/test_verify.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from plivo import exceptions
3 | from tests.base import PlivoResourceTestCase
4 | from tests.decorators import with_response
5 |
6 |
7 | class SessionTest(PlivoResourceTestCase):
8 | def test_create_session(self):
9 | expected_response = {'session_uuid': 'adsdafkjadshf123123'}
10 | self.client.set_expected_response(
11 | status_code=202, data_to_return=expected_response)
12 |
13 | test_session = self.client.verify_session.create(
14 | recipient='1234567890')
15 |
16 | self.assertEqual(
17 | self.client.current_request.url,
18 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Verify/Session/')
19 | self.assertEqual(self.client.current_request.method, 'POST')
20 | self.assertEqual(test_session.session_uuid,
21 | expected_response['session_uuid'])
22 |
23 | def test_create_session_without_recipient(self):
24 | self.assertRaises(
25 | exceptions.ValidationError,
26 | self.client.verify_session.create
27 | )
28 |
29 | @with_response(200)
30 | def test_get(self):
31 | session_uuid = 'session_uuid'
32 | session = self.client.verify_session.get(session_uuid)
33 | self.assertResponseMatches(session)
34 | self.assertUrlEqual(self.client.current_request.url,
35 | self.get_url('Verify', 'Session', session_uuid))
36 | self.assertEqual(self.client.current_request.method, 'GET')
37 |
38 | @with_response(200)
39 | def test_list(self):
40 | messages = self.client.verify_session.list()
41 | # Test if ListResponseObject's __iter__ is working correctly
42 | self.assertEqual(len(list(messages)), 20)
43 | self.assertUrlEqual(self.client.current_request.url,
44 | self.get_url('Verify', 'Session'))
45 | self.assertEqual(self.client.current_request.method, 'GET')
46 |
47 | @with_response(200)
48 | def test_validate(self):
49 | session_uuid = '1234567'
50 | expected_response = {'message': 'session validated successfully.'}
51 | self.client.set_expected_response(
52 | status_code=200, data_to_return=expected_response)
53 |
54 | test_session = self.client.verify_session.validate(
55 | session_uuid=session_uuid, otp='123456')
56 |
57 | self.assertEqual(
58 | self.client.current_request.url,
59 | 'https://api.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/Verify/Session/1234567/')
60 | self.assertEqual(self.client.current_request.method, 'POST')
61 | self.assertEqual(test_session.message,
62 | expected_response['message'])
63 |
64 |
--------------------------------------------------------------------------------
/tests/resources/test_verifycallerids.py:
--------------------------------------------------------------------------------
1 | from tests.base import PlivoResourceTestCase
2 | from tests.decorators import with_response
3 |
4 |
5 | class VerifyCalleridTest(PlivoResourceTestCase):
6 | @with_response(201)
7 | def test_initiate(self):
8 | self.client.verify_callerids.initiate_verify(phone_number='917708772011',
9 | alias='test',
10 | channel='call')
11 | self.assertEqual(self.client.current_request.method, 'POST')
12 | self.assertUrlEqual(
13 | self.get_voice_url('VerifiedCallerId'), self.client.current_request.url)
14 |
15 | @with_response(201)
16 | def test_verify(self):
17 | verification_uuid = 'eeab1477-e59b-4821-9e61-fd5847c2a5db'
18 | self.client.verify_callerids.verify_caller_id(
19 | verification_uuid='eeab1477-e59b-4821-9e61-fd5847c2a5db', otp='610534')
20 | self.assertEqual(self.client.current_request.method, 'POST')
21 | self.assertUrlEqual(
22 | self.get_voice_url('VerifiedCallerId', 'Verification', verification_uuid), self.client.current_request.url)
23 |
24 | @with_response(200)
25 | def test_delete(self):
26 | phone_number = "917708772011"
27 | self.client.verify_callerids.delete_verified_caller_id(
28 | phone_number)
29 | self.assertEqual(self.client.current_request.method, 'DELETE')
30 | self.assertUrlEqual(
31 | self.get_voice_url('VerifiedCallerId', phone_number), self.client.current_request.url)
32 |
33 | @with_response(200)
34 | def test_get(self):
35 | phone_number = "917708772011"
36 | self.client.verify_callerids.get_verified_caller_id(phone_number)
37 | self.assertEqual(self.client.current_request.method, 'GET')
38 | self.assertUrlEqual(
39 | self.get_voice_url('VerifiedCallerId', phone_number), self.client.current_request.url)
40 |
41 | @with_response(200)
42 | def test_update(self):
43 | phone_number = "917708772011"
44 | self.client.verify_callerids.update_verified_caller_id(
45 | phone_number=phone_number,
46 | alias='test123')
47 | self.assertEqual(self.client.current_request.method, 'POST')
48 | self.assertUrlEqual(
49 | self.get_voice_url('VerifiedCallerId', phone_number), self.client.current_request.url)
50 |
51 | @with_response(200)
52 | def test_list(self):
53 | self.client.verify_callerids.list_verified_caller_id()
54 | self.assertEqual(self.client.current_request.method, 'GET')
55 | self.assertUrlEqual(
56 | self.get_voice_url('VerifiedCallerId'), self.client.current_request.url)
57 |
--------------------------------------------------------------------------------
/tests/xml/__init__.py:
--------------------------------------------------------------------------------
1 | from .test_responseElement import ResponseElementTest
2 | from .test_recordElement import RecordElementTest
3 | from .test_getDigitsElement import GetDigitsElementTest
4 | from .test_getInputElement import GetInputElementTest
5 | from .test_messageElement import MessageElementTest
6 |
--------------------------------------------------------------------------------
/tests/xml/test_breakElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class BreakElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | time = "1000ms"
10 | strength = "x-strong"
11 | expected_response = 'Break of one second or same as paragraph '
12 | element = plivoxml.ResponseElement()
13 | response = element.add(
14 | plivoxml.SpeakElement("Break of", "Polly.Joey").add(
15 | plivoxml.BreakElement().set_strength(strength).set_time(time)
16 | ).add_cont("one second or same as paragraph")
17 | ).to_string(False)
18 | self.assertXmlEqual(response, expected_response)
19 |
--------------------------------------------------------------------------------
/tests/xml/test_emphasisElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class EmphasisElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = '' \
10 | 'This is Test' \
11 | 'This is TestThis is Test' \
13 | 'This is Test' \
14 | 'This is TestThis is Test' \
15 | 'This is Test'
16 | level = "strong"
17 | content_break = 'This is Test'
18 | strength_break = 'strong'
19 | time_break = '250ms'
20 |
21 | content_lang = 'This is Test'
22 | xmllang_lang = "it"
23 |
24 | content_emphasis = 'This is Test'
25 | level_emphasis = 'strong'
26 |
27 | content_phoneme = 'This is Test'
28 | alphabet_phoneme = "ipa"
29 | ph_phoneme = "təmei̥ɾou̥"
30 |
31 | content_prosody = "This is Test"
32 | volume_prosody = "+6dB"
33 | rate_prosody = "x-high"
34 | pitch_prosody = "low"
35 |
36 | content_say_as = 'This is Test'
37 | interpret_as_say_as = "spell-out"
38 | format_say_as = ""
39 |
40 | content_sub = "This is Test"
41 | alias_sub = "World Wide Web Consortium"
42 |
43 | content_w = "This is Test"
44 | role_w = "claws:VV0"
45 |
46 | element = plivoxml.ResponseElement()
47 | response = element.add(
48 | plivoxml.SpeakElement("").add(
49 | plivoxml.EmphasisElement().set_level(level).add_break(
50 | strength=strength_break
51 | ).add_lang(
52 | content_lang,
53 | xmllang=xmllang_lang
54 | ).add_emphasis(
55 | content_emphasis,
56 | level=level_emphasis
57 | ).add_phoneme(
58 | content_phoneme,
59 | alphabet=alphabet_phoneme,
60 | ph=ph_phoneme
61 | ).add_prosody(
62 | content_prosody,
63 | pitch=pitch_prosody
64 | ).add_say_as(
65 | content_say_as,
66 | interpret_as=interpret_as_say_as,
67 | format=format_say_as
68 | ).add_sub(
69 | content_sub,
70 | alias=alias_sub,
71 | ).add_w(
72 | content_w,
73 | role_w
74 | )
75 | )
76 | ).to_string(False)
77 | self.assertXmlEqual(response, expected_response)
78 |
--------------------------------------------------------------------------------
/tests/xml/test_getDigitsElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 | from plivo import plivoxml
3 | from tests import PlivoXmlTestCase
4 |
5 |
6 | class GetDigitsElementTest(TestCase, PlivoXmlTestCase):
7 | def test_set_methods(self):
8 | expected_response = 'This is test' \
12 | 'This is test'
13 |
14 | action = 'https://foo.example.com'
15 | method = 'GET'
16 | timeout = 100
17 | digitTimeout = 10
18 | finishOnKey = '#'
19 | numDigits = 2
20 | retries = True
21 | redirect = False
22 | playBeep = False
23 | validDigits = '*'
24 | invalidDigitsSound = 'http://foo.audio.url'
25 | log = True
26 |
27 | content_speak = 'This is test'
28 | voice_speak = 'WOMAN'
29 | language_speak = 'en-US'
30 | loop_speak = 2
31 | loop_play = 2
32 | content_play = 'This is test'
33 |
34 | element = plivoxml.ResponseElement()
35 | response = element.add(
36 | plivoxml.GetDigitsElement().set_action(action).set_method(method).
37 | set_redirect(redirect).set_timeout(timeout).set_play_beep(playBeep)
38 | .set_finish_on_key(finishOnKey).set_digit_timeout(digitTimeout).
39 | set_timeout(timeout).set_num_digits(numDigits).set_retries(retries)
40 | .set_valid_digits(validDigits).set_invalid_digits_sound(
41 | invalidDigitsSound).set_log(log).add_speak(
42 | content=content_speak,
43 | voice=voice_speak,
44 | language=language_speak,
45 | loop=loop_speak).add_play(
46 | content=content_play, loop=loop_play)).to_string(False)
47 | self.assertXmlEqual(response, expected_response)
48 |
--------------------------------------------------------------------------------
/tests/xml/test_getInputElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 | from plivo import plivoxml
3 | from tests import PlivoXmlTestCase
4 |
5 |
6 | class GetInputElementTest(TestCase, PlivoXmlTestCase):
7 | def test_set_methods(self):
8 | expected_response = 'This is testThis is test' \
15 | ''
16 |
17 | action = 'https://foo.example.com'
18 | method = 'GET'
19 | inputType = 'speech'
20 | executionTimeout = 100
21 | digitEndTimeout = 50
22 | speechEndTimeout = 25
23 | finishOnKey = '#'
24 | numDigits = 2
25 | speechModel = 'default'
26 | hints = '1 2 3'
27 | language = 'en-US'
28 | interimSpeechResultsCallback = 'https://bar.example.com'
29 | interimSpeechResultsCallbackMethod = 'POST'
30 | redirect = False
31 | log = True
32 |
33 | content_speak = 'This is test'
34 | voice_speak = 'WOMAN'
35 | language_speak = 'en-US'
36 | loop_speak = 2
37 | loop_play = 2
38 | content_play = 'This is test'
39 |
40 | element = plivoxml.ResponseElement()
41 | response = element.add(
42 | plivoxml.GetInputElement().set_action(action).set_method(method).
43 | set_input_type(inputType).set_execution_timeout(executionTimeout).
44 | set_digit_end_timeout(digitEndTimeout).set_speech_end_timeout(speechEndTimeout).
45 | set_finish_on_key(finishOnKey).set_num_digits(numDigits).
46 | set_hints(hints).set_interim_speech_results_callback(interimSpeechResultsCallback).
47 | set_interim_speech_results_callback_method(interimSpeechResultsCallbackMethod).set_log(log).
48 | set_redirect(redirect).set_language(language).set_speech_model(speechModel).
49 | add_speak(
50 | content=content_speak,
51 | voice=voice_speak,
52 | language=language_speak,
53 | loop=loop_speak).add_play(
54 | content=content_play, loop=loop_play)
55 | ).to_string(False)
56 | self.assertXmlEqual(response, expected_response)
57 |
--------------------------------------------------------------------------------
/tests/xml/test_hangupElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class HangupElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | schedule = 60
10 | reason = "rejected"
11 | expected_response = ''
12 |
13 | element = plivoxml.ResponseElement()
14 | response = element.add(
15 | plivoxml.HangupElement().set_reason(reason).set_schedule(schedule)
16 | ).to_string(False)
17 | self.assertXmlEqual(response, expected_response)
18 |
--------------------------------------------------------------------------------
/tests/xml/test_messageElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class MessageElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 |
10 | expected_response = 'this is test' \
12 | ''
13 | src = '1202322222'
14 | dst = '1203443444<1203443445'
15 | type = 'sms'
16 | callbackUrl = 'http://foo.example.com'
17 | callbackMethod = 'GET'
18 | content = 'this is test'
19 |
20 | element = plivoxml.ResponseElement()
21 | response = element.add(
22 | plivoxml.MessageElement(content).set_src(src).set_dst(dst)
23 | .set_type(type).set_callback_url(callbackUrl).set_callback_method(
24 | callbackMethod)).to_string(False)
25 | self.assertXmlEqual(response, expected_response)
26 |
--------------------------------------------------------------------------------
/tests/xml/test_numberElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class NumberElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = 'This is Test'
11 |
12 | content = 'This is Test'
13 | send_digits = 'wwww2410'
14 | send_on_preanswer = True
15 | send_digits_mode = ""
16 |
17 | element = plivoxml.ResponseElement()
18 | response = element.add(
19 | plivoxml.DialElement().add(
20 | plivoxml.NumberElement(content).set_send_digits(send_digits).set_send_on_preanswer(
21 | send_on_preanswer
22 | ).set_send_digits_mode(
23 | send_digits_mode
24 | )
25 | )
26 | ).to_string(False)
27 | self.assertXmlEqual(response, expected_response)
28 |
--------------------------------------------------------------------------------
/tests/xml/test_phonemeElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class ElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | alphabet = "ipa"
10 | ph = "təmei̥ɾou̥"
11 | expected_response = 'Well'
13 |
14 | element = plivoxml.ResponseElement()
15 | response = element.add(
16 | plivoxml.SpeakElement("").add(
17 | plivoxml.PhonemeElement("Well").set_alphabet(alphabet).set_ph(ph)
18 | )
19 | ).to_string(False)
20 | self.assertXmlEqual(response, expected_response)
21 |
--------------------------------------------------------------------------------
/tests/xml/test_playElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class PlayElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = 'This is test'
10 |
11 | loop = 1
12 | content = 'This is test'
13 | element = plivoxml.ResponseElement()
14 |
15 | response = element.add(
16 | plivoxml.PlayElement(content).set_loop(loop)
17 | ).to_string(False)
18 | self.assertXmlEqual(response, expected_response)
19 |
--------------------------------------------------------------------------------
/tests/xml/test_recordElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 | from plivo import plivoxml
3 | from tests import PlivoXmlTestCase
4 |
5 |
6 | class RecordElementTest(TestCase, PlivoXmlTestCase):
7 | def test_set_methods(self):
8 | expected_response = '' \
13 | ''
14 | action = 'https://foo.example.com'
15 | method = 'GET'
16 | fileFormat = 'wav'
17 | redirect = False
18 | timeout = 100
19 | maxLength = 10
20 | recordSession = False
21 | startOnDialAnswer = False
22 | playBeep = False
23 | finishOnKey = '#'
24 | transcriptionType = 'hybrid'
25 | transcriptionUrl = 'https://foo.example.com'
26 | transcriptionMethod = 'GET'
27 | callbackUrl = 'https://foo.example.com'
28 | callbackMethod = 'GET'
29 |
30 | element = plivoxml.ResponseElement()
31 | response = element.add(
32 | plivoxml.RecordElement().set_action(action).set_method(method)
33 | .set_file_format(fileFormat).set_redirect(redirect).set_timeout(
34 | timeout).set_max_length(maxLength).set_play_beep(playBeep)
35 | .set_finish_on_key(finishOnKey).set_record_session(recordSession).
36 | set_start_on_dial_answer(startOnDialAnswer).set_transcription_type(
37 | transcriptionType).set_transcription_url(transcriptionUrl)
38 | .set_transcription_method(transcriptionMethod).set_callback_url(
39 | callbackUrl).set_callback_method(callbackMethod)).to_string(False)
40 | self.assertXmlEqual(response, expected_response)
41 |
--------------------------------------------------------------------------------
/tests/xml/test_redirectElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class RedirectElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = 'This is Test'
10 |
11 | method = "POST"
12 | content = 'This is Test'
13 |
14 | element = plivoxml.ResponseElement()
15 | response = element.add(
16 | plivoxml.RedirectElement(content).set_method(method)
17 | ).to_string(False)
18 |
19 | self.assertXmlEqual(response, expected_response)
20 |
--------------------------------------------------------------------------------
/tests/xml/test_sElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class SElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = '' \
10 | 'This is TestThis is ' \
11 | 'TestThis is TestThis is Test' \
14 | 'This is TestThis is Test' \
15 | 'This is Test'
16 |
17 | content_break = 'This is Test'
18 | strength_break = 'strong'
19 | time_break = '250ms'
20 |
21 | content_lang = 'This is Test'
22 | xmllang_lang = "it"
23 |
24 | content_emphasis = 'This is Test'
25 | level_emphasis = 'strong'
26 |
27 | content_phoneme = 'This is Test'
28 | alphabet_phoneme = "ipa"
29 | ph_phoneme = "təmei̥ɾou̥"
30 |
31 | content_prosody = "This is Test"
32 | volume_prosody = "+6dB"
33 | rate_prosody = "x-high"
34 | pitch_prosody = "low"
35 |
36 | content_say_as = 'This is Test'
37 | interpret_as_say_as = "spell-out"
38 | # TODO: need to ask the value
39 | format_say_as = ""
40 |
41 | content_sub = "This is Test"
42 | alias_sub = "World Wide Web Consortium"
43 |
44 | content_w = "This is Test"
45 | role_w = "claws:VV0"
46 |
47 | element = plivoxml.ResponseElement()
48 | response = element.add(
49 | plivoxml.SpeakElement("").add(
50 | plivoxml.SElement().add_break(
51 | strength=strength_break
52 | ).add_emphasis(
53 | content_emphasis,
54 | level=level_emphasis
55 | ).add_lang(
56 | content_lang,
57 | xmllang=xmllang_lang
58 | ).add_phoneme(
59 | content_phoneme,
60 | alphabet=alphabet_phoneme,
61 | ph=ph_phoneme
62 | ).add_prosody(
63 | content_prosody,
64 | volume=volume_prosody,
65 | rate=rate_prosody,
66 | pitch=pitch_prosody
67 | ).add_say_as(
68 | content_say_as,
69 | interpret_as=interpret_as_say_as,
70 | format=format_say_as
71 | ).add_sub(
72 | content_sub,
73 | alias=alias_sub,
74 | ).add_w(
75 | content_w,
76 | role_w
77 | )
78 | )
79 | ).to_string(False)
80 | self.assertXmlEqual(response, expected_response)
81 |
--------------------------------------------------------------------------------
/tests/xml/test_sayAsElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class SayAsElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = '' \
10 | 'This is Test'
11 | interpret_as = "spell-out"
12 | format = "application/ssml+xml"
13 | content = 'This is Test'
14 |
15 | element = plivoxml.ResponseElement()
16 |
17 | response = element.add(
18 | plivoxml.SpeakElement("").add(
19 | plivoxml.SayAsElement(content).set_interpret_as(interpret_as).set_format(format)
20 | )
21 | ).to_string(False)
22 |
23 | self.assertXmlEqual(response, expected_response)
24 |
--------------------------------------------------------------------------------
/tests/xml/test_streamElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from plivo.exceptions import ValidationError
5 | from tests import PlivoXmlTestCase
6 |
7 |
8 | class StreamElementTest(TestCase, PlivoXmlTestCase):
9 | def test_set_methods(self):
10 | expected_response = """
11 | wss://test.url
12 | """
13 |
14 | content = 'wss://test.url'
15 | bidirectional = True
16 | extraHeaders = "a=1,b=2"
17 | keepCallAlive = True
18 |
19 | element = plivoxml.ResponseElement()
20 | response = element.add(
21 | plivoxml.StreamElement(content, bidirectional=bidirectional, extraHeaders=extraHeaders, keepCallAlive=keepCallAlive)
22 | ).to_string(False)
23 | self.assertXmlEqual(response, expected_response)
24 |
25 | def test_validations_on_elements(self):
26 | expected_error = 'bidirectional must be a boolean value.'
27 |
28 | actual_error = ''
29 | content = 'wss://test.url'
30 | bidirectional = "hello"
31 | try:
32 | plivoxml.StreamElement(content=content, bidirectional=bidirectional)
33 | except ValidationError as e:
34 | print("Error: ", str(e))
35 | actual_error = str(e)
36 | self.assertXmlEqual(expected_error, actual_error)
37 |
--------------------------------------------------------------------------------
/tests/xml/test_subElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class SubElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = 'substitution example W3C'
10 | alias="World Wide Web Consortium"
11 |
12 | element = plivoxml.ResponseElement()
13 | response = element.add(
14 | plivoxml.SpeakElement("substitution example ").add(
15 | plivoxml.SubElement("W3C").set_alias(alias)
16 | )
17 | ).to_string(False)
18 | self.assertXmlEqual(response, expected_response)
19 |
--------------------------------------------------------------------------------
/tests/xml/test_userElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class UserElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = 'This is Test'
11 |
12 | content = 'This is Test'
13 | send_digits = 'wwww2410'
14 | send_on_preanswer = True
15 | sip_headers = 'head1=val1,head2=val2'
16 |
17 | element = plivoxml.ResponseElement()
18 |
19 | response = element.add(
20 | plivoxml.DialElement().add(
21 | plivoxml.UserElement(content).set_send_digits(send_digits).set_send_on_preanswer(
22 | send_on_preanswer
23 | ).set_sip_headers(sip_headers)
24 | )
25 | ).to_string(False)
26 | self.assertXmlEqual(response, expected_response)
27 |
--------------------------------------------------------------------------------
/tests/xml/test_wElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class WElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = 'This is Test' \
10 | 'This is Test' \
11 | 'This is TestThis is Test' \
14 | 'This is TestThis is Test' \
15 | ''
16 |
17 | role = 'claws:VV0'
18 | content = 'This is Test'
19 |
20 | content_break = 'This is Test'
21 | strength_break = 'strong'
22 | time_break = '250ms'
23 |
24 | content_emphasis = 'This is Test'
25 | level_emphasis = 'strong'
26 |
27 | content_phoneme = 'This is Test'
28 | alphabet_phoneme = "ipa"
29 | ph_phoneme = "təmei̥ɾou̥"
30 |
31 | content_prosody = "This is Test"
32 | volume_prosody = "+6dB"
33 | rate_prosody = "x-high"
34 | pitch_prosody = "low"
35 |
36 |
37 | content_say_as = 'This is Test'
38 | interpret_as_say_as = "spell-out"
39 | format_say_as = ""
40 |
41 | content_sub = "This is Test"
42 | alias_sub = "World Wide Web Consortium"
43 |
44 | element = plivoxml.ResponseElement()
45 | response = element.add(
46 | plivoxml.SpeakElement("").add(
47 | plivoxml.WElement(content).set_role(
48 | role
49 | ).add_break(
50 | strength=strength_break
51 | ).add_emphasis(
52 | content_emphasis,
53 | level=level_emphasis
54 | ).add_phoneme(
55 | content_phoneme,
56 | alphabet=alphabet_phoneme,
57 | ph=ph_phoneme
58 | ).add_prosody(
59 | content_prosody,
60 | volume=volume_prosody,
61 | rate=rate_prosody,
62 | pitch=pitch_prosody
63 | ).add_say_as(
64 | content_say_as,
65 | interpret_as=interpret_as_say_as,
66 | format=format_say_as
67 | ).add_sub(
68 | content_sub,
69 | alias=alias_sub,
70 | ))
71 | ).to_string(False)
72 | self.assertXmlEqual(response, expected_response)
73 |
--------------------------------------------------------------------------------
/tests/xml/test_waitElement.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from plivo import plivoxml
4 | from tests import PlivoXmlTestCase
5 |
6 |
7 | class WaitElementTest(TestCase, PlivoXmlTestCase):
8 | def test_set_methods(self):
9 | expected_response = ''
10 |
11 | length = 1
12 | silence = True
13 | min_silence = 1
14 | beep = True
15 |
16 | element = plivoxml.ResponseElement()
17 | response = element.add(
18 | plivoxml.WaitElement().set_length(length).set_silence(
19 | silence
20 | ).set_min_silence(min_silence).set_beep(beep)
21 | ).to_string(False)
22 |
23 | self.assertXmlEqual(response, expected_response)
24 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | # Tox (https://tox.readthedocs.io/) is a tool for running tests in multiple
2 | # virtualenvs. This configuration file helps to run the test suite on all
3 | # supported Python versions. To use it, "pip install tox" and then run "tox"
4 | # from this directory.
5 |
6 | [tox]
7 | envlist =
8 | py27
9 | py34
10 | py35
11 | py36
12 | py37
13 | py38
14 | py39
15 | py310
16 | py311
17 | pypy
18 |
19 | [testenv]
20 | commands = pytest --cov=plivo --cov-report={posargs}
21 |
22 | # tox doesn't install deps automatically after env is created
23 | # so some deps are repeated here and in setup.py
24 | # see https://github.com/tox-dev/tox/issues/496#issuecomment-289854245
25 |
26 | deps =
27 | coverage
28 | pytest
29 | pytest-cov
30 | httmock
31 | six
32 | lxml
33 |
34 | setenv =
35 | PYTHONPATH = {toxinidir}/
36 |
--------------------------------------------------------------------------------