Code Monkey home page Code Monkey logo

call-tracking-laravel's Introduction

Call tracking using Twilio and Laravel

Build Status

This application demostrates how to use Twilio track calls and measure the effectiveness of marketing campaigns

Running locally

Installing Postgres

Start a local PostgreSQL database and create a database. If on a Mac, I recommend Postgres.app. You will need to create a new database the application can use. Example: createdb call_tracking. It's also a good idea to create a database createdb call_tracking_test you can run the tests against.

The web application

  1. Clone the repository, copy the included env.example as .env and customize it to your needs.

    • This file will be loaded by Laravel which will set the variables configured in it as environment variables. Then the application will attempt to read the configuration from the environment.
    • The values for TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN can be found under your Twilio account's settings panel.
    • The DATABASE_URL variable should follow the pgsql://<username>:<password>@<host>:<port>/<database name> schema.
    • If you already have a TwiML app under your account you'd like to use, you will also need to specify its SID in this file. If you don't know if you do then you can delete the TWILIO_APP_SID line. The app will take care of it.
  2. Use composer to install the app's dependencies by running composer install in the repo's root

  3. Run php artisan key:generate to generate an APP_KEY that Laravel will use for token and cookies.

  4. If you're on OS X you might need to install the PDO drivers so Eloquent can connect to your database. If you're running PHP 5.6 something like brew install php56-pdo-pgsql should do it.

  5. Run the database migrations using php artisan migrate. If the database is configured correctly in .env this will get you a working database

  6. Go to http://localhost:8000/dashboard. If everything is configured correctly you should see a dashboard and some numbers you can buy through Twilio's API. Buy at least one number and start calling the lead sources.

Exposing the app via ngrok

For this demo it's necessary that your local application instance is accessible from the Internet. The easiest way to accomplish this during development is using ngrok. If you're running OS X you can install ngrok using Homebrew by running brew install ngrok. First you will need to run the application and make sure it's bound to 127.0.0.1 so ngrok can find it:

php artisan serve --host=127.0.0.1

After this you can expose the application to the wider Internet by running (port 8000 is the default for Laravel):

ngrok http 8000

Configuring the TwiML app to forward calls

Go to http://localhost:8000/dashboard and click "App Configuration" right under "All lead sources". This will take you either to a newly create TwiML app under your account or to the application configured in the TWILIO_APP_SID variable. Edit the application and sets its request URL to http://<your-ngrok-id>.ngrok.io/lead and make sure the method is set to POST. Click save to finish.

App configuration button

Configuring the app under your Twilio account:

Twilio app configuration

Running the tests

The tests interact with the database so you'll first need to migrate your test database. First, set the DATABASE_URL to your test database and then run.

php artisan migrate

Make sure you have TWILIO_APP_SID set so the app does not attempt to look it while running the tests. Then tests then can be run using:

phpunit

call-tracking-laravel's People

Contributors

dependabot-preview[bot] avatar itsazzad avatar jefflinwood avatar lopenchi avatar mcelicalderon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

call-tracking-laravel's Issues

Exception on new lead source

Clicking on "New" by the lead sources list results in

Whoops, looks like something went wrong.

1/1
InvalidArgumentException in Response.php line 470:
The HTTP status code "1" is not valid.
in Response.php line 470
at Response->setStatusCode(array('numbers' => array(object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass)), 'areaCode' => null)) in Response.php line 203
at Response->__construct('', array('numbers' => array(object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass)), 'areaCode' => null), array()) in JsonResponse.php line 43
at JsonResponse->__construct('available_numbers.index', array('numbers' => array(object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass)), 'areaCode' => null), array()) in JsonResponse.php line 31
at JsonResponse->__construct('available_numbers.index', array('numbers' => array(object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass)), 'areaCode' => null), array(), '0') in ResponseFactory.php line 89
at ResponseFactory->json('available_numbers.index', array('numbers' => array(object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass), object(stdClass)), 'areaCode' => null)) in AvailableNumberController.php line 34
at AvailableNumberController->index(object(Request))
at call_user_func_array(array(object(AvailableNumberController), 'index'), array(object(Request))) in Controller.php line 256
at Controller->callAction('index', array(object(Request))) in ControllerDispatcher.php line 164
at ControllerDispatcher->call(object(AvailableNumberController), object(Route), 'index') in ControllerDispatcher.php line 112
at ControllerDispatcher->Illuminate\Routing\{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103
at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 114
at ControllerDispatcher->callWithinStack(object(AvailableNumberController), object(Route), object(Request), 'index') in ControllerDispatcher.php line 69
at ControllerDispatcher->dispatch(object(Route), object(Request), 'App\Http\Controllers\AvailableNumberController', 'index') in Route.php line 201
at Route->runWithCustomDispatcher(object(Request)) in Route.php line 134
at Route->run(object(Request)) in Router.php line 704
at Router->Illuminate\Routing\{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103
at Pipeline->then(object(Closure)) in Router.php line 706
at Router->runRouteWithinStack(object(Route), object(Request)) in Router.php line 671
at Router->dispatchToRoute(object(Request)) in Router.php line 631
at Router->dispatch(object(Request)) in Kernel.php line 236
at Kernel->Illuminate\Foundation\Http\{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 139
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in VerifyCsrfToken.php line 50
at VerifyCsrfToken->handle(object(Request), object(Closure))
at call_user_func_array(array(object(VerifyCsrfToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in ShareErrorsFromSession.php line 54
at ShareErrorsFromSession->handle(object(Request), object(Closure))
at call_user_func_array(array(object(ShareErrorsFromSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in StartSession.php line 62
at StartSession->handle(object(Request), object(Closure))
at call_user_func_array(array(object(StartSession), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in AddQueuedCookiesToResponse.php line 37
at AddQueuedCookiesToResponse->handle(object(Request), object(Closure))
at call_user_func_array(array(object(AddQueuedCookiesToResponse), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in EncryptCookies.php line 59
at EncryptCookies->handle(object(Request), object(Closure))
at call_user_func_array(array(object(EncryptCookies), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in CheckForMaintenanceMode.php line 42
at CheckForMaintenanceMode->handle(object(Request), object(Closure))
at call_user_func_array(array(object(CheckForMaintenanceMode), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103
at Pipeline->then(object(Closure)) in Kernel.php line 122
at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 87
at Kernel->handle(object(Request)) in index.php line 54
at require_once('/Users/kwhinnery/dev/twilio/apps/php/call-tracking-laravel/public/index.php') in server.php line 21

Steps to take to build this

I'm completely new to this and don't understand the steps and the requirements to build this.

There are also no examples of how it looks when built.

Could you please let me know what's the process?

I have a server with Apache Php and PosgreSQL installed.

Do I have to install laravel as well?

Please explain.

Production Instructions (i.e. Digital Ocean)

Hey guys,

This looks like exactly what I'm looking for, but I'm not to clear on setup instructions. I'd love to get this set up on a Digital Ocean droplet, is that possible? Or is this just meant to run locally?

Thanks!

UI too messy/confusing in current state

We're not super concerned with visual polish on these, but in it's current state the UI is not presentable. Normally I wouldn't mind if the paths are different or the UX diverging slightly, but the deviations from the Django app's UX were not in a positive direction.

To eliminate any confusion about what is desired, let's precisely follow UX for the Django implementation:

  1. The "dashboard" should have the list of editable lead sources in a left column, and charts for lead distribution on the right. There should be a form to search for a new number to add as a lead source on the dashboard as well
  2. Searching for a number should initiate a workflow where you select from available numbers to purchase
  3. After selecting a number, it should be purchased with the Twilio API, and then associated with a lead source, that you edit with a name and forwarding number.

I would check out and run the Django app locally, and very closely mirror it's layout and UX.

Trouble implementing in Laravel 5.4

Followed the instructions from the readme and Twilio page but when I access the page https://myapp.com/available_number I get the following error:

Whoops, looks like something went wrong.
(1/1) ConfigurationException - Credentials are required to create a Client
--

I made sure I added my credentials in .env and flushed cache

README does not contain explicit enough instructions to run app locally

The README should be followable by just about anyone, regardless of technical skill level. There are several items that are not covered:

  • How to set up and connect to Postgres - if you decide to use Postgres for dev instead of sqlite, you need to document this dependency and how to set it up, at least on the Mac. Postgres.app is a good choice. Mention what the connection string will be in .env
  • How to set environment variables. You mention editing .env "to your needs" but don't mention what is in it, or how to use the file they just edited.
  • Most platforms require a database driver to be installed - on the Mac, you need to do brew install php56-pdo-pgsql (or similar) or running the migrations will fail
  • you mention that you can configure an app SID in .env but don't say how to do it or what the environment variable should be called.

need to instruct developer to generate secrets

To run the app successfully, you'll need to run php artisan key:generate before php artisan serve to generate secrets. This should be in the README, as the error you get is not helpful.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.