var twilio = require('twilio');
var config = require('../config');
var LeadSource = require('../models/LeadSource');
var client = twilio(config.apiKey, config.apiSecret, { accountSid: config.accountSid });
exports.create = function(request, response) {
var phoneNumberToPurchase = request.body.phoneNumber;
client.incomingPhoneNumbers.create({
phoneNumber: phoneNumberToPurchase,
voiceCallerIdLookup: 'true',
voiceApplicationSid: config.appSid
}).then(function(purchasedNumber) {
var leadSource = new LeadSource({number: purchasedNumber.phoneNumber});
return leadSource.save();
}).then(function(savedLeadSource) {
console.log('Saving lead source');
response.redirect(303, '/lead-source/' + savedLeadSource._id + '/edit');
}).catch(function(numberPurchaseFailure) {
console.log('Could not purchase a number for lead source:');
console.log(numberPurchaseFailure);
response.status(500).send('Could not contact Twilio API');
});
};
exports.edit = function(request, response) {
var leadSourceId = request.params.id;
LeadSource.findOne({_id: leadSourceId}).then(function(foundLeadSource) {
return response.render('editLeadSource', {
leadSourceId: foundLeadSource._id,
leadSourcePhoneNumber: foundLeadSource.number,
leadSourceForwardingNumber: foundLeadSource.forwardingNumber,
leadSourceDescription: foundLeadSource.description,
messages: request.flash('error')
});
}).catch(function() {
return response.status(404).send('No such lead source');
});
};
exports.update = function(request, response) {
var leadSourceId = request.params.id;
request.checkBody('description', 'Description cannot be empty').notEmpty();
request.checkBody('forwardingNumber', 'Forwarding number cannot be empty')
.notEmpty();
if (request.validationErrors()) {
request.flash('error', request.validationErrors());
return response.redirect(303, '/lead-source/' + leadSourceId + '/edit');
}
LeadSource.findOne({_id: leadSourceId}).then(function(foundLeadSource) {
foundLeadSource.description = request.body.description;
foundLeadSource.forwardingNumber = request.body.forwardingNumber;
return foundLeadSource.save();
}).then(function(savedLeadSource) {
return response.redirect(303, '/dashboard');
}).catch(function(error) {
return response.status(500).send('Could not save the lead source');
});
};
using System.Net;
using System.Threading.Tasks;
using System.Web.Mvc;
using CallTracking.Web.Domain.Twilio;
using CallTracking.Web.Models;
using CallTracking.Web.Models.Repository;
using HttpStatusCodeResult = System.Web.Mvc.HttpStatusCodeResult;
namespace CallTracking.Web.Controllers
{
public class LeadSourcesController : Controller
{
private readonly IRepository<LeadSource> _repository;
private readonly IRestClient _restClient;
public LeadSourcesController()
: this(new LeadSourcesRepository(), new RestClient()) { }
public LeadSourcesController(IRepository<LeadSource> repository, IRestClient restClient)
{
_repository = repository;
_restClient = restClient;
}
// POST: LeadSources/Create
[HttpPost]
public async Task<ActionResult> Create(string phoneNumber)
{
var twiMLApplicationSid = Credentials.TwiMLApplicationSid ?? await _restClient.GetApplicationSidAsync();
var twilioNumber = await _restClient.PurchasePhoneNumberAsync(phoneNumber, twiMLApplicationSid);
var leadSource = new LeadSource
{
IncomingNumberNational = twilioNumber.FriendlyName,
IncomingNumberInternational = twilioNumber.PhoneNumber?.ToString()
};
_repository.Create(leadSource);
return RedirectToAction("Edit", new {id = leadSource.Id});
}
// GET: LeadSources/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var leadSource = _repository.Find(id.Value);
if (leadSource == null)
{
return HttpNotFound();
}
return View(leadSource);
}
// POST: LeadSources/Edit/
[HttpPost]
public ActionResult Edit(
[Bind(Include = "Id,Name,IncomingNumberNational,IncomingNumberInternational,ForwardingNumber")]
LeadSource leadSource)
{
if (ModelState.IsValid)
{
_repository.Update(leadSource);
return RedirectToAction("Index", new { Controller = "Dashboard" });
}
return View(leadSource);
}
}
}
class LeadSourcesController < ApplicationController
before_filter :find_lead_source, only: [:edit, :update]
def edit
end
def create
phone_number = params[:format]
twilio_number = TwilioClient.purchase_phone_number(phone_number)
lead_source = LeadSource.create(name: '', incoming_number: twilio_number.friendly_name)
message = "Phone number #{twilio_number.friendly_name} has been purchased. Please add a name for this lead source"
redirect_to edit_lead_source_path(lead_source), notice: message
end
def update
if @lead_source.update_attributes(lead_sources_params)
redirect_to root_url, notice: 'Lead source successfully updated.'
end
end
private
def find_lead_source
@lead_source = LeadSource.find(params[:id])
end
def lead_sources_params
params.require(:lead_source).permit(:name, :forwarding_number)
end
end
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse_lazy
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect
from django.template.context_processors import csrf
from django.views.decorators.csrf import csrf_exempt
from django.views.generic.base import TemplateView
from django.views.generic.edit import UpdateView
from twilio.twiml.voice_response import VoiceResponse
from .forms import AreaCodeForm, PurchaseNumberForm
from .models import LeadSource, Lead
from .utils import search_phone_numbers, purchase_phone_number
# Home page view and JSON views to power the charts
def home(request):
"""Renders the home page"""
context = {}
# Add the area code form - default to 415
context['form'] = AreaCodeForm({'area_code': '415'})
# Add the list of lead sources
context['lead_sources'] = LeadSource.objects.all()
return render(request, 'index.html', context)
def leads_by_source(request):
"""Returns JSON data about the lead sources and how many leads they have"""
# Invoke a LeadSource classmethod to get the data
data = LeadSource.objects.get_leads_per_source()
# Return it as JSON - use safe=False because we're sending a JSON array
return JsonResponse(data, safe=False)
def leads_by_city(request):
"""Returns JSON data about the different cities leads come from"""
# Invoke a Lead classmethod to get the data
data = Lead.objects.get_leads_per_city()
# Return it as JSON - use safe=False because we're sending a JSON array
return JsonResponse(data, safe=False)
# Views for purchase number workflow
def list_numbers(request):
"""Uses the Twilio API to generate a list of available phone numbers"""
form = AreaCodeForm(request.POST)
if form.is_valid():
# We received a valid area code - query the Twilio API
area_code = form.cleaned_data['area_code']
available_numbers = search_phone_numbers(area_code=area_code)
# Check if there are no numbers available in this area code
if not available_numbers:
messages.error(
request,
'There are no Twilio numbers available for area code {0}. Search for numbers in a different area code.'.format(area_code))
return redirect('home')
context = {}
context['available_numbers'] = available_numbers
return render(request, 'call_tracking/list_numbers.html', context)
else:
# Our area code was invalid - flash a message and redirect back home
bad_area_code = form.data['area_code']
messages.error(request, '{0} is not a valid area code. Please search again.'
.format(bad_area_code))
return redirect('home')
def purchase_number(request):
"""Purchases a new phone number using the Twilio API"""
form = PurchaseNumberForm(request.POST)
if form.is_valid():
# Purchase the phone number
phone_number = form.cleaned_data['phone_number']
twilio_number = purchase_phone_number(phone_number.as_e164)
# Save it in a new LeadSource object
lead_source = LeadSource(incoming_number=twilio_number.phone_number)
lead_source.save()
messages.success(
request,
'Phone number {0} has been purchased. Please add a name for this lead source.'.format(
twilio_number.friendly_name))
# Redirect to edit lead page
return redirect('edit_lead_source', pk=lead_source.pk)
else:
# In the unlikely event of an error, redirect to the home page
bad_phone_number = form.data['phone_number']
messages.error(request, '{0} is not a valid phone number. Please search again.'
.format(bad_phone_number))
return redirect('home')
class LeadSourceUpdateView(SuccessMessageMixin, UpdateView):
"""Powers a form to edit Lead Sources"""
model = LeadSource
fields = ['name', 'forwarding_number']
success_url = reverse_lazy('home')
success_message = 'Lead source successfully updated.'
# View used by Twilio API to connect callers to the right forwarding
# number for that lead source
@csrf_exempt
def forward_call(request):
"""Connects an incoming call to the correct forwarding number"""
# First look up the lead source
source = LeadSource.objects.get(incoming_number=request.POST['Called'])
# Create a lead entry for this call
lead = Lead(
source=source,
phone_number=request.POST['Caller'],
city=request.POST['CallerCity'],
state=request.POST['CallerState'])
lead.save()
# Respond with some TwiML that connects the caller to the forwarding_number
r = VoiceResponse()
r.dial(source.forwarding_number.as_e164)
return HttpResponse(r)
package com.twilio.calltracking.servlets.leadsources;
import com.twilio.calltracking.lib.Config;
import com.twilio.calltracking.lib.services.TwilioServices;
import com.twilio.calltracking.models.LeadSource;
import com.twilio.calltracking.repositories.LeadSourceRepository;
import com.twilio.calltracking.servlets.WebAppServlet;
import com.twilio.rest.api.v2010.account.incomingphonenumber.Local;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
public class CreateServlet extends WebAppServlet {
private LeadSourceRepository leadSourceRepository;
private TwilioServices twilioServices;
@SuppressWarnings("unused")
public CreateServlet() {
this(new LeadSourceRepository(), new TwilioServices());
}
public CreateServlet(LeadSourceRepository leadSourceRepository, TwilioServices twilioServices) {
this.leadSourceRepository = leadSourceRepository;
this.twilioServices = twilioServices;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String phoneNumber = request.getParameter("phoneNumber");
String twimlApplicationSid = Config.getTwimlApplicationSid();
if (Objects.equals(twimlApplicationSid, "") || (twimlApplicationSid == null)) {
twimlApplicationSid = twilioServices.getApplicationSid();
}
Local twilioNumber = twilioServices.purchasePhoneNumber(phoneNumber, twimlApplicationSid);
LeadSource leadSource = leadSourceRepository.create(new LeadSource(
twilioNumber.getFriendlyName(),
twilioNumber.getPhoneNumber().toString()));
response.sendRedirect(String.format("/leadsources/edit?id=%s", leadSource.getId()));
}
}
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use App\LeadSource;
use Illuminate\Http\Request;
use Twilio\Rest\Client;
class LeadSourceController extends Controller
{
/**
* Twilio Client
*/
protected $_twilioClient;
public function __construct(Client $twilioClient)
{
$this->_twilioClient = $twilioClient;
}
/**
* Store a new lead source (i.e phone number) and redirect to edit
* page
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$appSid = $this->_appSid();
$phoneNumber = $request->input('phoneNumber');
$this->_twilioClient->incomingPhoneNumbers
->create(
[
"phoneNumber" => $phoneNumber,
"voiceApplicationSid" => $appSid,
"voiceCallerIdLookup" => true
]
);
$leadSource = new LeadSource(
[
'number' => $phoneNumber
]
);
$leadSource->save();
return redirect()->route('lead_source.edit', [$leadSource]);
}
/**
* Show the form for editing a lead source
*
* @param int $id
* @return Response
*/
public function edit($id)
{
$leadSourceToEdit = LeadSource::find($id);
return response()->view(
'lead_sources.edit',
['leadSource' => $leadSourceToEdit]
);
}
/**
* Update the lead source in storage.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function update(Request $request, $id)
{
$this->validate(
$request,
[
'forwarding_number' => 'required',
'description' => 'required'
]
);
$leadSourceToUpdate = LeadSource::find($id);
$leadSourceToUpdate->fill($request->all());
$leadSourceToUpdate->save();
return redirect()->route('dashboard');
}
/**
* Remove the lead source from storage and release the number
*
* @param int $id
* @return Response
*/
public function destroy($id)
{
$leadSourceToDelete = LeadSource::find($id);
$phoneToDelete = $this->_twilioClient->incomingPhoneNumbers
->read(
[
"phoneNumber" => $leadSourceToDelete->number
]
);
if ($phoneToDelete) {
$phoneToDelete[0]->delete();
}
$leadSourceToDelete->delete();
return redirect()->route('dashboard');
}
/**
* The Twilio TwiML App SID to use
* @return string
*/
private function _appSid()
{
$appSid = config('app.twilio')['TWILIO_APP_SID'];
if (isset($appSid)) {
return $appSid;
}
return $this->_findOrCreateCallTrackingApp();
}
private function _findOrCreateCallTrackingApp()
{
$existingApp = $this->_twilioClient->applications->read(
array(
"friendlyName" => 'Call tracking app'
)
);
if ($existingApp) {
return $existingApp[0]->sid;
}
$newApp = $this->_twilioClient->applications
->create('Call tracking app');
return $newApp->sid;
}
}