File: //home/arjun/projects/buyercall_new/buyercall/buyercall/blueprints/sms/bw_sms_tasks.py
import traceback
import logging as log
import json
from flask import current_app, url_for
import os.path as path
from buyercall.lib.util_bandwidth import bw_client as bw_dashboard_client
from buyercall.app import create_celery_app
from buyercall.extensions import db
from buyercall.blueprints.sms.models import Message
from buyercall.blueprints.contacts.models import Contact
from buyercall.blueprints.mobile.models import Endpoint
from buyercall.blueprints.phonenumbers.models import Phone
from buyercall.blueprints.partnership.models import PartnershipAccount, Partnership
from buyercall.blueprints.phonenumbers.routing import (
get_sms_routing_agents, get_agent_number
)
from buyercall.lib.util_webhooks import WebhookUtil
from buyercall.blueprints.filters import format_phone_number
celery = create_celery_app(current_app)
webhooker = WebhookUtil()
@celery.task
def bw_forward_sms(inbound_id, message_id, **kwargs):
""" This function is used to send Bandwidth sms messages using celery. More information on
bandwidth messaging can be found here; https://dev.bandwidth.com/howto/sendSMSMMS.html
"""
msg_obj = Message.query.filter(Message.id == message_id).first()
inbound = Phone.query.filter(Phone.id == inbound_id).first()
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == inbound.partnership_account_id).first()
partner = Partnership.query.filter(Partnership.id == partner_account.partnership_id).first()
if inbound.type == 'mobile':
client = bw_dashboard_client(partner_account.partnership_id, 'messaging', tn_type='mobile')
else:
client = bw_dashboard_client(partner_account.partnership_id, 'messaging')
phone_number = inbound.phonenumber
routing = inbound.routing_config['defaultRouting']
lead_phone = format_phone_number(msg_obj.from_)
contact = Contact.query.filter(Contact.phonenumber_1 == lead_phone) \
.filter(Contact.partnership_account_id == inbound.partnership_account_id).first()
if contact:
if contact.firstname:
contact_name = "{} {} - {}".format(contact.firstname, contact.lastname, lead_phone)
elif contact.caller_id:
contact_name = "{} - {}".format(contact.caller_id, lead_phone)
else:
contact_name = lead_phone
if partner.partner_url:
lead_contact_url = '{}/contacts/contact/{}'.format(partner.partner_url, contact.id)
else:
lead_contact_url = url_for('contacts.contact_lead_page', id=contact.id, _external=True)
else:
contact_name = 'unknown'
lead_contact_url = 'unavailable'
agents = get_sms_routing_agents(routing)
try:
agent_list = []
for agent in agents:
agent_phone_number = get_agent_number(agent, routing)
sms_agent_number = str(agent_phone_number[0])
if msg_obj.media_url:
media_available = 'Yes'
else:
media_available = 'No'
mod_body = 'FROM: {} MSG: {} MEDIA: {} REPLY: {}'.format(contact_name, msg_obj.body_text, media_available,
lead_contact_url)
send_msg = client.messages.create(
m_to=sms_agent_number,
m_from=phone_number,
m_body=mod_body
)
log.info('The message responds is: {}'.format(send_msg))
agent_list.append(agent.id)
log.info('A sms message has been successfully sent to agent phone number: {} using bandwidth '
'phone number {}'
.format(sms_agent_number, phone_number))
except Exception as e:
log.info(traceback.format_exc())
log.info('The bandwidth sms message could not be sent, either due to no agent to receive it or there '
'was another error')
return ''
log.info('Updating message lead in DB')
if msg_obj:
msg_obj.agent_id = agent_list
db.session.commit()
@celery.task
def bw_send_sms(inbound_id, to, text, agent_list, media=None, **kwargs):
""" This function is used to send Bandwidth sms messages using celery. More information on
bandwidth messaging can be found here; https://dev.bandwidth.com/howto/sendSMSMMS.html
"""
inbound = Phone.query.filter(Phone.id == inbound_id).first()
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == inbound.partnership_account_id).first()
if inbound.type == 'mobile':
client = bw_dashboard_client(partner_account.partnership_id, 'messaging', tn_type='mobile')
else:
client = bw_dashboard_client(partner_account.partnership_id, 'messaging')
phonenumber = inbound.phonenumber
try:
if media:
send_msg = client.messages.create(
m_to=to,
m_from=phonenumber,
m_body=text,
media=media
)
else:
send_msg = client.messages.create(
m_to=to,
m_from=phonenumber,
m_body=text,
)
log.info('A sms message has been successfully sent using bandwidth phone number {}'
.format(phonenumber))
add_bw_outbound_message_lead(inbound_id, send_msg, inbound.partnership_account_id, inbound.provider,
agent_list)
return json.loads(send_msg).get('id', '')
except Exception as e:
log.info(traceback.format_exc())
log.info('The bandwidth sms message could not be sent, either due to no agent to receive it or there was '
'another error')
return
@celery.task
def add_bw_message_lead(inbound_id, inbound_tn, message_type, message_info, delivery_description,
partnership_account_id, provider, **kwargs):
"""
Add sms lead message to the messages table
"""
# The sender's formatted phone number
format_phone = format_phone_number(message_info.get('from', ''))
contact = Contact.query.filter(Contact.phonenumber_1 == format_phone).filter(
Contact.partnership_account_id == partnership_account_id
).first()
if not contact:
contact_entry = Contact(
phonenumber_1=format_phone,
partnership_account_id=partnership_account_id
)
db.session.add(contact_entry)
db.session.commit()
new_contact = Contact.query.filter(Contact.phonenumber_1 == format_phone).filter(
Contact.partnership_account_id == partnership_account_id
).first()
if message_type == 'mms':
media_args = str(message_info.get('media')).replace("[", "").replace("]", "").replace(" ", "").replace("'", "")
media_links = media_args.split(",")
print(media_links)
media_list = []
for i in media_links:
if not i.endswith(".xml"):
from ..partnership.models import PartnershipAccount, Partnership
partner_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == partnership_account_id).first()
partner_name = partner_account.name
media_file_name = i.rpartition('media/')[2].replace("'", "")
client = bw_dashboard_client(partner_account.partnership_id, request_type='messaging')
try:
get_media = client.media.get_media(media_file_name)
converted_media_file_name = media_file_name.replace('/', '-')
file_path = path.join(current_app.config['UPLOAD_FOLDER'], converted_media_file_name)
with open(file_path, 'wb') as f:
count = 0
for c in get_media.iter_content(chunk_size=1024):
count += len(c)
f.write(c)
log.info("Read {} bytes.".format(count))
from buyercall.blueprints.sms.tasks import upload_mms_image
media_url = upload_mms_image(
partner_name,
partner_account.id,
converted_media_file_name,
file_path
)
media_list.append(str(media_url))
except Exception as e:
log.info('exception is: {}'.format(e))
else:
media_list = ''
try:
if new_contact:
new_contact_id = new_contact.id
if message_info.get('direction', '') == 'in':
msg_direction = 'inbound'
msg_status = 'received'
else:
msg_direction = ''
msg_status = 'unknown'
new_contact.updated_on = message_info.get('time')
agent_list = []
message = Message(
type=message_type,
provider=provider,
provider_message_id=message_info.get('id', ''),
provider_message_date=message_info.get('time'),
to=inbound_tn,
from_=message_info.get('from', ''),
body_text=message_info.get('text', ''),
media_url=media_list,
status=msg_status,
delivery_code=message_info.get('deliveryCode', 201),
delivery_type=message_info.get('type', ''),
delivery_description=delivery_description,
direction=msg_direction,
inbound_id=inbound_id,
partnership_account_id=partnership_account_id,
contact_id=new_contact_id,
originating_number=message_info.get('from'),
agent_id=agent_list
)
db.session.add(message)
db.session.commit()
webhooker.trigger_generic_webhook('operational_receive_message', message.id)
return message
except Exception as e:
log.error('There is no contact for message to add new message to message table. Exception: {}'.format(e))
return ''
@celery.task
def add_bw_outbound_message_lead(inbound_id, message_info, partnership_account_id, provider, agent_list, **kwargs):
"""
Add sms lead message to the messages table
"""
msg_dict = json.loads(message_info)
log.info('The send msg is: {}'.format(msg_dict))
log.info(msg_dict.get('text', ''))
# The sender's formatted phone number
format_phone = format_phone_number(str(msg_dict.get('to', '')[0]))
contact = Contact.query.filter(Contact.phonenumber_1 == format_phone).filter(
Contact.partnership_account_id == partnership_account_id
).first()
if not contact:
contact_entry = Contact(
phonenumber_1=format_phone,
partnership_account_id=partnership_account_id
)
db.session.add(contact_entry)
db.session.commit()
log.info('The message contact has been added')
new_contact = Contact.query.filter(Contact.phonenumber_1 == format_phone).filter(
Contact.partnership_account_id == partnership_account_id
).first()
log.info('The contact exist and the contact id is: {}'.format(new_contact.id))
try:
if new_contact:
new_contact_id = new_contact.id
if msg_dict.get('direction', '') == 'out':
msg_direction = 'outbound'
msg_status = 'sent'
else:
msg_direction = ''
msg_status = 'unknown'
if msg_dict.get('media', ''):
msg_type = 'mms'
else:
msg_type = 'sms'
new_contact.updated_on = msg_dict.get('time', '')
if not agent_list:
agent_list = []
message = Message(
type=msg_type,
provider=provider,
provider_message_id=msg_dict.get('id', ''),
provider_message_date=msg_dict.get('time', ''),
to=format_phone,
from_=msg_dict.get('from', ''),
body_text=msg_dict.get('text', ''),
media_url=msg_dict.get('media', ''),
status=msg_status,
direction=msg_direction,
inbound_id=inbound_id,
partnership_account_id=partnership_account_id,
contact_id=new_contact_id,
originating_number=msg_dict.get('from', ''),
agent_id=agent_list
)
db.session.add(message)
db.session.commit()
phone = Phone.query.filter(Phone.id == inbound_id).first()
if phone is not None and phone.type == 'mobile':
webhooker.trigger_generic_webhook('mobile_send_message', message.id)
sip_endpoint = Endpoint.query.filter(Endpoint.inbound_id == inbound_id).first()
if sip_endpoint and sip_endpoint.agent_id:
from buyercall.blueprints.agents.models import Agent
agent = Agent.query.filter(Agent.id == sip_endpoint.agent_id).first()
if agent and new_contact.agent_id != agent.id:
new_contact.agent_id = agent.id
new_contact.agent_assigned = agent.full_name
db.session.commit()
from buyercall.blueprints.mobile.utils import send_agent_push_notification
send_agent_push_notification(new_contact)
elif phone is not None and phone.type == 'tracking':
webhooker.trigger_generic_webhook('operational_send_message', message.id)
except Exception as e:
log.error('There is no contact for message to add new message to message table')
return ''
# This celery task gets used to send application text messages such as two factor auth codes
@celery.task
def app_send_sms(to_number, from_number, body, **kwargs):
partner_id = 1
client = bw_dashboard_client(partner_id, 'messaging')
try:
msg = client.messages.create(
m_to=to_number,
m_from=from_number,
m_body=body,
)
log.info('The msg response looks like: {}'.format(msg))
log.info('A two factor auth code has been successfully sent using bandwidth phone number {}'
.format(from_number))
except Exception as e:
log.info(traceback.format_exc())
log.info(
'The bandwidth two factor authentication sms code could not be sent')
return
# Update the outbound message record in the DB
@celery.task
def update_msg_record(bw_msg_id, delivery_code, delivery_type, delivery_description, **kwargs):
msg = Message.query.filter(Message.provider_message_id == bw_msg_id).first()
try:
if msg:
msg.delivery_code = delivery_code
msg.delivery_type = delivery_type
msg.delivery_description = delivery_description
db.session.commit()
except Exception as e:
log.info('Unable to update outbound message record: {}'.format(e))