Skip to content
This repository has been archived by the owner on Mar 4, 2021. It is now read-only.

Conference Call - List Calls, Join and Listen #346

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions OpenVBX/controllers/twiml.php
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ public function dial()

$rest_access = $this->input->get_post('rest_access');
$to = $this->input->get_post('to');
$conference_name = $this->input->get_post('conference_name');
$callerid = $this->input->get_post('callerid');

if(!$this->session->userdata('loggedin')
Expand Down Expand Up @@ -360,8 +361,11 @@ public function dial()
{
$this->dial_user_by_client_id($this->input->get_post('to'), $options);
}
else
elseif(strlen($conference_name) > 0)
{
$this->join_conference($conference_name, $this->input->get_post('muted'), $this->input->get_post('beep'));
}
else {
$to = normalize_phone_to_E164($to);
$this->response->dial($to, $options);
}
Expand Down Expand Up @@ -396,7 +400,35 @@ protected function dial_user_by_client_id($client_id, $options)
}
else
{
$this->reponse->say('Unknown client id: '.$user_id.'. Goodbye.');
$this->response->say('Unknown client id: '.$user_id.'. Goodbye.');
$this->response->hangup();
}
}

/**
* Join A Conference Call
*
* @param string $conference_name
* @param string $muted
* @param string $beep
* @return void
*/
protected function join_conference($conference_name,$muted,$beep)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: spaces after commas.

{
if (strlen($conference_name)>2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: spaces around >

{
$confOptions = array(
'muted' => $muted,
'beep' => $beep,
'startConferenceOnEnter' => 'false'
);

$dial = $this->response->dial(NULL, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use lower case null

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm changing the NULL to lower case but the reason I used uppercase was because I copied the function above it which also used upper case. I'll just change all upper case NULL to lower in the file if that's what you prefer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bah... this file is a bit schizophrenic on its nulls. All but two are lower cased. Lower case is preferred. Thank you.

$dial->conference($conference_name, $confOptions);
}
else
{
$this->response->say('Invalid confernce call name. Goodbye.');
$this->response->hangup();
}
}
Expand Down
97 changes: 97 additions & 0 deletions plugins/standard/applets/conference/conference-calls.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

if(isset($_GET['json'])):

$ci =& get_instance();

$service = new Services_Twilio($ci->twilio_sid, $ci->twilio_token);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use built in factory to get a shared service object.

$account = OpenVBX::getAccount();
$account->conferences->getIterator(0, 50, array('Status' => 'in-progress'));


$conferences = $service->account->conferences->getIterator(0, 50, array("Status" => "in-progress"));

$res = array();

foreach($conferences as $call) {
$res[$call->friendly_name] = array(
'date_created' => date("F j, Y, g:i a",strtotime($call->date_created)),
'friendly_name' => $call->friendly_name,
'status' => $call->status,
'duration' => $call->duration
);
}

die(json_encode($res));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set header echo, and use exit.

header('Content-type: application/json');
echo json_encode($res);
exit;

die is preferred in error situations.


endif;

?>

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should already have access to jQuery here. Do you not? If so, we should fix that problem. Plugins should get access to jQuery by default.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing in the browser tells me that the built in jQuery 1.6.2 is available here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I remove the jquery import line I get the follow error: Uncaught ReferenceError: jQuery is not defined. When I add the line back it goes way. I'm not really sure how to work around the issue. Can you point to an example of a plugin that uses jquery without directly importing it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right, this is because we load jQuery at the bottom of the page (it is concatenated in to min). Bah... the solution is a bit tacky but it works:

window.addEventListener('load', function() {
    jQuery(function($) {
        // safely use jQuery here
    });
});

This is the unfortunate price we have to pay for how the scripts are loaded and that there's no script registration system for plugins.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe there is, and I'm forgetting. The code hints that there is a way to include scripts. Lemme investigate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, there it is.

  • Move your javascript in to its own file in the plugin folder. Name it appropriately, i.e.: conferences.js.
  • In your PHP you can register the js file: OpenVBX::addJS('conferences.js');

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. All these suggestion got me around including jquery directly. Checking that in now and then I'll switch the code for the join and listen function and hopefully that will wrap up this feature.

<script>

function join_call(conference_name){

window.parent.Client.call({
'conference_name' : conference_name,
'muted' : 'false',
'beep' : 'true',
'Digits' : 1});

return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning false to cancel a click action is dirty. This should be done through jQuery listeners.

<script type="text/javascript">

function joinConference(params) {
    params = $.extend(params, { 'Digits': 1 });
    window.parent.Client.call(params)
}

jQuery(function($) {
    $('#calls').on('click', '.join', function(e) {
        e.preventDefault();

        joinConference({
            'conference_name': $(this).closest('tr').attr('id'),
            'muted': 'false',
            'beep': 'true'
        });
    });

    $('#calls').on('click', '.listen', function(e) {
        e.preventDefault();

        joinConference({
            'conference_name': $(this).closest('tr').attr('id'),
            'muted': 'true',
            'beep': 'false'
        });
    });
});

</script>

<tr id="conf-friendly-name">
    <td>
        <a class="join">Join</a>
        <a class="listen">Listen</a>
    </td>
</tr>

The jQuery '.on()' method will register a listener on the #calls table that will respond to events that bubble from .listen and .join elements. This allows you to add/remove elements to the table and have them trigger registered events.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first version actually used .on but then jquery 1.6.2 doesn't support using .on it only uses .live which isn't actually equivalent and that why I ended up going with a more basic none jquery implementation. What's the official jquery version for OpenVBX? I think I got 1.6.2 from some other plugin I was reviewing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes... 1.7 introduced .on(). So, yeah, .live().

1.6.2 is the included version. I've not tested with anything beyond that. The last time I upgraded jQuery it was quite the endeavor. Lots of testing and minor tweaks all over the place.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And live can be equivalent:

$('.join').live('click', function(e) {
  // ...
});

If you prefer, I think .delegate() should suffice as well. It may even be preferred to using .live(), I don't fully recall.

$('#calls').delegate('.join', 'click', function(e) {
  // ...
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with delegate since it was most like .on and it working.

}

function listen_call(conference_name){

window.parent.Client.call({
'conference_name' : conference_name,
'muted' : 'true',
'beep' : 'false',
'Digits' : 1});

return false;
}

var $ = jQuery;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get rid of this line by doing:

jQuery(function($) {
   // safely wrapped $ calls here
});```


$(function(){

var
calls = {},
select = $('#calls'),
updateCalls = function() {
$.getJSON(window.location + '/?json=1', function(data) {
$.each(data, function(conference_name, call) {
if(!calls[conference_name]) {
calls[conference_name] = call;
select.append('<tr class="message-row recording-type" id="' + call.friendly_name + '"><td class="recording-date">' + call.date_created + '</td><td class="recording-duration">' + call.friendly_name + '</td><td class="recording-duration">' + call.status + '</td><td class="recording-duration" ><a id="join" onclick="join_call(\'' + call.friendly_name + '\');">Join</a></td><td class="recording-duration" ><a id="listen" onclick="listen_call(\'' + call.friendly_name + '\');">Listen</a></td></tr>');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will add multiple items to the DOM with id="join" and id="listen". HTML id attributes should be unique. You can convert them to classes and not lose anything here.

Should also break this out to multiple lines for readability.

}
});

$.each(calls, function(conference_name, call) {
if(!data[conference_name]) {
delete calls[conference_name];
$('#' + conference_name).fadeOut(250, function() {
$(this).remove();
});
}
});
});
};

updateCalls();
setInterval(updateCalls, 5000);
});
</script>

<div class="vbx-content-main">
<div class="vbx-content-menu vbx-content-menu-top">
<h2 class="vbx-content-heading">Conference Calls In Progress</h2>
</div><!-- .vbx-content-menu -->
<div class="vbx-content-container">
<div class="vbx-content-section">
<table class="vbx-items-grid" border="0" id="calls">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should always include the <thead> and <tbody>. See the built in usage plugin for an example.

<tr class="items-head recording-head"><th>Start Time</th><th>Conference Name</th><th>Status</th><th>Join</th><th>Listen</th></tr>

</table>
</div><!-- .vbx-content-section -->
</div><!-- .vbx-content-container -->
</div><!-- .vbx-content-main -->
2 changes: 2 additions & 0 deletions plugins/standard/applets/conference/twiml.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
$isModerator = false;
$defaultWaitUrl = 'http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient';
$waitUrl = AppletInstance::getValue('wait-url', $defaultWaitUrl);
$record = AppletInstance::getValue('record','do-not-record');

$hasModerator = false;

Expand Down Expand Up @@ -45,6 +46,7 @@
'startConferenceOnEnter' => (!$hasModerator || $isModerator)? 'true' : 'false',
'endConferenceOnExit' => ($hasModerator && $isModerator)? 'true' : 'false',
'waitUrl' => $waitUrl,
'record' => $record,
);

$response = new TwimlResponse();
Expand Down
23 changes: 23 additions & 0 deletions plugins/standard/applets/conference/ui.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
array("url" => "http://twimlets.com/holdmusic?Bucket=com.twilio.music.soft-rock",
"name" => "Soft Rock"),
);
$record = AppletInstance::getValue('record','do-not-record');
?>
<div class="vbx-applet">
<h2>Moderator</h2>
Expand All @@ -33,6 +34,28 @@
<input type="hidden" name="conf-id" value="<?php echo AppletInstance::getValue('conf-id', 'conf_'.mt_rand()) ?>" />
</fieldset>
</div><!-- .vbx-full-pane -->

<h2>Call Recording</h2>
<div class="radio-table">
<table>
<tr class="radio-table-row first <?php echo ($record === 'record-from-start') ? 'on' : 'off' ?>">
<td class="radio-cell">
<input type="radio" class='dial-whom-selector-radio' name="record" value="record-from-start" <?php echo ($record === 'record-from-start') ? 'checked="checked"' : '' ?> />
</td>
<td class="content-cell">
<h4>Enable</h4>
</td>
</tr>
<tr class="radio-table-row last <?php echo ($record === 'do-not-record') ? 'on' : 'off' ?>">
<td class="radio-cell">
<input type="radio" class='dial-whom-selector-radio' name="record" value="do-not-record" <?php echo ($record === 'do-not-record') ? 'checked="checked"' : '' ?> />
</td>
<td class="content-cell">
<h4>Disable</h4>
</td>
</tr>
</table>
</div>

</div><!-- .vbx-applet -->

Expand Down
8 changes: 7 additions & 1 deletion plugins/standard/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,11 @@
"name" : "Standard",
"author" : "Twilio <vbx@twilio.com>",
"description" : "Standard set of applets for OpenVBX",
"url" : "http://openvbx.org"
"url" : "http://openvbx.org",
"links" : [{
"menu" : "Call Log",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent level looks funny here.

"url" : "applets/conference/conference-calls",
"script" : "applets/conference/conference-calls.php",
"label" : "Conference Calls"
}]
}