def _handle_500_error(self, raw_response):
     request_id = raw_response.headers["X-Request-Id"]
     if raw_response.json():
         message = raw_response.json()["data"]
     else:
         message = "There was no error message"
     raise exceptions.KazooApiError("Internal Server Error, "
                                    "Request ID was {0}"
                                    " message was {1}".format(
                                        request_id, message))
Exemple #2
0
    def getUser(self, accountId, kazooUserId):

        if accountId is None or kazooUserId is None:
            raise exceptions.KazooApiError(
                u'accountId {} and kazooUserId {} must be provided'.format(
                    accountId, kazooUserId))

        result = self.kazooCli.get_user(accountId, kazooUserId)

        return result
Exemple #3
0
 def _handle_error(self, error_data):
     if error_data["error"] == "400" and ("data" in error_data):
         raise exceptions.KazooApiBadDataError(error_data["data"])
     raise exceptions.KazooApiError(
         "There was an error calling the kazoo api, "
         "Request ID was {1}"
         "the error was {0}".format(
             error_data["message"],
             error_data["request_id"],
         ))
Exemple #4
0
    def createEnterpriseAccount(self, enterpriseId, name):
        '''
        Given a enterprise id and name, create an account on Kazoo

        enterpriseId Id of the EnterpriseAccount to be created on kazoo (unique)
        name Name of the EnterpriseAccount to be created on kazoo
        '''

        logging.info(u'createEnterpriseAccount invoked with {},{}'.format(
            enterpriseId, name))

        if enterpriseId is None or name is None:
            raise exceptions.KazooApiError(
                u'EnterpriseId {} and Name {} must be provided'.format(
                    enterpriseId, name))

        result = {}

        @retry(3)
        def _wrappedAccountCreation(result):
            '''
            Wrap calls to account creation to allow for retries
            '''

            result.update(
                self.kazooCli.create_account({
                    u'name':
                    str(enterpriseId),
                    u'enterprise_id':
                    str(enterpriseId),
                    u'enterprise_name':
                    name,
                    u'realm':
                    u'{}.sip.sendhub.com'.format(enterpriseId)
                }))

            return ('data' in result and 'id' in result['data'])

        if _wrappedAccountCreation(result):
            logging.info(
                'Created account {} successfully. Kazoo id = {}'.format(
                    enterpriseId, result['data']['id']))

            # create the no-match call flow for this account
            # so the global carrier stuff works
            self.kazooCli.create_callflow(result['data']['id'],
                                          deepcopy(NO_MATCH_CALL_FLOW))
        else:
            logging.error(
                'Unable to create account on kazoo: {}'.format(result))

            raise Exception('Kazoo account creation error: {}'.format(result))

        return result
Exemple #5
0
    def _handle_error(self, error_data):
        if error_data["error"] == "400" and ("data" in error_data):
            raise exceptions.KazooApiBadDataError(error_data["data"])

        if error_data['error'] == '401':
            raise exceptions.KazooApiAuthenticationError('Invalid credentials')

        raise exceptions.KazooApiError(
            "There was an error calling the kazoo api,"
            " Request ID was {1} the error was {0}".format(error_data["message"],
                                                           error_data["request_id"])
        )
Exemple #6
0
    def updateUser(self, accountId, kazooUserId, updateData):
        '''
        Update a user on Kazoo within an given account
        updateData is a dictionary of optional (specific) overwrites over current user data in Kazoo
        '''

        if accountId is None or kazooUserId is None or updateData is None:
            raise exceptions.KazooApiError(
                u'accountId {} and kazooUserId {} and updateData {} must be provided'
                .format(accountId, kazooUserId, updateData))

        currentUserRes = self.kazooCli.get_user(accountId, kazooUserId)
        if currentUserRes['status'] != 'success':
            raise exceptions.KazooApiError(
                u'Failed to get user: accountId {}, kazooUserId {}'.format(
                    accountId, kazooUserId))

        userData = currentUserRes['data']
        userData.update(updateData)
        result = self.kazooCli.update_user(accountId, kazooUserId, userData)

        return result
Exemple #7
0
    def copyMedia(self, accountId, mediaId, fromUrl):

        # this function doesn't fit the general model for crossbar API URLs hence why it is hand built
        try:
            c = None
            fh = None

            mediaData = wget(fromUrl, numTries=3)

            toUrl = '{}/accounts/{}/media/{}/raw'.format(
                self.kazooCli.base_url, accountId, mediaId)

            fh = tempfile.NamedTemporaryFile(mode='wr+b')
            fh.write(mediaData)
            fh.flush()
            fh.seek(0)

            c = pycurl.Curl()
            c.setopt(pycurl.URL, toUrl)
            c.setopt(pycurl.READFUNCTION, fh.read)
            c.setopt(pycurl.POST, 1)
            c.setopt(pycurl.HTTPHEADER, [
                "Content-type: audio/mp3", "X-Auth-Token: {}".format(
                    self.kazooCli.auth_token)
            ])
            c.setopt(pycurl.POSTFIELDSIZE, os.path.getsize(fh.name))
            response = cStringIO.StringIO()
            c.setopt(c.WRITEFUNCTION, response.write)

            logging.info(u'Uploading file %s to url %s' % (fh.name, toUrl))

            c.perform()
            returnCode = c.getinfo(pycurl.HTTP_CODE)
            logging.info("File upload %s Http %d Response %s" %
                         (fh.name, returnCode, response.getvalue()))
            if returnCode != 200:
                raise exceptions.KazooApiError(
                    'Failed upload media, return code %d' % returnCode)

        finally:
            if c is not None:
                c.close()
            if fh is not None:
                fh.close()
Exemple #8
0
    def createUser(self,
                   accountId,
                   name,
                   userId,
                   password,
                   enterpriseId,
                   sipUsername,
                   sipPassword,
                   softPhoneNumber=None,
                   cellPhoneNumbers=[],
                   email=None):
        '''
        Create a user on Kazoo within an given enterprise or within the general sendhub enterprise

        accountId: Account on kazoo which this user will be created under
        name: ShUser name
        userId: Id of the user
        password: Password to set on kazoo
        enterpriseId: The id of the enterprise account. The account must already exist on kazoo.
        sipUsername: SIP device username for the web device
        sipPassword: SIP password for the web device
        softPhoneNumber: Voip number too add for this account
        cellPhoneNumbers: Cell phone numbers to add for this account
        email: Email address for this account (will be set to a unique-bogus email if not specified as kazoo requires it)
        '''

        logging.info(u'createUser invoked with {},{},{},{},{},{},{},{}'.format(
            accountId, name, userId, password, enterpriseId, sipUsername,
            softPhoneNumber, cellPhoneNumbers))

        userDetails = {
            'id': None,
            'first_name': None,
            'username': None,
            'voicemailId': None,
            'softphoneId': None,
            'cellphoneIds': [],
            'callFlowId': None,
            'autoAttendantMenuId': None,
            'temporalRuleId': None
        }

        shortSoftPhoneNumber = None

        if name is None or userId is None or password is None:
            raise exceptions.KazooApiError(
                u'userId () and Name () must be provided'.format(userId, name))

        createUserResult = None
        try:
            userSettings = {
                u'first_name':
                name,
                u'last_name':
                'SH',
                u'username':
                str(userId),
                u'password':
                password,
                u'enterprise_id':
                str(enterpriseId),
                u'email':
                u'{}@no-reply.sendhub.com'.format(email)
                if email is None else email,
                u'vm_to_email_enabled':
                False,
            }

            if softPhoneNumber is not None:
                shortSoftPhoneNumber = softPhoneNumber[
                    2:] if softPhoneNumber.startswith(
                        "+1") else softPhoneNumber
                callerId = {
                    u'caller_id': {
                        u'internal': {
                            u'name': name,
                            u'number': shortSoftPhoneNumber
                        },
                        u'external': {
                            u'name': name,
                            u'number': shortSoftPhoneNumber
                        }
                    }
                }
                userSettings.update(callerId)

            createUserResult = self.kazooCli.create_user(
                accountId, userSettings)

            if createUserResult['status'] == 'success':
                userDetails['id'] = createUserResult['data']['id']
                userDetails['name'] = createUserResult['data']['first_name']
                userDetails['username'] = createUserResult['data']['username']
                userDetails['enterpriseId'] = createUserResult['data'][
                    'enterprise_id']

                callFlow = deepcopy(DEFAULT_KAZOO_CALL_FLOW)

                softPhoneDeviceResult = None
                if softPhoneNumber is not None:
                    createNumberResult = self.createPhoneNumber(
                        accountId, shortSoftPhoneNumber)

                    if 'data' not in createNumberResult or 'id' not in createNumberResult[
                            'data']:
                        raise exceptions.KazooApiError(
                            u'Unable to create phone number: {}'.format(
                                shortSoftPhoneNumber))

                    callFlow['numbers'].append(softPhoneNumber)

                    softPhoneDeviceResult = self.createDevice(
                        type=u'softphone',
                        accountId=accountId,
                        userId=userId,
                        ownerId=userDetails['id'],
                        number=shortSoftPhoneNumber,
                        username=sipUsername,
                        password=sipPassword)

                    userDetails['softphoneId'] = softPhoneDeviceResult['data'][
                        'id'] if softPhoneDeviceResult is not None else None

                callFlow['numbers'].append(str(userId))
                callFlow['flow']['data']['id'] = str(userDetails['id'])

                cellPhoneResults = []
                for number in cellPhoneNumbers:
                    if number is not None:
                        shortNumber = number[2:] if number.startswith(
                            "+1") else number
                        cellPhoneResult = self.createDevice(
                            type=u'cellphone',
                            accountId=accountId,
                            userId=userId,
                            ownerId=userDetails['id'],
                            number=shortNumber)
                        if cellPhoneResult is not None:
                            cellPhoneResults.append(cellPhoneResult)
                userDetails['cellphoneIds'] = [{
                    'id':
                    cellPhoneResult['data']['id'],
                    'number':
                    '+1{}'.format(
                        cellPhoneResult['data']['call_forward']['number'])
                } for cellPhoneResult in cellPhoneResults]

                # the following requires that the schema be changed on kazoo.
                # so if this fails, then check
                vmBoxObj = self.kazooCli.create_voicemail_box(
                    accountId, {
                        'mailbox': str(userId),
                        'check_if_owner': True,
                        'require_pin': False,
                        'name': str(userId),
                        'check_if_owner': True,
                        'delete_after_notify': True,
                        'owner_id': str(userDetails['id'])
                    })
                userDetails['voicemailId'] = vmBoxObj['data']['id']
                callFlow['flow']['children']['_']['data']['id'] = userDetails[
                    'voicemailId']

                callFlowResult = self.kazooCli.create_callflow(
                    accountId, callFlow)
                userDetails['callFlowId'] = callFlowResult['data']['id']

                autoAttendantMenuResult = self.kazooCli.create_menu(
                    accountId, {
                        'name': str(userId),
                        'retries': 3,
                        'timeout': '10000',
                        'max_extension_length': '1'
                    })
                userDetails['autoAttendantMenuId'] = autoAttendantMenuResult[
                    'data']['id']

                temporalRuleResult = self.kazooCli.create_temporal_rule(
                    accountId, {
                        'name':
                        str(userId),
                        'time_window_start':
                        0,
                        'time_window_stop':
                        86400,
                        'wdays': [
                            'monday', 'tuesday', 'wednesday', 'thursday',
                            'friday', 'saturday', 'sunday'
                        ],
                        'name':
                        '{}'.format(str(userId)),
                        'cycle':
                        'weekly',
                        'start_date':
                        62586115200,
                        'ordinal':
                        'every',
                        'interval':
                        1
                    })

                userDetails['temporalRuleId'] = temporalRuleResult['data'][
                    'id']

        except Exception as e:

            logging.error(u'Unable to create user on Kazoo: {}'.format(e))
            import traceback
            traceback.print_exc(e)

            # if we couldn't create the user then try to delete them so
            # we can try again
            if createUserResult is not None and createUserResult[
                    'status'] == 'success':
                logging.error(u'Deleting partially created user')
                self.deleteUser(
                    accountId, userDetails['id'], shortSoftPhoneNumber,
                    userDetails['cellphoneIds'].extend([
                        userDetails['softphoneId']
                    ]), userDetails['voicemailId'], userDetails['callFlowId'],
                    userDetails['autoAttendantMenuId'],
                    userDetails['temporalRuleId'])
            raise

        return userDetails