File: //home/arjun/projects/buyercall_new/buyercall/buyercall/blueprints/phonenumbers/bw_tasks.py
import os
import traceback
import logging as log
from datetime import datetime, timedelta
from tempfile import TemporaryFile
import uuid
import pytz
import boto3
import redis
from flask import url_for, current_app as app
from sqlalchemy.orm import load_only, subqueryload
from buyercall.app import create_celery_app
from buyercall.lib.util_twilio import (
CallStorage,
subaccount_client,
InboundCallState as State,
bw_client,
select_voice,
split_name,
)
from buyercall.lib.util_webhooks import WebhookUtil
from buyercall.lib.messages import (
MSG_SERVICE_UNAVAILABLE
)
from buyercall.extensions import db
from ..leads.models import Lead
from ..agents.models import Agent
from ..phonenumbers.models import (
Phone,
HoldMusic,
Audio,
)
from .routing import (
get_routing_agents,
get_agent_number
)
from ..contacts.models import Contact
from .bw_inbound import hold_music_url
HOURS = 3600
DAYS = 86400 # The length of a day in seconds
AGENT_TIMEOUT = 30
# TODO Parse Redis URL
celery = create_celery_app(app)
webhooker = WebhookUtil()
@celery.task
def bw_lead_accept_or_reject_call(inbound_id, call_id, **kwargs):
inbound = Phone.query.options(
subqueryload(Phone.partnership_account)
).filter(
Phone.id == inbound_id
).first()
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == inbound.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
if inbound is None:
log.error('Cannot find inbound route {} in the database!'.format(
inbound_id
))
client.calls[call_id].reject()
return
# Check if the account has been disabled; if so, reject the call
if not inbound.partnership_account.has_active_subscription:
log.error('Partnership account {} has no active subscription!'.format(
inbound.partnership_account_id
))
client.calls[call_id].reject()
return
client.calls[call_id].accept()
@celery.task
def bw_lead_create(
inbound_id, call_id, phone_number, caller_name=None, start_time=None, **kwargs
):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
inbound = Phone.query.filter(
Phone.id == inbound_id
).first()
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == inbound.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
first_name, last_name = split_name(caller_name)
if (not first_name and not last_name) or (first_name == 'Unknown'):
first_name, last_name = Lead.get_last_known_name(
inbound.partnership_account_id, phone_number
)
previous_lead = Lead.query.filter(
phone_number == Lead.phonenumber,
inbound.partnership_account_id == Lead.partnership_account_id
).order_by(Lead.created_on.desc()).first()
if previous_lead is not None:
contact_id = previous_lead.contact_id
progress_status = previous_lead.progress_status
else:
contact_id = None
progress_status = 'no status'
lead = Lead(
partnership_account_id=inbound.partnership_account_id,
firstname=first_name,
lastname=last_name,
phonenumber=phone_number,
email='',
starttime=datetime.utcnow(),
call_sid=call_id,
call_type='inbound',
my_phone=inbound.phonenumber,
call_source=inbound.friendly_name,
inbound_id=inbound_id,
status='ringing',
contact_id=contact_id,
originating_number=phone_number,
progress_status=progress_status
)
db.session.add(lead)
db.session.commit()
# Return Bandwidth call for CNAM value for lead
# info = client.number_info(phone_number)
# if not info:
# log.debug('Caller ID information not found')
# return
# log.debug('Caller info: {}'.format(info))
# Query the leads table to retrieve the latest lead that was added
latest_lead = Lead.query\
.filter(Lead.phonenumber == phone_number)\
.order_by(Lead.created_on.desc())\
.first()
log.info('latest lead: {}'.format(latest_lead))
# Query contacts to see if lead already exist in the contacts table
contact = Contact.query\
.filter(Contact.phonenumber_1 == latest_lead.phonenumber)\
.filter(Contact.partnership_account_id == inbound.partnership_account_id)\
.first()
if contact:
log.info('a lead exist with number {}'.format(contact.phonenumber_1))
contact.updated_on = latest_lead.updated_on
# contact.caller_id = info.get('name', '')
log.info('The updated date is: {}'.format(latest_lead.updated_on))
db.session.commit()
else:
contact = Contact(
firstname=first_name,
lastname=last_name,
# caller_id=info.get('name', ''),
phonenumber_1=phone_number,
email='',
partnership_account_id=inbound.partnership_account_id,
)
db.session.add(contact)
db.session.commit()
log.info('The contact has been added')
new_contact = Contact.query\
.filter(Contact.phonenumber_1 == latest_lead.phonenumber)\
.filter(Contact.partnership_account_id == inbound.partnership_account_id)\
.first()
if new_contact:
latest_lead.contact_id = new_contact.id
db.session.commit()
else:
log.info('no lead contact exist')
# Associate the lead ID with the Bandwidth call ID
key = 'CALL:{}'.format(call_id)
redis_db.setex(key, 2*HOURS, lead.id)
storage = CallStorage(redis_db, lead.id)
storage.init()
storage.call_sid = call_id
storage.routing_config = inbound.routing_config
storage.clear_retry_cnt()
storage.clear_callback_cnt()
storage.caller_number = phone_number
storage.start_time = start_time
# TODO: Bandwidth user ID
storage.subaccount_sid = None
storage.state = State.NEW
storage.inbound = inbound.phonenumber
if previous_lead is not None:
storage.caller_name = caller_name
# Make a CNAM lookup to find out the caller ID
# TODO: Make this conditional on the agent's settings
bw_lead_cnam_lookup.delay(lead.id, phone_number)
webhooker.trigger_generic_webhook('operational_start_call', lead.id)
client.calls[call_id].redirect(url_for(
'bw_inbound.lead_inbound_call_continue',
lead_id=lead.id,
_external=True
))
bw_lead_whisper_message.delay(lead.id, call_id, inbound_id)
@celery.task
def bw_lead_cnam_lookup(lead_id, phone_number, **kwargs):
lead = Lead.query.filter(Lead.id == lead_id).first()
if not lead:
log.warning('Lead not found in the database')
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
# Check leads in the database for caller ID information
created_cutoff = datetime.utcnow().replace(tzinfo=pytz.utc) - timedelta(days=30)
existing = Lead.query.filter(
Lead.phonenumber == lead.phonenumber,
Lead.partnership_account_id == lead.partnership_account_id,
Lead.caller_id != '',
Lead.created_on > created_cutoff,
).first()
if existing:
log.debug('Using existing caller ID')
lead.caller_id = existing.caller_id
db.session.commit()
return
info = client.number_info(phone_number)
if not info:
log.debug('Caller ID information not found')
return
log.debug('Caller info: {}'.format(info))
lead.caller_id = info.get('name', '')
db.session.commit()
@celery.task
def bw_lead_whisper_message(lead_id, call_id, inbound_id, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
inbound = Phone.query.options(
subqueryload(Phone.partnership_account)
).filter(
Phone.id == inbound_id
).first()
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == inbound.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
storage = CallStorage(redis_db, lead_id)
log.debug('{}: {}'.format(lead_id, storage.state))
routing_config = storage.routing_config
routing_type = routing_config.get('routingType', '')
language = routing_config.get('language', 'en')
gender, locale, voice = select_voice(language)
whisper_message = routing_config.get('whisperMessage', '')
whisper_message_type = routing_config.get('whisperMessageType', '')
whisper_message_audio = routing_config.get('whisperMessageAudio', '')
if routing_type == 'default':
routing = routing_config['defaultRouting']
storage.routing = routing
# If there's a whisper message, say it
if whisper_message_type == 'audio':
audio = Audio.query.filter(
Audio.id == whisper_message_audio,
Audio.inbound_id == inbound_id,
Audio.whisper_message_type == 'whisperMessage',
Audio.enabled == True,
).order_by(Audio.id.desc()).first()
if audio:
client.calls[call_id].audio(
file_url=audio.audio_url,
tag='whisper_default',
)
return
elif whisper_message:
# TODO: language
client.calls[call_id].audio(
sentence=whisper_message,
gender=gender,
locale=locale,
voice=voice,
tag='whisper_default'
)
return
# Otherwise play hold music and call agents directly
bw_play_hold_music(lead_id, call_id, routing_config)
bw_call_agents.delay(lead_id, routing)
elif routing_type == 'digits':
client.calls[call_id].gather({
'prompt': {
'sentence': whisper_message,
'gender': gender,
'locale': locale
},
'max_digits': 1
})
else:
log.error(
'Unknown routing type for lead {}'.format(lead_id)
)
client.calls[call_id].audio(
sentence=MSG_SERVICE_UNAVAILABLE,
gender=gender, locale=locale, voice=voice
)
@celery.task
def bw_play_hold_music(lead_id, call_id, routing_config, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
storage = CallStorage(redis_db, lead_id)
lead = Lead.query.filter(Lead.id == lead_id).first()
if not lead:
log.warning('Lead not found in the database')
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
conf = client.conferences.create(
from_=storage.inbound,
callback_url=url_for(
'bw_inbound.lead_inbound_conference',
lead_id=lead_id,
_external=True
)
)
storage.bw_conf_id = conf.id
conf.add_member(call_id)
conf.audio(
file_url=hold_music_url(routing_config),
loop_enabled='true',
tag='hold_music',
)
@celery.task
def bw_stop_hold_music(lead_id, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
storage = CallStorage(redis_db, lead_id)
lead = Lead.query.filter(Lead.id == lead_id).first()
if not lead:
log.warning('Lead not found in the database')
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
client.conferences[storage.bw_conf_id].audio(file_url='')
@celery.task
def bw_call_agents(lead_id, routing, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
storage = CallStorage(redis_db, lead_id)
agents = get_routing_agents(routing)
agent_ids = [a.id for a in agents]
call_order = routing.get('callOrder', '')
if call_order == 'shuffle':
import random
log.debug('Shuffling agent list...')
random.shuffle(agent_ids)
call_order = 'sequence'
storage.call_order = call_order
storage.set_agents_to_call(agent_ids)
bw_try_call_agent_sequence(routing, lead_id)
@celery.task
def bw_try_call_agent_sequence(routing, lead_id, **kwargs):
""" Call a single agent from the list of available agents.
"""
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
storage = CallStorage(redis_db, lead_id)
lead = Lead.query\
.join(Lead.inbound)\
.filter(Lead.id == lead_id)\
.first()
calls = None
a = None
while not calls:
agent_id = storage.next_agent_to_call()
if not agent_id:
log.info('No more agents left to call.')
break
a = Agent.query.filter(Agent.id == agent_id).first()
if not a:
continue
agents_to_call = a.agents if a.is_group else [a]
calls = bw_call_multiple_agents(
agents=agents_to_call, lead=lead, routing=routing
)
if not calls:
bw_redirect_to_voicemail(lead_id)
# client.calls[storage.call_sid].hangup()
else:
webhooker.trigger_generic_webhook('operational_agent_call', lead_id)
if a and lead:
contact = Contact.query.filter(Contact.id == lead.contact_id).first()
if contact and not contact.agent_id and contact.agent_id != a.id:
contact.agent_id = a.id
contact.agent_assigned = a.full_name
db.session.commit()
from buyercall.blueprints.mobile.utils import send_agent_push_notification
send_agent_push_notification(contact)
def bw_call_multiple_agents(agents=None, lead=None, routing=None, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
storage = CallStorage(redis_db, lead.id)
calls = []
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
for agent in agents:
try:
agent_number, extension = get_agent_number(agent, routing)
# digits = 'wwww' + extension if extension else None
if not agent_number:
log.warning(u'Invalid agent number for {}'.format(agent.full_name))
continue
with storage.lock():
if storage.state in [
State.NEW, State.LEAD_ONHOLD, State.CALLBACK_PROMPT
]:
call = client.call(
from_=lead.inbound.phonenumber,
to=agent_number,
callback_url=url_for(
'bw_inbound.agent_status_callback',
lead_id=lead.id,
agent_id=agent.id,
_external=True,
_scheme='https'
),
callback_http_method='POST'
)
storage.push_agent_call(agent.id, call.id)
calls.append(call)
except Exception as e:
log.warning(traceback.format_exc())
log.warning('Error calling agent {}...'.format(
agent.id
))
return calls
@celery.task
def bw_hangup_calls(call_ids, **kwargs):
for call_id in call_ids:
lead = Lead.query.filter(Lead.call_sid == call_id).first()
if not lead:
log.warning('Lead not found in the database')
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
try:
client.calls.hangup(call_id)
except Exception as e:
log.warning(traceback.format_exc())
@celery.task
def bw_redirect_to_voicemail(lead_id, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
storage = CallStorage(redis_db, lead_id)
routing_config = storage.routing_config
language = routing_config.get('language', 'en')
gender, locale, voice = select_voice(language)
with storage.lock():
if storage.prompt_task:
celery.control.revoke(storage.prompt_task)
storage.prompt_task = None
lead = Lead.query.filter(Lead.id == lead_id).first()
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
try:
# If voicemail enabled, blindly redirect there...
voicemail = routing_config.get('voicemail', False)
voicemail_message_type = routing_config.get('voicemailMessageType')
voicemail_message = routing_config.get('voicemailMessage')
voicemail_message_audio = routing_config.get('voicemailMessageAudio')
call = client.calls[storage.call_sid]
if not voicemail:
call.hangup()
return
conf = client.conferences[storage.bw_conf_id]
conf.audio(file_url='')
if voicemail_message_type == 'audio':
inbound_id = lead.inbound_id
audio = Audio.query.filter(
Audio.id == voicemail_message_audio,
Audio.inbound_id == inbound_id,
Audio.whisper_message_type == 'voicemailMessage',
Audio.enabled == True,
).order_by(Audio.id.desc()).first()
if audio:
call.audio(
file_url=audio.audio_url,
tag='voicemail_prompt',
)
elif voicemail_message:
call.say(
voicemail_message, gender, locale, voice,
tag='voicemail_prompt'
)
except Exception as e:
log.error(traceback.format_exc())
return
@celery.task
def bw_play_voicemail_beep(lead_id, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
storage = CallStorage(redis_db, lead_id)
lead = Lead.query.filter(Lead.id == lead_id).first()
if not lead:
log.warning('Lead not found in the database')
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
call = client.calls[storage.call_sid]
call.audio(file_url=celery.conf['BEEP_SOUND'], tag='voicemail_beep')
@celery.task
def bw_start_recording(lead_id, call_id, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
storage = CallStorage(redis_db, lead_id)
lead = Lead.query.filter(Lead.id == lead_id).first()
if not lead:
log.warning('Lead not found in the database')
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
call = client.calls[storage.call_sid]
call.post(
recording_enabled='true',
recording_file_format='wav'
)
@celery.task
def bw_agent_bridge_lead(lead_id, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
lead = Lead.query.filter(Lead.id == lead_id).first()
if not lead:
log.warning('Lead not found in the database')
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
storage = CallStorage(redis_db, lead_id)
routing_config = storage.routing_config
if routing_config.get('recordCalls', False):
client.calls[storage.call_sid].post(
recording_enabled='true',
recording_file_format='mp3'
)
client.bridge(call_ids=[storage.call_sid, storage.agent_call_id])
client.calls[storage.agent_call_id].audio(
file_url='https://s3.amazonaws.com/buyercall-static-sounds/beep.wav'
)
@celery.task
def bw_cancel_agent_calls(lead_id, other_than=None, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
log.debug('Canceling agent calls for lead {}...'.format(lead_id))
lead = Lead.query.filter(Lead.id == lead_id).first()
if not lead:
log.warning('Lead not found in the database')
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
storage = CallStorage(redis_db, lead_id)
log.debug('{}: {}'.format(lead_id, storage.state))
agent_calls = storage.clear_agent_calls(
lambda id_, _: id_ != other_than
)
if not agent_calls:
return
for (agent_id, call_sid) in agent_calls:
try:
log.debug('...agent {}, call {}'.format(agent_id, call_sid))
client.calls[call_sid].hangup()
except Exception as e:
log.info('Cannot hangup call {}'.format(call_sid))
# TODO: FIXME: What was I going to do here?
@celery.task
def bw_agent_bridge_lead2(lead_id, agent_id, call_settings, **kwargs):
# Declare redis url
redis_db = redis.StrictRedis(host=celery.conf['REDIS_CONFIG_URL'], port=celery.conf['REDIS_CONFIG_PORT'])
from ..agents.models import Agent
lead = Lead.query.join(Lead.inbound).filter(
Lead.id == lead_id
).first()
if not lead:
return
# import partnership information to get partnership id
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == lead.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()
storage = CallStorage(redis_db, lead_id)
storage.routing = call_settings
storage.manual_call = True
storage.routing_config = {}
twilio_client = subaccount_client(lead.partnership_account.subscription.twilio_subaccount_sid, partner.id)
agent = Agent.query.filter(Agent.id == agent_id).first()
if not agent:
log.error('Cannot find agent with ID {}!'.format(lead_id))
return
storage.state = State.CALLBACK
log.debug('Calling agent with ID {}...'.format(agent_id))
call = None
try:
agent_number, extension = get_agent_number(agent, call_settings)
digits = 'wwww' + extension if extension else None
with storage.lock():
if storage.state == State.CALLBACK:
call = twilio_client.calls.create(
to=agent_number,
from_=lead.inbound.phonenumber,
url=url_for(
'twilio_inbound.agent_callback_lead',
lead_id=lead_id,
agent_id=agent.id,
_external=True
),
status_callback=url_for(
'twilio_inbound.agent_callback_call_status',
agent_id=agent.id,
lead_id=lead_id,
_external=True
),
status_callback_event=['answered', 'completed'],
send_digits=digits,
timeout=AGENT_TIMEOUT
)
storage.push_agent_call(agent.id, call.sid)
except Exception as e:
log.warning(traceback.format_exc())
log.warning('Error calling agent {}...'.format(
agent.id
))
if call is None:
# None of the calls got through
lead.status = 'missed'
db.session.commit()
@celery.task
def bw_upload_recording(call_id, **kwargs):
""" After the call, grab the first recording from Bandwidth, if any, and
upload to S3.
"""
lead = Lead.query.filter(Lead.call_sid == call_id).first()
from ..partnership.models import Partnership, PartnershipAccount
partner_account = PartnershipAccount.query. \
filter(PartnershipAccount.id == lead.partnership_account_id).first()
partner_name = partner_account.name
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
client = bw_client(partner.id)
recs = client.calls[call_id].recordings()
if len(recs) == 0:
log.warning('No recordings found for call {}!'.format(call_id))
return
file_path = os.path.join(app.config['UPLOAD_FOLDER'], call_id)
log.info('The file path is: {}'.format(file_path))
with open(file_path, 'wb') as f:
count = 0
for c in recs[0].data().iter_content(chunk_size=1024):
f.write(c)
count += len(c)
log.info("Read {} bytes.".format(count))
with open(file_path, 'rb') as f:
hex_value = uuid.uuid4().hex
key = '{}_{}/{}_{}_{}'.format(
partner_name, lead.partnership_account_id, lead.id, 'recording', hex_value)
app.logger.debug('The recording key is {}'.format(key))
s3 = boto3.client(
's3',
aws_access_key_id=celery.conf['AMAZON_ACCESS_KEY'],
aws_secret_access_key=celery.conf['AMAZON_SECRET_KEY']
)
s3.upload_fileobj(f,
celery.conf['RECORDING_BUCKET'],
key,
ExtraArgs={'Metadata': {'Content-Type': 'audio/mpeg'},
'ACL': 'private'})
log.info('Uploaded file {}'.format(key))
# Update recording link
updated_lead = Lead.query.options(
load_only("id", "recording_url")
).filter(Lead.id == lead.id).first()
updated_lead.recording_url = '{}::{}'.format(celery.conf['RECORDING_BUCKET'], key)
db.session.commit()
os.remove(file_path)
@celery.task
def bw_upload_holdmusic(user_id, hold_music_id, file_path, **kwargs):
""" Upload the given MP3 file to S3.
"""
# Update recording link
hold_music = HoldMusic.query.options(
load_only("id", "uuid", "url")
).filter(HoldMusic.id == hold_music_id).first()
with open(file_path, 'r') as f:
conn = S3Connection(
celery.conf['AMAZON_ACCESS_KEY'], celery.conf['AMAZON_SECRET_KEY']
)
bucket = conn.get_bucket(celery.conf['HOLD_MUSIC_BUCKET'])
k = Key(bucket)
k.set_metadata('Content-Type', 'audio/mpeg')
k.key = hold_music.uuid
k.set_contents_from_file(f)
k.set_acl('public-read')
log.info('Uploaded file {}'.format(k.key))
os.remove(file_path)
hold_music.url = k.generate_url(expires_in=0, query_auth=False)
db.session.commit()
@celery.task()
def update_tn(pa_id, p_id, tn, tn_type, sms_option, **kwargs):
# If it's a bandwidth number update the SMS enable status for the TN
from buyercall.lib.util_bandwidth import bw_client
if tn_type == 'mobile':
client = bw_client(p_id, 'voice', 'mobile')
r = client.phone_numbers_options.update(partner_account_id=pa_id,
phonenumber=tn,
sms_option=sms_option,
# Add back these campaign items when campaigns have been moved.
# sms_campaign_id=app.config.get('SMS_MOBILE_CAMPAIGN_ID'),
# sms_campaign_class=app.config.get('SMS_MOBILE_CAMPAIGN_CLASS')
)
else:
client = bw_client(p_id, 'voice')
r = client.phone_numbers_options.update(partner_account_id=pa_id,
phonenumber=tn,
sms_option=sms_option)
return r