HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: //home/arjun/projects/buyercall_forms/buyercall/buyercall/blueprints/phonenumbers/views.py
import os
import csv
import json
import uuid
import time
import os.path as path
from contextlib import closing
from io import StringIO
import logging as log
import xmltodict
import traceback
from datetime import date, datetime

from flask import (
    Blueprint,
    request,
    flash,
    url_for,
    jsonify,
    redirect,
    current_app as app,
    send_from_directory,
    make_response,
    render_template)
from flask_login import login_required, current_user
from sqlalchemy import or_, and_
from sqlalchemy.orm import defer
from sqlalchemy.sql import text
from sqlalchemy.sql.expression import func, case
from buyercall.blueprints.phonenumbers.forms import PhoneForm
from buyercall.blueprints.partnership.models import PartnershipAccount
from buyercall.blueprints.phonenumbers.models import (
    HoldMusic,
    Phone,
)
from buyercall.blueprints.mobile.models import Endpoint
from buyercall.blueprints.user.decorators import role_required
from flask_babel import gettext as _
from datatables import DataTables, ColumnDT

from buyercall.blueprints.billing.decorators import subscription_required
from buyercall.blueprints.filters import format_phone_number
from buyercall.extensions import csrf
from buyercall.extensions import db
from buyercall.lib.util_crypto import AESCipher
from buyercall.lib.util_twilio import (
    bw_client,
    account_client,
    subaccount_client
)
from buyercall.lib.util_bandwidth import bw_client as bw_dashboard_client
from buyercall.lib.bandwidth import BandwidthException
from twilio.base.exceptions import TwilioRestException
from buyercall.blueprints.leads.models import Lead
from buyercall.blueprints.partnership.models import PartnershipCpaasPhoneNumberSubscriptions as NumberSubscription

phonenumbers = Blueprint('phonenumbers', __name__, template_folder='templates')

MAX_FILE_SIZE = 4 * 1024 * 1024


class ClientError(Exception):
    def __init__(self, message):
        self.message = message


# Inbound Routing onboarding page
@phonenumbers.route('/inbound_onboarding', methods=['GET', 'POST'])
@login_required
@role_required('admin', 'partner', 'sysadmin')
def onboarding_inbound():
    if request.method == 'POST':
        current_user.inbound_onboard = True
        db.session.commit()

    if current_user.inbound_onboard:
        flash(_('Great, you are ready to get started with the Inbound Routing '
                'Wizard feature. Remember to checkout the support section or '
                'FAQ if you have any additional inbound routing questions.'),
              'success')
        return redirect(url_for('phonenumbers.inbound_list'))

    return render_template('phonenumbers/inbound_onboarding.jinja2')


@phonenumbers.route('/inbound/install-instructions/<int:id>', methods=['GET'])
@login_required
@role_required('admin')
def install_instructions(id):
    partnership_account_id = current_user.partnership_account_id
    is_admin_in_group = current_user.is_admin_user_with_groups
    viewing_partnership_account = current_user.is_viewing_partnership
    # Check if being viewed by super partner
    if is_admin_in_group and viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id
    elif not viewing_partnership_account and is_admin_in_group:
        return redirect(url_for('partnership.company_accounts'))

    inbound = Phone.query.filter(
        Phone.id == id, Phone.partnership_account_id == partnership_account_id
    ).first()
    if inbound is None:
        return redirect(url_for('.inbound_list'))

    greeting_messages = 'Custom audio file' if (
        inbound.routing_config.get('whisperMessageType', '') == 'audio'
    ) else 'Text to speech'

    retry_count = ['Never', 'Once', 'Twice'][inbound.routing_config['defaultRouting']['retryRouting']]

    notify_leads = inbound.notifications.get('notifyLeads')

    if notify_leads == 'missed':
        notifications = 'Missed calls only'
    elif notify_leads == 'all':
        notifications = 'All calls'
    else:
        notifications = 'Disabled'
    auto_attendance = 'Enabled' if (
        inbound.routing_config.get('routingType') == 'digits'
    ) else 'Disabled'

    call_recording = 'Enabled' if (
        inbound.routing_config.get('recordCalls')
    ) else 'Disabled'

    call_backs = 'Enabled' if (
        inbound.routing_config.get('callBack')
    ) else 'Disabled'

    if call_backs == 'Enabled':
        call_back_intervals = ', '.join('{} min'.format(x) for x in [
            inbound.routing_config.get('firstCallBack'),
            inbound.routing_config.get('secondCallBack'),
            inbound.routing_config.get('thirdCallBack'),
         ] if x)
    else:
        call_back_intervals = 'Disabled'

    return render_template(
        'phonenumbers/inbound_instructions.jinja2', id=id,
        phonenumber=inbound.phonenumber,
        friendlyname=inbound.friendly_name,
        source=inbound.source,
        type=inbound.type,
        status=inbound.active,
        agents_list=inbound.agents_list,
        mobile_agent_email=inbound.mobile_agent_email,
        mobile_agent_id=inbound.mobile_agent_id,
        greeting_messages=greeting_messages,
        retry_count=retry_count,
        notifications=notifications,
        notification_recipients=', '.join(inbound.notification_recipients),
        auto_attendance=auto_attendance,
        call_recording=call_recording,
        voicemail='Enabled' if inbound.routing_config.get('voicemail') else 'Disabled',
        hold_music='Enabled' if inbound.routing_config.get('playHoldMusic') else 'Disabled',
        custom_hold_music='Enabled' if inbound.routing_config.get('customHoldMusic') else 'Disabled',
        call_backs=call_backs,
        call_back_intervals=call_back_intervals,
    )


@phonenumbers.route('/inbound/email-instructions/<int:id>', methods=['POST'])
@login_required
@role_required('admin')
def email_instructions(id):
    from .tasks import send_phonenumber_email
    partnership_account_id = current_user.partnership_account_id
    is_admin_in_group = current_user.is_admin_user_with_groups
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if is_admin_in_group and viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id
    elif not viewing_partnership_account and is_admin_in_group:
        return redirect(url_for('partnership.company_accounts'))

    try:
        inbound = Phone.query.filter(
            Phone.id == id, Phone.partnership_account_id == partnership_account_id
        ).first()
        if not inbound:
            return redirect(url_for('.inbound_list'))
        email = request.form['email']
        send_phonenumber_email.delay(inbound.phonenumber, email, inbound.partnership_account_id)
    except Exception:
        log.error(traceback.format_exc())
        flash(
            _('Sorry, we were unable to send the email.'), 'danger'
        )
    finally:
        return redirect(url_for('.install_instructions', id=id))


@phonenumbers.route('/inbound')
@login_required
@role_required('admin')
def inbound_list():
    partnership_account_id = current_user.partnership_account_id
    is_admin_in_group = current_user.is_admin_user_with_groups
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if is_admin_in_group and viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id
    elif not viewing_partnership_account and is_admin_in_group:
        return redirect(url_for('partnership.company_accounts'))

    # Check if onboarding was excepted
    if current_user.inbound_onboard is False:
        return redirect(url_for('phonenumbers.onboarding_inbound'))

    filter_by = partnership_account_id == Phone.partnership_account_id
    # defining the initial query depending on your purpose
    paginated_phone = Phone.query.filter(filter_by).count()
    subscription = current_user.subscription
    subscriped = subscription is not None and subscription.status == 'active'
    return render_template('phonenumbers/phonenumbers.jinja2',
                           phonenumbers=paginated_phone,
                           subscribed=subscriped)


# return agent data into jquery datatables
@phonenumbers.route('/phone-data')
@csrf.exempt
@login_required
@role_required('admin')
def data():
    """Return server side data."""
    # defining columns
    search = request.args.get('search[value]', '')
    order = int(request.args.get('order[0][column]', '-1'))
    direction = request.args.get('order[0][dir]', 'asc')
    offset = int(request.args.get('start', 0))
    limit = int(request.args.get('length', 99))
    columns = [
        'id', 'friendly_name', 'phonenumber', 'type', 'lead_count',
        'created_on', 'updated_on'
    ]
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    total = Phone.query.filter(
        (Phone.partnership_account_id == partnership_account_id),
        Phone.is_deactivated.is_(False)
    )

    leads = Lead.query.filter(
        Lead.partnership_account_id == partnership_account_id
    ).with_entities(
        Lead.inbound_id,
        func.sum(1).label('lead_count')
    ).group_by(Lead.inbound_id).subquery()

    filtered = total
    if search:
        pattern = '%{}%'.format(search)
        filtered = total.filter(or_(
            Phone.friendly_name.ilike(pattern),
            Phone.phonenumber.like(pattern),
            Phone.toll_type.ilike(pattern)
        ))

    filtered = filtered.outerjoin(
        (leads, Phone.id == leads.c.inbound_id)
    ).with_entities(
        Phone.id,
        Phone.friendly_name,
        Phone.phonenumber,
        Phone.toll_type.label('type'),
        case(
            [(leads.c.lead_count.is_(None), 0)],
            else_=leads.c.lead_count
        ).label('lead_count'),
        Phone.created_on,
        Phone.updated_on
    )

    sorted_ = filtered
    if 0 <= order < len(columns):
        order_pred = '{} {}'.format(columns[order], direction)
        sorted_ = sorted_.order_by(text(order_pred))
    sorted_ = sorted_.offset(offset).limit(limit)

    data = [
        {i: col for i, col in enumerate(row)} for row in sorted_.all()
    ]

    return jsonify(
        draw=request.args['draw'],
        recordsFiltered=filtered.count(),
        recordsTotal=total.count(),
        data=data
    )


# return agent data into jquery datatables
@phonenumbers.route('/inbound/csv')
@login_required
@role_required('admin')
def data_csv():
    """Return server side data."""
    # defining columns
    header = [
        'No', 'Friendly Name', 'Phone Number', 'Type', 'Lead Count',
        'Created On', 'Updated On'
    ]
    fields = [
        'id', 'friendly_name', 'phonenumber', 'type', 'lead_count',
        'created_on', 'updated_on'
    ]
    columns = [
        ColumnDT(Phone.id),
        ColumnDT(Phone.friendly_name),
        ColumnDT(Phone.phonenumber),
        ColumnDT(Phone.type),
        ColumnDT(Phone.lead_count),
        ColumnDT(Phone.created_on),
        ColumnDT(Phone.updated_on)
    ]
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    # TODO: defer_by routing_config
    query = db.session.query().select_from(Phone).group_by(Phone.id).filter(
        partnership_account_id == Phone.partnership_account_id
    )
    row_table = DataTables(request.args, query, columns)
    result = row_table.output_result()

    # Build the CSV
    row_no = 0
    with closing(StringIO()) as out:
        writer = csv.writer(out)
        writer.writerow(header)
        for row in result['data']:
            csv_row = [row[key] for key in sorted(row.keys())]
            row_no += 1
            csv_row[0] = row_no
            writer.writerow(csv_row)

        filename = 'Buyercall Inbound Routings - {}.csv'.format(
            date.today().strftime('%Y-%m-%d')
        )

        resp = make_response(out.getvalue())

        resp.headers['Content-Type'] = 'text/csv'
        resp.headers['Content-Disposition'] = \
            'attachment; filename="{}"'.format(filename)
        return resp


@phonenumbers.route('/inbound/new', methods=['GET'])
@login_required
@subscription_required
@role_required('admin')
def inbound_new():
    phone = Phone()
    form = PhoneForm(obj=phone)
    partnership_account_id = current_user.partnership_account_id
    is_admin_in_group = current_user.is_admin_user_with_groups
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if is_admin_in_group and viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id
    elif not viewing_partnership_account and is_admin_in_group:
        return redirect(url_for('partnership.company_accounts'))

    total_phonenumbers = Phone.query.filter(
        partnership_account_id == Phone.partnership_account_id
    ).count()

    # check only for phonenumbers that's not deactivated
    total_active_phonenumbers = Phone.query.filter(
        partnership_account_id == Phone.partnership_account_id
    ).filter(Phone.is_deactivated == '0').count()

    from buyercall.blueprints.agents.models import Agent
    partner_agent = Agent.query \
        .filter(Agent.partnership_account_id == partnership_account_id).first()

    partner_agent_phone = format_phone_number(partner_agent.phonenumber)

    # Check to see if user exceeded his plan's phonenumber limit
    subscription = current_user.partnership_account.subscription
    # Set the plan limit as a variable
    plan_number_limit = subscription.phonenumber_limit

    if plan_number_limit <= total_active_phonenumbers:
        log.info('the subscription phone number limit is {}'.format(plan_number_limit))
        log.info('the current phone number total is {}'.format(total_active_phonenumbers))
        if current_user.subscription.plan == 'partnershipsingle':
            flash(_(
                'You have reached your plans phone number limit. Please <a href='"/support"' style='"color:#ffffff"'>'
                '<strong>contact BuyerCall support</strong></a> '
                'if you are interested in more phone number and call features. '), 'warning')
            return redirect(url_for('phonenumbers.inbound_list'))
        else:
            flash(_(
                'You have reached your plans phone number limit. '
                'Please <a href='"/subscription/update"' style='"color:#ffffff"'>'
                '<strong>Upgrade your plan</strong></a> to active more phone numbers '), 'danger')
            return redirect(url_for('phonenumbers.inbound_list'))

    log.info('the subscription phone number limit is {}'.format(plan_number_limit))
    log.info('the current phone number total is {}'.format(total_active_phonenumbers))

    # Check to see how many priority phone numbers are used and check it against plan limit
    # check only for phonenumbers that's not deactivated
    total_active_priority_numbers = Phone.query.filter(
        partnership_account_id == Phone.partnership_account_id
    ).filter(Phone.is_deactivated == '0').filter(Phone.type == 'priority').count()

    # Set the plan's prioirty number limit as variable
    plan_priority_limit = subscription.priority_number_limit
    log.info('the user has {} active priority numbers'.format(total_active_priority_numbers))
    log.info('the subscription phone number limit is {}'.format(plan_priority_limit))

    return render_template(
        'phonenumbers/wizard.jinja2', form=form,
        phone=phone, total_phonenumbers=total_phonenumbers,
        total_active_priority_numbers=total_active_priority_numbers,
        plan_priority_limit=plan_priority_limit,
        agent=partner_agent,
        agent_phone=partner_agent_phone,
    )


@phonenumbers.route('/inbound/<int:id>', methods=['GET'])
@login_required
@subscription_required
@role_required('admin')
def phonenumber_edit(id):
    partnership_account_id = current_user.partnership_account_id
    is_admin_in_group = current_user.is_admin_user_with_groups
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if is_admin_in_group and viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id
    elif not viewing_partnership_account and is_admin_in_group:
        return redirect(url_for('partnership.company_accounts'))

    routing = Phone.query.filter(
        Phone.partnership_account_id == partnership_account_id,
        Phone.id == id,
    ).first()
    if not routing:
        flash('Inbound routing with ID {} not found.'.format(id))
        return redirect(url_for('phonenumbers.inbound_list'))

    # This variable is to state if the leads name gets whisper to the agent
    # If it's set to true it will be whispered. If false no whisper. By default
    # its false.
    caller_whisper = routing.caller_id

    from buyercall.blueprints.agents.models import Agent
    partner_agent = Agent.query \
        .filter(Agent.partnership_account_id == partnership_account_id).first()

    partner_agent_phone = format_phone_number(partner_agent.phonenumber)

    routing_data = routing.as_dict()
    log.info('The pre-routing data is: {}'.format(routing_data))
    if routing_data['routingConfig'].get('configSMSSetup', '') and \
            routing_data['routingConfig'].get('SMSAutoReply', '') \
            and routing_data['routingConfig'].get('SMSAutoReplyImageUrl', ''):
        mms_url = routing_data['routingConfig'].get('SMSAutoReplyImageUrl', '')
        media_key = (mms_url.split('/', 3)[-1]).split('?')[0].replace('%20', ' ')
        bucket = app.config['MMS_BUCKET']
        from buyercall.lib.util_boto3_s3 import generate_presigned_aws_url
        presigned_mms_url = generate_presigned_aws_url(media_key, bucket)
        routing_data['routingConfig']['SMSAutoReplyImageUrl'] = presigned_mms_url
        log.info('The post-routing data is: {}'.format(routing_data))
    json_routing_data = json.dumps(routing_data).replace('</', '<\\/')
    return render_template(
        'phonenumbers/wizard.jinja2', model_data=json_routing_data,
        phone=routing,
        caller_whisper=caller_whisper,
        agent=partner_agent,
        agent_phone=partner_agent_phone,
    )


@phonenumbers.route('/inbound/hold-music', methods=['POST'])
@login_required
@subscription_required
@role_required('admin', 'partner', 'sysadmin')
def upload_hold_music():
    def allowed_file(file_ext):
        return file_ext in ['.mp3', '.wav']

    file = request.files['file']
    file_ext = path.splitext(file.filename.lower())[1]
    if not file:
        return make_response('Error uploading file.', 400)

    if not allowed_file(file_ext):
        return make_response('File extension not allowed: {}'.format(file_ext), 400)

    if file.content_length and file.content_length > MAX_FILE_SIZE:
        return make_response('File too large.', 400)

    file_guid = str(uuid.uuid4())

    file_path = path.join(app.config['UPLOAD_FOLDER'], file_guid)
    file.save(file_path)

    if path.getsize(file_path) > MAX_FILE_SIZE:
        os.remove(file_path)
        return make_response('File too large.', 400)

    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    hold_music = HoldMusic(
        partnership_account_id=partnership_account_id,
        uuid=file_guid,
        filename=file.filename
    )
    db.session.add(hold_music)
    db.session.commit()

    from .bw_tasks import bw_upload_holdmusic
    bw_upload_holdmusic(current_user.id, hold_music.id, file_path)

    return jsonify(guid=file_guid, filename=file.filename)


@phonenumbers.route('/inbound/hold-music/<file_guid>', methods=['GET'])
def hold_music(file_guid):
    file_dir = path.join(app.config['UPLOAD_FOLDER'], 'hold_music')
    return send_from_directory(file_dir, file_guid, mimetype='audio/mpeg')


@phonenumbers.route('/api/inbound/routings', methods=['GET'])
@login_required
@subscription_required
@role_required('admin', 'partner', 'sysadmin')
def get_routings():
    return jsonify(data=[])


@phonenumbers.route('/api/inbound/routings', methods=['POST'])
@login_required
@subscription_required
@role_required('admin')
def create_routing():
    current_partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        current_partnership_account_id = current_user.get_user_viewing_partnership_account_id

    model = request.json

    routing = Phone(
        partnership_account_id=current_partnership_account_id
    )

    routing.phonenumber = model['phoneNumber']
    routing.friendly_name = model['friendlyName']
    routing.source = model['source']
    routing.channel = model['channel']
    routing.caller_id = model['callerId']
    routing.routing_config = model['routingConfig']
    routing.notifications = model['notificationConfig']
    routing.type = model['type']
    routing.local = (model['typePn'] == 'local')
    routing.tollfree = (model['typePn'] == 'tollfree')

    provider = 'bandwidth' if model['type'] in ['tracking', 'mobile'] else 'twilio'
    routing.provider = provider

    try:
        log.info('Purchasing number from {}'.format(provider))
        if provider == 'bandwidth':
            if model['type'] == 'mobile':
                # Auto-generate a sip username and password for mobile app use
                username = routing.mobile_agent_email.split('@')[0]
                username_hex = uuid.uuid4().hex[:5]
                sip_username = '{}{}_{}'.format(username, username_hex, routing.partnership_account_id)
                # Create a random password string used for mobile passwords
                random_pwd = uuid.uuid4().hex[:23].lower().replace('0', 'X').replace('o', 'Y').replace('e', 'E')
                sip_password = random_pwd
                # Provision the mobile phone number using the sip username and password
                purchase_bw_mobile(routing, sip_username, sip_password)
            else:
                purchase_bw(routing)
        elif provider == 'twilio':
            purchase_twilio(routing)

        routing.connect_audio_files()

        return jsonify(routing.as_dict())
    except Exception:
        log.error(traceback.format_exc())
        db.session.rollback()
        return 'Error while purchasing phone number', 500


def endpoint_exists_check_bw(partnership_id, sip_username):
    exists = False
    client = bw_client(partnership_id)

    # Lets get the domain now using the partnership_id
    from ..mobile.models import Domain
    domain = Domain.query\
        .filter(and_(Domain.is_deactivated == False, Domain.partnership_id == partnership_id))\
        .first()

    if domain is not None:
        # Check to see if the username exists in the endpoints
        found_endpoints = client.domains.get_endpoints(domain_id=domain.domain_id)

        if found_endpoints is not None:
            for endpoint in found_endpoints:
                if 'credentials' in endpoint:
                    cred = endpoint['credentials']

                    if 'username' in cred:
                        username = cred['username']

                        if username == sip_username:
                            exists = True
                            break

    return exists


def purchase_bw(routing, api_call=False, partnership_account=None):
    # Check to see if it is an api_call. If it is, check the partner/account details.
    if api_call and partnership_account is not None:
        log.info('Purchasing via API call. Using API token details.')
        partnership_account_id = partnership_account.id
    else:
        log.info('Purchasing via frontend. Using current_user details.')
        partnership_account_id = current_user.partnership_account_id

    # import partnership information to get partnership id
    from buyercall.blueprints.partnership.models import Partnership, PartnershipAccount, PartnershipCpaasProviders
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == partnership_account_id).first()

    dashboard_client = bw_dashboard_client(partner_account.partnership_id)

    # Check to see if there's a phone number order subscription available for the partnership
    current_subscription = NumberSubscription.query\
        .filter(NumberSubscription.order_type == 'orders').first()
    # If there's no current subscription we need to create one and save it to the database
    if not current_subscription:
        call_back_url = 'https://{}{}'.format(
            app.config.get('SERVER_DOMAIN'),
            url_for('phonenumbers.subscription_callback')
        )
        create_subscription = dashboard_client.subscriptions.subscribe(order_type='orders',
                                                                       callback_url=call_back_url,
                                                                       expiry='3153600000')
        subscription_id = create_subscription.rsplit('/', 1)[-1]
        # Save the new order subscription to the database
        subscription = NumberSubscription(
            cpaas_provider_name='bandwidth',
            partnership_id=partner_account.partnership_id,
            order_type='orders',
            subscription_id=subscription_id,
            callback_url=call_back_url
        )
        db.session.add(subscription)
        db.session.commit()
        log.info('A new subscription has been added for phone number orders')

    # We don't want to purchase phone numbers when debugging/testing
    if app.config.get('DEBUG', False):
        log.warning('DEBUG is enabled; not purchasing the number.')
        # Just take our first defined phone number to get a fake Id
        test_number = app.config['BANDWIDTH_CALLER_ID']
        test_order_id = app.config['BANDWIDTH_ORDER_ID']
        valid_test_number = dashboard_client.in_service_number.validate(test_number)
        if valid_test_number == 200:
            bw_number_id = test_order_id
            # Use the config bandwidth number as phone number for testing purposes
            routing.phonenumber = format_phone_number(app.config['BANDWIDTH_CALLER_ID'])
        else:
            flash(_('The bandwidth test number does not exist. A 404 error was received.'), 'danger')
            log.info('The bandwidth test number does not exist. A 404 error was received.')
            return ''
    else:
        # Order a phone number in the Dashboard platform. Below we will import it into the
        # Application platform after creating an application
        unformatted_phone_number = routing.phonenumber
        # We need to remove the +1 from the phone number, because the Dashboard Order API doesn't allow for it
        bw_pn_formatted = unformatted_phone_number.replace("+1", "")
        log.info('The phone number passed to the BW Dashboard Order API is: {}'.format(bw_pn_formatted))
        order_bw_number = dashboard_client.phone_numbers.order(partner_account_id=str(partnership_account_id),
                                                               name='{}:{} - ({}) - {}'.format(
                                                                   partnership_account_id,
                                                                   routing.id,
                                                                   routing.type,
                                                                   routing.friendly_name
                                                               ),
                                                               phonenumber=bw_pn_formatted)
        # Get the order id from the location url by splitting the url
        bw_number_id = order_bw_number.rsplit('/', 1)[-1]

        # If the sms config is set to True lets set a messaging url variable otherwise leave it empty
        if routing.routing_config.get("configSMSSetup", False):
            sms_enabled = 'on'
        else:
            sms_enabled = 'off'
        # We need to delay the updating of TN to enable/disable SMS. We delay with celery task
        from .bw_tasks import update_tn
        update_tn.apply_async(args=[str(partnership_account_id), partner_account.partnership_id,
                                    bw_pn_formatted, 'tracking', sms_enabled], countdown=180)

    routing.twilio_number_sid = bw_number_id
    # Save the phone number and routing to the database
    db.session.add(routing)
    db.session.commit()


def purchase_bw_mobile(routing, sip_username, sip_password, api_call=False, api_sip_description=None, partnership_account=None):

    # Check to see if it is an api_call. If it is, check the partner/account details.
    if api_call and partnership_account is not None:
        log.info('Purchasing via API call. Using API token details.')
        partnership_account_id = partnership_account.id
    else:
        log.info('Purchasing via frontend. Using current_user details.')
        partnership_account_id = current_user.partnership_account_id

    # import partnership information to get partnership id
    from buyercall.blueprints.partnership.models import Partnership, PartnershipAccount, PartnershipCpaasProviders
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    dashboard_client = bw_dashboard_client(partner.id, tn_type='mobile')

    # Check to see if there's a phone number order subscription available for the partnership
    current_subscription = NumberSubscription.query \
        .filter(NumberSubscription.order_type == 'orders').first()
    # If there's no current subscription we need to create one and save it to the database
    if not current_subscription:
        call_back_url = 'https://{}{}'.format(
            app.config.get('SERVER_DOMAIN'),
            url_for('phonenumbers.subscription_callback')
        )
        create_subscription = dashboard_client.subscriptions.subscribe(
            order_type='orders',
            callback_url=call_back_url,
            expiry='3153600000'
        )
        subscription_id = create_subscription.rsplit('/', 1)[-1]
        # Save the new order subscription to the database
        subscription = NumberSubscription(
            cpaas_provider_name='bandwidth',
            partnership_id=partner.id,
            order_type='orders',
            subscription_id=subscription_id,
            callback_url=call_back_url
        )
        db.session.add(subscription)
        db.session.commit()
        log.info('A new subscription has been added for phone number orders')

    # We don't want to purchase phone numbers when debugging/testing
    if app.config.get('DEBUG', False):
        log.warning('DEBUG is enabled; not purchasing the number.')
        # Just take our first defined phone number to get a fake Id
        test_number = app.config['BANDWIDTH_CALLER_ID_MOBILE']
        test_order_id = app.config['BANDWIDTH_ORDER_ID']
        valid_test_number = dashboard_client.in_service_number.validate(test_number)
        if valid_test_number == 200:
            bw_number_id = test_order_id
            # Use the config bandwidth number as phone number for testing purposes
            routing.phonenumber = format_phone_number(app.config['BANDWIDTH_CALLER_ID_MOBILE'])
        else:
            flash(_('The bandwidth test number does not exist. A 404 error was received.'), 'danger')
            log.info('The bandwidth test number does not exist. A 404 error was received.')
            return ''
    else:
        # Order a phone number in the Dashboard platform. Below we will import it into the
        # Application platform after creating an application
        unformatted_phone_number = routing.phonenumber
        # We need to remove the +1 from the phone number, because the Dashboard Order API doesn't allow for it
        bw_pn_formatted = unformatted_phone_number.replace("+1", "")
        log.info('The mobile number passed to the BW Dashboard Order API is: {}'.format(bw_pn_formatted))
        order_bw_number = dashboard_client.phone_numbers.order(partner_account_id=str(partnership_account_id),
                                                               name='{}:{} - ({}) - {}'.format(
                                                                   partnership_account_id,
                                                                   routing.id,
                                                                   routing.type,
                                                                   routing.friendly_name
                                                               ),
                                                               phonenumber=bw_pn_formatted)
        # Get the order id from the location url by splitting the url
        bw_number_id = order_bw_number.rsplit('/', 1)[-1]

        # Always enable SMS for mobile numbers
        sms_enabled = 'on'
        # We need to delay the updating of TN to enable/disable SMS. We delay with celery task
        from .bw_tasks import update_tn
        update_tn.apply_async(args=[str(partnership_account_id), partner_account.partnership_id,
                                    bw_pn_formatted, 'mobile', sms_enabled], countdown=180)

    routing.twilio_number_sid = bw_number_id
    # Save the imported phone number and routing to the database
    db.session.add(routing)
    db.session.commit()

    # Lets get the domain now using the partnership_id
    from buyercall.blueprints.mobile.models import Domain
    # This is the same as realm,
    realm = Domain.query\
        .filter(and_(Domain.is_deactivated.is_(False), Domain.partnership_id == partner.id)).first()

    # Lets create a sip endpoint now
    if api_call and api_sip_description is not None and api_sip_description is not '':
        sip_description = api_sip_description
    else:
        sip_description = '{} sip domain endpoint for mobile account use'.format(realm.name)

    endpoint = dashboard_client.realms.create_sip_credentials(
        realm_id=realm.domain_id,
        realm=realm.sip_realm,
        sip_username=sip_username,
        sip_password=sip_password
    )
    # Lets get the information on the newly created sip endpoint
    # get_endpoint = client.domains.get_endpoint(domain_id=realm.domain_id, endpoint_id=endpoint.id)
    # log.info('The endpoint info is {}'.format(get_endpoint))
    log.info('The sip response is: {}'.format(endpoint.content.decode()))
    print(endpoint.status_code)
    if 300 >= endpoint.status_code:
        endpoint_content = xmltodict.parse(endpoint.content.decode())
        json_endpoint_content = json.loads(json.dumps(endpoint_content))
        endpoint_id = json_endpoint_content['SipCredentialsResponse']['ValidSipCredentials']['SipCredential']['Id']
        endpoint_uri = 'sip:' + sip_username + '@' + realm.sip_realm
        endpoint_username = json_endpoint_content['SipCredentialsResponse']['ValidSipCredentials']['SipCredential']['UserName']
        endpoint_hash_1 = json_endpoint_content['SipCredentialsResponse']['ValidSipCredentials']['SipCredential']['Hash1']
        endpoint_hash_1_b = json_endpoint_content['SipCredentialsResponse']['ValidSipCredentials']['SipCredential']['Hash1b']
        log.info('The endpoint id is: {}'.format(endpoint_id))
        # Get the agent assigned to the SIP from the routing configuration
        agents = routing.routing_config.get("defaultRouting").get("agents")
        agent_id = agents[0].get("id")

        # Create a SIP endpoint in BuyerCall for the specific phone number and application created above
        Endpoint.create(sip_description, realm.provider, endpoint_id, endpoint_uri, sip_username,
                        sip_password, True, routing.id, agent_id, partnership_account_id, realm.id, False,
                        hash_1=endpoint_hash_1, hash_1_b=endpoint_hash_1_b)

        # Return the newly created sip endpoint info
        sip_endpoint = Endpoint.query\
            .filter(and_(Endpoint.sip_username == endpoint_username,
                         Endpoint.is_deactivated.is_(False))).first()

        # Generate a QR code for the sip endpoint account so that they can login to app
        log.info('The partner name is {}'.format(partner_account.name))
        from buyercall.blueprints.mobile.tasks import qr_code
        qr = qr_code(sip_endpoint.sip_username,
                     sip_endpoint.sip_password,
                     partner_account.id,
                     partner_account.name,
                     realm.cloud_id)

        # Save the QR link to the sip endpoint database
        sip_endpoint.qr_url = qr
        db.session.commit()
    else:
        log.info('Unable to create endpoint for sip username {} and account {}'
                 .format(sip_username, partner_account.id))
    return ''


def purchase_twilio(routing, api_call=False, partnership_account=None):
    # Check to see if it is an api_call. If it is, check the partner/account details.
    if api_call and partnership_account is not None:
        partnership_account_id = partnership_account.id
        log.info('Purchasing via API call. Using API token details.')
        if partnership_account.subscription is not None:
            twilio_subaccount_sid = partnership_account.subscription.twilio_subaccount_sid
        elif partnership_account.partnership.subscription is not None:
            twilio_subaccount_sid = partnership_account.subscription.twilio_subaccount_sid
    else:
        log.info('Purchasing via frontend. Using current_user details.')
        twilio_subaccount_sid = current_user.subscription.twilio_subaccount_sid
        partnership_account_id = current_user.partnership_account_id

    # import partnership information to get partnership id
    from buyercall.blueprints.partnership.models import Partnership, PartnershipAccount
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    client = subaccount_client(twilio_subaccount_sid, partner.id)

    # We don't want to purchase phone numbers when debugging/testing
    if app.config.get('DEBUG', False):
        log.warning('DEBUG is enabled; not purchasing the number.')
        twilio_number = client.incoming_phone_numbers.list()[0]
        # twilio_number = twilio_number[0] if twilio_number else None
    else:
        # TODO: Fix Twilio purchasing
        if routing.local:
            twilio_number = client.incoming_phone_numbers.local.create(
                phone_number=routing.phonenumber
            )
        else:
            twilio_number = client.incoming_phone_numbers.toll_free.create(
                phonenumber=routing.phonenumber
            )

    routing.twilio_number_sid = twilio_number.sid
    routing.phonenumber = twilio_number.phone_number

    numbers = client.incoming_phone_numbers.list(
        phone_number=twilio_number.phone_number
    )

    db.session.add(routing)
    db.session.commit()

    numbers[0].update(
        voice_url=url_for(
            'twilio_inbound.lead_inbound_call',
            inbound_id=routing.id,
            _external=True,
            _scheme='https'
        ),
        status_callback=url_for(
            'twilio_inbound.call_result_callback',
            _external=True,
            _scheme='https'
        ),
        sms_url=url_for(
            'tw_sms_inbound.lead_inbound_message',
            inbound_id=routing.id,
            _external=True,
            _scheme='https'
        ),
        voice_caller_id_lookup=True
    )


@phonenumbers.route('/api/inbound/routings/<int:id>', methods=['GET'])
def get_routing(id):
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    routing = Phone.query.filter(
        Phone.partnership_account_id == partnership_account_id,
        Phone.id == id,
    ).one()
    return jsonify(routing.as_dict())


@phonenumbers.route('/api/inbound/routings/<int:id_>', methods=['PUT'])
@login_required
@subscription_required
@role_required('admin', 'partner', 'sysadmin')
def update_routing(id_):
    partnership_account_id = current_user.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    model = request.json
    log.info(f'request data is:{model}')
    routing = Phone.query.filter(
        Phone.partnership_account_id == partnership_account_id,
        Phone.id == id_,
    ).one()

    routing.phonenumber = model['phoneNumber']
    routing.friendly_name = model['friendlyName']
    routing.routing_config = model['routingConfig']
    routing.caller_id = model['callerId']
    routing.notifications = model['notificationConfig']
    db.session.commit()

    routing.connect_audio_files()

    # import partnership information to get partnership id
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == partnership_account_id).first()
    # Only update the TN in Bandwidth if DEBUG is false
    if not app.config.get('DEBUG'):
        # If the sms config is set to True lets set a messaging url variable otherwise leave it empty
        if routing.routing_config.get("configSMSSetup") or routing.type == 'mobile':
            sms_enabled = 'on'
        else:
            sms_enabled = 'off'
        # If it's a bandwidth number update the SMS enable status for the TN
        if routing.provider == 'bandwidth':
            unformatted_phone_number = routing.phonenumber
            bw_pn_formatted = unformatted_phone_number.replace("+1", "")
            if routing.type == 'mobile':
                dashboard_client = bw_dashboard_client(partner_account.partnership_id, tn_type='mobile')
                dashboard_client.phone_numbers_options.update(partner_account_id=str(partnership_account_id),
                                                              phonenumber=bw_pn_formatted,
                                                              sms_option=sms_enabled,
                                                              #sms_campaign_id=app.config.get('SMS_MOBILE_CAMPAIGN_ID'),
                                                              #sms_campaign_class=app.config.get('SMS_MOBILE_CAMPAIGN_CLASS')
                                                              )
            else:
                dashboard_client = bw_dashboard_client(partner_account.partnership_id)
                dashboard_client.phone_numbers_options.update(partner_account_id=str(partnership_account_id),
                                                              phonenumber=bw_pn_formatted,
                                                              sms_option=sms_enabled)
    return jsonify(routing.as_dict())


@phonenumbers.route('/api/inbound/routings/<int:id_>', methods=['DELETE'])
@login_required
@subscription_required
@role_required('admin', 'partner', 'sysadmin')
def delete_routing(id_):
    routing = Phone.query.filter(Phone.id == id_).first()
    if not routing:
        return jsonify(success=True)

    partnership_account_id = routing.partnership_account_id
    viewing_partnership_account = current_user.is_viewing_partnership

    # Check if being viewed by super partner
    if viewing_partnership_account:
        partnership_account_id = current_user.get_user_viewing_partnership_account_id

    # import partnership information to get partnership id
    from buyercall.blueprints.partnership.models import Partnership, PartnershipAccount
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    # If debugging, do not delete the numbers
    if not app.config.get('DEBUG'):
        if routing.provider == 'bandwidth':
            delete_bw(routing)
        elif routing.provider == 'twilio':
            delete_twilio(routing)

    routing.is_deactivated = True
    routing.deactivated_on = datetime.now()
    db.session.commit()

    if routing.type == 'mobile':
        # Get the endpoint associated with this number
        from buyercall.blueprints.mobile.models import Endpoint
        endpoint = Endpoint.query.filter(Endpoint.inbound_id == id_).first()
        # Lets get the domain now using the partnership_id
        from ..mobile.models import Domain
        if endpoint:
            realm = Domain.query.filter(Domain.id == endpoint.domain_id).first()

            # Deactivate the sip_endpoint in BuyerCall
            Endpoint.deactivate(endpoint.id, current_user.partnership_account_id)
            # Delete the endpoint from the provider
            if routing.provider == 'bandwidth' and realm:
                dashboard_client = bw_dashboard_client(partner.id, tn_type='mobile')
                dashboard_client.realms.delete_sip_credentials(
                    realm_id=realm.domain_id,
                    endpoint_id=endpoint.provider_id,
                )

    return jsonify(success=True)


def delete_bw(routing):
    # import partnership information to get partnership id
    from ..partnership.models import Partnership, PartnershipAccount
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == routing.partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    if routing.type == 'mobile':
        dashboard_client = bw_dashboard_client(partner.id, tn_type='mobile')
    else:
        dashboard_client = bw_dashboard_client(partner.id)

    # Check to see if there's a phone number disconnect subscription available for the partnership
    current_subscription = NumberSubscription.query \
        .filter(NumberSubscription.order_type == 'disconnects').first()
    # If there's no current subscription we need to create one and save it to the database
    if current_subscription is None:
        call_back_url = 'https://' + app.config.get('SERVER_DOMAIN') + url_for('phonenumbers.subscription_callback')
        create_subscription = dashboard_client.subscriptions.subscribe(order_type='disconnects',
                                                                       callback_url=call_back_url,
                                                                       expiry='3153600000')
        subscription_id = create_subscription.rsplit('/', 1)[-1]
        # Save the new order subscription to the database
        subscription = NumberSubscription(
            cpaas_provider_name='bandwidth',
            partnership_id=partner.id,
            order_type='disconnects',
            subscription_id=subscription_id,
            callback_url=call_back_url
        )
        db.session.add(subscription)
        db.session.commit()
        log.info('A new subscription has been added for phone number disconnects')
    # Delete the phone number from Dashboard platform using V2 API
    unformatted_phone_number = routing.phonenumber
    bw_pn_formatted = unformatted_phone_number.replace("+1", "")
    dashboard_client.phone_numbers.disconnect(partner_account.name, bw_pn_formatted)


def delete_twilio(routing):
    # import partnership information to get partnership id
    from ..partnership.models import Partnership, PartnershipAccount
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == routing.partnership_account_id).first()
    # Get the partner id to get relevant twilio credentails with twilio client
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    sub_twilio_client = subaccount_client(
        current_user.subscription.twilio_subaccount_sid, partner.id)
    sub_twilio_client.incoming_phone_numbers(routing.twilio_number_sid).delete()


@phonenumbers.route('/api/inbound/search', methods=['GET'])
@login_required
@subscription_required
@role_required('admin', 'partner', 'sysadmin')
def phonenumber_search():
    """ Used for updating phone number search results. Arguments:
     * tollfree - true if we're searching for a toll-free or local number
     * prefix - local prefix (e.g. '312')
     * phrase - a string of letters/numbers to search for, e.g. 'CARS'
     * type - either tracking or priority or mobile.
    """
    tollfree = (request.args.get('tollfree') == 'true')
    type = request.args['type']
    prefix = request.args.get('prefix')
    phrase = request.args.get('phrase')
    city = request.args.get('city')
    state = request.args.get('state')
    phrase = '*{}*'.format(phrase) if phrase else None

    partnership_account_id = current_user.partnership_account_id

    # What is the provider we're searching?
    provider = 'bandwidth' if type in ['tracking', 'mobile'] else 'twilio'

    try:
        if provider == 'bandwidth':
            numbers_list = bandwidth_search(tollfree, prefix, phrase, city, state, partnership_account_id, tn_type=type)
        else:
            numbers_list = twilio_search(tollfree, prefix, phrase, city, state, partnership_account_id)
        return jsonify(data=numbers_list)
    except ClientError as e:
        log.error(traceback.format_exc())
        return e.message, 400
    except BandwidthException as e:
        log.error(traceback.format_exc())
        return e.message, 400
    except TwilioRestException as e:
        log.error(traceback.format_exc())
        return e, 400
    except Exception as e:
        log.error(traceback.format_exc())
        # error_details = e.message.split('DETAIL: ')
        error_details = None

        if error_details is not None and len(error_details) >= 2:
            error_message = error_details[1]
        else:
            error_message = 'An unexpected error has occurred.'
        return error_message, 400


def bandwidth_search(tollfree, prefix, phrase, city, state, partnership_account_id, tn_type=None):
    # import partnership information to get partnership id
    from ..partnership.models import Partnership, PartnershipAccount
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == partnership_account_id).first()
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
    if tn_type and tn_type == 'mobile':
        client = bw_dashboard_client(partner.id, tn_type='mobile')
    else:
        client = bw_dashboard_client(partner.id)
    updated_number_list = []
    if not tollfree:
        kwargs = {}
        count = 0

        if prefix is not None and prefix is not '':
            if len(prefix) != 3:
                raise ClientError('An area code must be 3 digits.')

            kwargs['areaCode'] = prefix
            count = count + 1

        if phrase is not None and phrase is not '':
            kwargs['localVanity'] = phrase
            count = count + 1

        if city is not None and city is not '':
            kwargs['city'] = city
            count = count + 1

        if state is not None and state is not '':
            kwargs['state'] = state
            count = count + 1

        if count == 0:
            raise ClientError('No search parameters provided.')
        else:
            kwargs['quantity'] = '18'
            numbers = client.available_numbers.search(**kwargs)
            # We converted the xml list of numbers to a dict, but now we need to load it as json object
            no_json = json.loads(numbers)
            # Then we need to work through the nested json to get just the list of numbers
            if no_json['SearchResult'] is not None:
                try:
                    numbers_list = no_json['SearchResult']['TelephoneNumberList']['TelephoneNumber']
                    updated_number_list = []
                    for number in numbers_list:
                        number = '+1' + number
                        updated_number_list.append(number)
                    log.info('the numbers are: {}'.format(updated_number_list))
                except BandwidthException as e:
                    log.error('The exception is: {}'.format(e))

    else:
        # The prefix is the 3 digits of the Toll-free number. However, Bandwidth only allows 3 characters
        # and you have to include a wildcard(*), therefore we remove a digit from prefix
        kwargs = {}
        if prefix is not None and prefix is not '':
            pattern = (prefix[:-1] or '') + '*'
            # Set the query string for the GET available search request for toll-free numbers
            kwargs['tollFreeWildCardPattern'] = pattern
        else:
            pattern = (phrase or '') + '*'
            kwargs['tollFreeVanity'] = pattern
        # Return 12 numbers to choose from in the UI
        kwargs['quantity'] = '18'
        numbers = client.available_numbers.search(**kwargs)
        log.info('the numbers are: {}'.format(numbers))
        # We converted the xml list of numbers to a dict, but now we need to load it as json object
        no_json = json.loads(numbers)
        # Then we need to work through the nested json to get just the list of numbers
        if no_json['SearchResult'] is not None:
            try:
                numbers_list = no_json['SearchResult']['TelephoneNumberList']['TelephoneNumber']
                updated_number_list = []
                for number in numbers_list:
                    number = '+1' + number
                    updated_number_list.append(number)
                log.info('the numbers are: {}'.format(updated_number_list))
            except BandwidthException as e:
                log.error('The exception is: {}'.format(e))

    return updated_number_list


def twilio_search(tollfree, prefix, phrase, city, state, partnership_account_id):
    # import partnership information to get partnership id
    from ..partnership.models import Partnership, PartnershipAccount
    partner_account = PartnershipAccount.query \
        .filter(PartnershipAccount.id == partnership_account_id).first()
    # Get the partner id to get relevant twilio credentails with twilio client
    partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()

    twilio_client = account_client(partner.id)
    country = app.config.get('COUNTRY', 'US')

    if not tollfree:
        numbers = twilio_client.available_phone_numbers(country).local.list(
            area_code=prefix,
            contains=phrase,
            in_region=state
        )
    else:
        numbers = twilio_client.available_phone_numbers(country).toll_free.list(
            area_code=prefix,
            contains=phrase
        )
    numbers_list = [x.phone_number for x in numbers]
    return numbers_list


@phonenumbers.route('/inbound/edit/<int:id>', methods=['GET', 'POST'])
@subscription_required
@role_required('admin')
@login_required
def phone_edit(id):
    phone = Phone.query.get(id)

    form = PhoneForm(obj=phone)

    if form.validate_on_submit():
        form.populate_obj(phone)
        phone.save()

        flash(_('The phone number has been updated successfully.'), 'success')
        return redirect(url_for('phonenumbers.inbound_list'))

    return render_template('phonenumbers/edit.jinja2', phone=phone,
                           form=form)


@phonenumbers.route('/inbound/phonenumberSubscriptionCallback/', methods=['GET', 'POST'])
@csrf.exempt
def subscription_callback():
    # This function is a call back url after an phone number action, like a order is performed
    # Get the params of the Request
    data = xmltodict.parse(request.data)
    json_data = json.dumps(data)
    load_json_data = json.loads(json_data)
    from .tasks import send_callback_email
    send_callback_email.delay(load_json_data)
    log.info('The phone number subscription callback content is: {}'.format(load_json_data))
    return ''