Permalink
Browse files

Support for scheduled calls and messages.

  • Loading branch information...
1 parent adddd7f commit 90df7c4d5494b0d77d6ed0753fb0bd9337a1ef73 @chadsmith committed May 18, 2011
Showing with 354 additions and 9 deletions.
  1. +35 −1 README.md
  2. +4 −0 cron.php
  3. +11 −0 db.sql
  4. +6 −6 outbound.php
  5. +15 −2 plugin.json
  6. +18 −0 queue.js
  7. +96 −0 queue.php
  8. +9 −0 schedule.js
  9. +160 −0 schedule.php
View
@@ -1,6 +1,6 @@
# Outbound Flows for OpenVBX
-This plugin allows you to call out using flows or trigger outgoing calls or texts within another flow.
+This plugin allows you to call out using flows, schedule calls and messages, or trigger outgoing calls or texts within another flow.
## Installation
@@ -19,6 +19,24 @@ Once installed, OUTBOUND will appear in the OpenVBX sidebar
3. Select the Flow to call with
4. Select the caller ID (OpenVBX number) to call with
+### Schedule an outgoing call
+
+1. Click Schedule Flow in the OpenVBX sidebar
+2. Click Add Call
+3. Enter the number to call
+4. Enter the date and time to call
+5. Select the Flow to call with
+6. Select the caller ID (OpenVBX number) to call with
+
+### Schedule a text message
+
+1. Click Schedule Flow in the OpenVBX sidebar
+2. Click Add SMS
+3. Enter the number to call
+4. Enter the date and time to call
+5. Select the caller ID (OpenVBX number) to send with
+6. Enter the message to text
+
### Trigger a call to another number from a Flow
1. Add the New Call applet to a Call or SMS flow
@@ -34,3 +52,19 @@ Once installed, OUTBOUND will appear in the OpenVBX sidebar
3. Enter the message to text*
`* Use %caller% or %sender% to substitute the caller's number, %number% for the number called or %body% for the message body`
+
+## OpenVBX requirements ##
+
+This plugin requires a modified version of OpenVBX to allow for plugin hooks, subpages and cron jobs. Download the modified version from my fork [here][2].
+
+[2]: https://github.com/chadsmith/OpenVBX
+
+## Set Cron Job ##
+
+A cron job must be set to send scheduled calls and messages every 5 minutes. If you have access to crontab, enter:
+
+`*/5 * * * * /usr/bin/php5 /PATH_TO_OPENVBX/plugins/outbound/cron.php`
+
+If using cron source or a poorman's cron use:
+
+`http://YOUR_DOMAIN/hook/outbound/queue`
View
@@ -0,0 +1,4 @@
+<?php
+$_SERVER['PATH_INFO'] = '/hook/outbound/queue';
+chdir(dirname(dirname(dirname(__FILE__))));
+require('index.php');
View
11 db.sql
@@ -0,0 +1,11 @@
+CREATE TABLE IF NOT EXISTS `outbound_queue` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `tenant` bigint(20) NOT NULL,
+ `number` varchar(15) NOT NULL,
+ `type` varchar(4) NOT NULL,
+ `time` int(11) NOT NULL,
+ `callerId` varchar(15) NOT NULL,
+ `data` text,
+ PRIMARY KEY (`id`),
+ KEY `tenant` (`tenant`,`type`,`time`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
View
@@ -2,24 +2,24 @@
$user = OpenVBX::getCurrentUser();
$tenant_id = $user->values['tenant_id'];
$ci =& get_instance();
- if(($recipient = $_POST['recipient'])&&($number = $_POST['number'])&&($id = intval($_POST['flow']))){
+ if(($recipient = $_POST['recipient']) && ($number = $_POST['number']) && ($id = intval($_POST['flow']))) {
require_once(APPPATH . 'libraries/twilio.php');
$ci->twilio = new TwilioRestClient($ci->twilio_sid, $ci->twilio_token, $ci->twilio_endpoint);
- if($id&&($flow = OpenVBX::getFlows(array('id' => $id, 'tenant_id' => $tenant_id)))&&$flow[0]->values['data'])
- $ci->twilio->request("Accounts/{$this->twilio_sid}/Calls", 'POST', array('From' => $number, 'To' => normalize_phone_to_E164($_POST['recipient']), 'Url' => site_url('twiml/start/voice/'.$id)));
+ if($id && ($flow = OpenVBX::getFlows(array('id' => $id, 'tenant_id' => $tenant_id))) && $flow[0]->values['data'])
+ $ci->twilio->request("Accounts/{$this->twilio_sid}/Calls", 'POST', array('From' => $number, 'To' => normalize_phone_to_E164($_POST['recipient']), 'Url' => site_url('twiml/start/voice/' . $id)));
}
$flows = OpenVBX::getFlows(array('tenant_id' => $tenant_id));
?>
<style>
- .vbx-subscriptions form {
+ .vbx-outbound form {
padding:20px 5%;
}
</style>
<div class="vbx-content-main">
<div class="vbx-content-menu vbx-content-menu-top">
<h2 class="vbx-content-heading">Start Flow</h2>
- </div><!-- .vbx-content-menu -->
- <div class="vbx-table-section vbx-subscriptions">
+ </div>
+ <div class="vbx-table-section vbx-outbound">
<form method="post" action="">
<fieldset class="vbx-input-container">
<?php if(count($callerid_numbers)): ?>
View
@@ -1,12 +1,25 @@
{
"name" : "Outbound Flows",
"author" : "Chad Smith <chad@nospam.me>",
- "description" : "Lets you call out with a flow or start calls and messages (to someone else) within a flow.",
+ "description" : "Lets you call out with a flow now or later. Start or schedule calls and messages within a flow.",
"url" : "http://twitter.com/chadsmith",
"links" : [{
"menu" : "Outbound",
"url" : "outbound",
"script" : "outbound.php",
"label" : "Start Flow"
+ },
+ {
+ "menu" : "Outbound",
+ "url" : "outbound/schedule",
+ "script" : "schedule.php",
+ "label" : "Schedule Flow"
+ },
+ {
+ "menu" : "Outbound",
+ "url" : "outbound/queue",
+ "script" : "queue.php",
+ "label" : "Manage Queue",
+ "hook" : true
}]
-}
+}
View
@@ -0,0 +1,18 @@
+$(function() {
+ $('.vbx-queue .event a.delete').click(function() {
+ var $event = $(this).parent().parent().parent(), id = $event.attr('id'), type = $event.children().children('span').eq(1).text();
+ if(confirm('You are about to delete a' + ('sms' == type ? 'n ' : ' ') + type + ' to ' + $event.children().children('span').eq(0).text()+'.'))
+ $.ajax({
+ type: 'POST',
+ url: window.location,
+ data: {
+ remove: id.match(/([\d]+)/)[1]
+ },
+ success: function() {
+ $event.hide(500);
+ },
+ dataType: 'text'
+ });
+ return false
+ });
+})
View
@@ -0,0 +1,96 @@
+<?php
+ $ci =& get_instance();
+ if(defined("HOOK") AND HOOK) {
+ set_time_limit(0);
+ $events = $ci->db->query(sprintf('SELECT id, tenant, number, type, time, callerId, data FROM outbound_queue WHERE time < %d ORDER BY time ASC', time()))->result();
+ if(count($events)) {
+ require_once(APPPATH . 'libraries/twilio.php');
+ foreach($events as $event) {
+ $event->data = json_decode($event->data);
+ $tenant = $ci->settings->get_tenant_by_id($event->tenant);
+ $twilio_sid = $ci->settings->get('twilio_sid', $event->tenant);
+ $twilio_token = $ci->settings->get('twilio_token', $event->tenant);
+ $twilio = new TwilioRestClient($twilio_sid, $twilio_token, $ci->twilio_endpoint);
+ if('sms' == $event->type)
+ $twilio->request("Accounts/{$twilio_sid}/SMS/Messages", 'POST', array('From' => $event->callerId, 'To' => $event->number, 'Body' => $event->data->message));
+ else
+ $twilio->request("Accounts/{$twilio_sid}/Calls", 'POST', array('From' => $event->callerId, 'To' => $event->number, 'Url' => site_url(($tenant->url_prefix ? $tenant->url_prefix . '/' : '') . 'twiml/start/voice/' . $event->data->id)));
+ $ci->db->delete('queue', array('id' => $event->id));
+ }
+ }
+ die;
+ }
+ $user = OpenVBX::getCurrentUser();
+ $tenant_id = $user->values['tenant_id'];
+ $queries = explode(';', file_get_contents(dirname(__FILE__) . '/db.sql'));
+ foreach($queries as $query)
+ if(trim($query))
+ $ci->db->query($query);
+ if($remove = intval($_POST['remove'])) {
+ $ci->db->delete('outbound_queue', array('id' => $remove, 'tenant' => $tenant_id));
+ die;
+ }
+ $events = $ci->db->query(sprintf('SELECT id, number, type, time, callerId, data FROM outbound_queue WHERE tenant=%d ORDER BY time ASC', $tenant_id))->result();
+ OpenVBX::addJS('queue.js');
+?>
+<style>
+ .vbx-queue h3 {
+ font-size: 16px;
+ font-weight: bold;
+ margin-top: 0;
+ }
+ .vbx-queue .event {
+ clear: both;
+ width: 95%;
+ overflow: hidden;
+ margin: 0 auto;
+ padding: 5px 0;
+ border-bottom: 1px solid #eee;
+ }
+ .vbx-queue .event span {
+ display: inline-block;
+ width: 20%;
+ text-align: center;
+ float: left;
+ vertical-align: middle;
+ line-height: 24px;
+ }
+ .vbx-queue a.delete {
+ display: inline-block;
+ height: 24px;
+ width: 24px;
+ text-indent: -999em;
+ background: transparent url(/assets/i/action-icons-sprite.png) no-repeat -68px 0;
+ }
+</style>
+<div class="vbx-content-main">
+ <div class="vbx-content-menu vbx-content-menu-top">
+ <h2 class="vbx-content-heading">Scheduled Events</h2>
+ </div>
+ <div class="vbx-table-section vbx-queue">
+ <div class="event">
+ <h3>
+ <span>Number</span>
+ <span>Type</span>
+ <span>Time</span>
+ <span>Caller ID</span>
+ <span>Delete</span>
+ </h3>
+ </div>
+<?php foreach($events as $event): $event->data = json_decode($event->data); ?>
+ <div class="event" id="event_<?php echo $event->id; ?>">
+ <p>
+ <span><?php echo $event->number; ?></span>
+<?php if('sms' == $event->type): ?>
+ <span title="<?php echo htmlentities($event->data->message); ?>">SMS</span>
+<?php else: ?>
+ <span><?php echo htmlentities($event->data->name); ?></span>
+<?php endif; ?>
+ <span><?php echo date('j-M-Y g:i:sa', $event->time); ?></span>
+ <span><?php echo $event->callerId; ?></span>
+ <span><a href="" class="delete">X</a></span>
+ </p>
+ </div>
+<?php endforeach; ?>
+ </div>
+</div>
View
@@ -0,0 +1,9 @@
+$(function() {
+ $('.add-button').click(function() {
+ var $form = $('form.' + $(this).attr('id'));
+ $('.vbx-schedule form').not($form).slideUp();
+ $form.slideToggle();
+ return false;
+ });
+ $('.time').timePicker({ step: 05, show24Hours: false });
+})
Oops, something went wrong.

0 comments on commit 90df7c4

Please sign in to comment.