Call Flows allow feature code and alternate destination to be optional. If feature code is empty and pin number is provided then require the pin number.

This commit is contained in:
FusionPBX
2023-10-19 19:35:36 -06:00
committed by GitHub
parent fb834ccf8a
commit 100ccc0db2
3 changed files with 172 additions and 142 deletions
+1 -1
View File
@@ -50,7 +50,7 @@
$apps[$x]['destinations'][$y]['label'] = "call_flows"; $apps[$x]['destinations'][$y]['label'] = "call_flows";
$apps[$x]['destinations'][$y]['name'] = "call_flows"; $apps[$x]['destinations'][$y]['name'] = "call_flows";
$apps[$x]['destinations'][$y]['sql'] = "select call_flow_name as name, call_flow_uuid, call_flow_uuid as uuid, call_flow_extension as extension, call_flow_feature_code as destination, call_flow_context as context from v_call_flows "; $apps[$x]['destinations'][$y]['sql'] = "select call_flow_name as name, call_flow_uuid, call_flow_uuid as uuid, call_flow_extension as extension, call_flow_feature_code as destination, call_flow_context as context from v_call_flows ";
$apps[$x]['destinations'][$y]['where'] = "where domain_uuid = '\${domain_uuid}' and call_flow_enabled = 'true' "; $apps[$x]['destinations'][$y]['where'] = "where domain_uuid = '\${domain_uuid}' and call_flow_feature_code is not null and call_flow_enabled = 'true' ";
$apps[$x]['destinations'][$y]['order_by'] = "natural_sort(call_flow_feature_code) asc"; $apps[$x]['destinations'][$y]['order_by'] = "natural_sort(call_flow_feature_code) asc";
$apps[$x]['destinations'][$y]['field']['uuid'] = "uuid"; $apps[$x]['destinations'][$y]['field']['uuid'] = "uuid";
$apps[$x]['destinations'][$y]['field']['name'] = "name"; $apps[$x]['destinations'][$y]['field']['name'] = "name";
+18 -17
View File
@@ -121,7 +121,7 @@
//if (empty($dialplan_uuid)) { $msg .= $text['message-required']." ".$text['label-dialplan_uuid']."<br>\n"; } //if (empty($dialplan_uuid)) { $msg .= $text['message-required']." ".$text['label-dialplan_uuid']."<br>\n"; }
//if (empty($call_flow_name)) { $msg .= $text['message-required']." ".$text['label-call_flow_name']."<br>\n"; } //if (empty($call_flow_name)) { $msg .= $text['message-required']." ".$text['label-call_flow_name']."<br>\n"; }
if (empty($call_flow_extension)) { $msg .= $text['message-required']." ".$text['label-call_flow_extension']."<br>\n"; } if (empty($call_flow_extension)) { $msg .= $text['message-required']." ".$text['label-call_flow_extension']."<br>\n"; }
if (empty($call_flow_feature_code)) { $msg .= $text['message-required']." ".$text['label-call_flow_feature_code']."<br>\n"; } //if (empty($call_flow_feature_code)) { $msg .= $text['message-required']." ".$text['label-call_flow_feature_code']."<br>\n"; }
//if (empty($call_flow_context)) { $msg .= $text['message-required']." ".$text['label-call_flow_context']."<br>\n"; } //if (empty($call_flow_context)) { $msg .= $text['message-required']." ".$text['label-call_flow_context']."<br>\n"; }
//if (empty($call_flow_status)) { $msg .= $text['message-required']." ".$text['label-call_flow_status']."<br>\n"; } //if (empty($call_flow_status)) { $msg .= $text['message-required']." ".$text['label-call_flow_status']."<br>\n"; }
//if (empty($call_flow_pin_number)) { $msg .= $text['message-required']." ".$text['label-call_flow_pin_number']."<br>\n"; } //if (empty($call_flow_pin_number)) { $msg .= $text['message-required']." ".$text['label-call_flow_pin_number']."<br>\n"; }
@@ -181,13 +181,15 @@
//build the xml dialplan //build the xml dialplan
$dialplan_xml = "<extension name=\"".xml::sanitize($call_flow_name)."\" continue=\"\" uuid=\"".xml::sanitize($dialplan_uuid)."\">\n"; $dialplan_xml = "<extension name=\"".xml::sanitize($call_flow_name)."\" continue=\"\" uuid=\"".xml::sanitize($dialplan_uuid)."\">\n";
$dialplan_xml .= " <condition field=\"destination_number\" expression=\"^".xml::sanitize($destination_feature)."$\" break=\"on-true\">\n"; if (!empty($call_flow_feature_code)) {
$dialplan_xml .= " <action application=\"answer\" data=\"\"/>\n"; $dialplan_xml .= " <condition field=\"destination_number\" expression=\"^".xml::sanitize($destination_feature)."$\" break=\"on-true\">\n";
$dialplan_xml .= " <action application=\"sleep\" data=\"200\"/>\n"; $dialplan_xml .= " <action application=\"answer\" data=\"\"/>\n";
$dialplan_xml .= " <action application=\"set\" data=\"feature_code=true\"/>\n"; $dialplan_xml .= " <action application=\"sleep\" data=\"200\"/>\n";
$dialplan_xml .= " <action application=\"set\" data=\"call_flow_uuid=".xml::sanitize($call_flow_uuid)."\"/>\n"; $dialplan_xml .= " <action application=\"set\" data=\"feature_code=true\"/>\n";
$dialplan_xml .= " <action application=\"lua\" data=\"call_flow.lua\"/>\n"; $dialplan_xml .= " <action application=\"set\" data=\"call_flow_uuid=".xml::sanitize($call_flow_uuid)."\"/>\n";
$dialplan_xml .= " </condition>\n"; $dialplan_xml .= " <action application=\"lua\" data=\"call_flow.lua\"/>\n";
$dialplan_xml .= " </condition>\n";
}
$dialplan_xml .= " <condition field=\"destination_number\" expression=\"^".xml::sanitize($destination_extension)."$\">\n"; $dialplan_xml .= " <condition field=\"destination_number\" expression=\"^".xml::sanitize($destination_extension)."$\">\n";
$dialplan_xml .= " <action application=\"set\" data=\"call_flow_uuid=".xml::sanitize($call_flow_uuid)."\"/>\n"; $dialplan_xml .= " <action application=\"set\" data=\"call_flow_uuid=".xml::sanitize($call_flow_uuid)."\"/>\n";
$dialplan_xml .= " <action application=\"lua\" data=\"call_flow.lua\"/>\n"; $dialplan_xml .= " <action application=\"lua\" data=\"call_flow.lua\"/>\n";
@@ -254,9 +256,10 @@
$p->delete("dialplan_edit", "temp"); $p->delete("dialplan_edit", "temp");
// Update subscribed endpoints // Update subscribed endpoints
$fp = event_socket_create(); if (!empty($call_flow_feature_code)) {
if ($fp) { $fp = event_socket_create();
//send the event if ($fp) {
//send the event
$event = "sendevent PRESENCE_IN\n"; $event = "sendevent PRESENCE_IN\n";
$event .= "proto: flow\n"; $event .= "proto: flow\n";
$event .= "event_type: presence\n"; $event .= "event_type: presence\n";
@@ -271,11 +274,9 @@
} else { } else {
$event .= "answer-state: terminated\n"; $event .= "answer-state: terminated\n";
} }
event_socket_request($fp, $event); event_socket_request($fp, $event);
//echo $event."<br />"; fclose($fp);
fclose($fp); }
} }
//debug info //debug info
@@ -558,7 +559,7 @@
echo "</tr>\n"; echo "</tr>\n";
echo "<tr>\n"; echo "<tr>\n";
echo "<td class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n"; echo "<td class='vncell' valign='top' align='left' nowrap='nowrap'>\n";
echo " ".$text['label-call_flow_feature_code']."\n"; echo " ".$text['label-call_flow_feature_code']."\n";
echo "</td>\n"; echo "</td>\n";
echo "<td class='vtable' align='left'>\n"; echo "<td class='vtable' align='left'>\n";
@@ -695,7 +696,7 @@
*/ */
echo "<tr>\n"; echo "<tr>\n";
echo "<td class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n"; echo "<td class='vncell' valign='top' align='left' nowrap='nowrap'>\n";
echo " ".$text['label-call_flow_alternate_destination']."\n"; echo " ".$text['label-call_flow_alternate_destination']."\n";
echo "</td>\n"; echo "</td>\n";
echo "<td class='vtable' align='left'>\n"; echo "<td class='vtable' align='left'>\n";
+153 -124
View File
@@ -25,158 +25,187 @@
-- POSSIBILITY OF SUCH DAMAGE. -- POSSIBILITY OF SUCH DAMAGE.
--set the variables --set the variables
max_tries = "3"; max_tries = "3";
digit_timeout = "5000"; digit_timeout = "5000";
--include config.lua --include config.lua
require "resources.functions.config"; require "resources.functions.config";
--create logger object --create logger object
log = require "resources.functions.log".call_flow log = require "resources.functions.log".call_flow
--additional includes --additional includes
local presence_in = require "resources.functions.presence_in" local presence_in = require "resources.functions.presence_in"
local Database = require "resources.functions.database" local Database = require "resources.functions.database"
local play_file = require "resources.functions.play_file" local play_file = require "resources.functions.play_file"
--include json library --include json library
local json local json
if (debug["sql"]) then if (debug["sql"]) then
json = require "resources.functions.lunajson" json = require "resources.functions.lunajson"
end end
--connect to the database --connect to the database
local dbh = Database.new('system'); local dbh = Database.new('system');
--get the variables --get the variables
if not session:ready() then return end if not session:ready() then return end
local domain_name = session:getVariable("domain_name"); local domain_name = session:getVariable("domain_name");
local domain_uuid = session:getVariable("domain_uuid"); local domain_uuid = session:getVariable("domain_uuid");
local call_flow_uuid = session:getVariable("call_flow_uuid"); local call_flow_uuid = session:getVariable("call_flow_uuid");
local feature_code = session:getVariable("feature_code"); local feature_code = session:getVariable("feature_code");
if not call_flow_uuid then if not call_flow_uuid then
log.warning('Can not get call flow uuid') log.warning('Can not get call flow uuid')
return return
end end
--get the call flow details --get the call flow details
local sql = "SELECT * FROM v_call_flows where call_flow_uuid = :call_flow_uuid" local sql = "SELECT * FROM v_call_flows where call_flow_uuid = :call_flow_uuid"
-- .. "and call_flow_enabled = 'true'" -- .. "and call_flow_enabled = 'true'"
local params = {call_flow_uuid = call_flow_uuid}; local params = {call_flow_uuid = call_flow_uuid};
--log.notice("SQL: %s", sql); --log.notice("SQL: %s", sql);
dbh:query(sql, params, function(row) dbh:query(sql, params, function(row)
call_flow_name = row.call_flow_name; call_flow_name = row.call_flow_name;
call_flow_extension = row.call_flow_extension; call_flow_extension = row.call_flow_extension;
call_flow_feature_code = row.call_flow_feature_code; call_flow_feature_code = row.call_flow_feature_code;
--call_flow_context = row.call_flow_context; --call_flow_context = row.call_flow_context;
call_flow_status = row.call_flow_status; call_flow_status = row.call_flow_status;
pin_number = row.call_flow_pin_number; pin_number = row.call_flow_pin_number;
call_flow_label = row.call_flow_label; call_flow_label = row.call_flow_label;
call_flow_alternate_label = row.call_flow_alternate_label; call_flow_alternate_label = row.call_flow_alternate_label;
call_flow_sound = row.call_flow_sound or ''; call_flow_sound = row.call_flow_sound or '';
call_flow_alternate_sound = row.call_flow_alternate_sound or ''; call_flow_alternate_sound = row.call_flow_alternate_sound or '';
if #call_flow_status == 0 then if #call_flow_status == 0 then
call_flow_status = "true"; call_flow_status = "true";
end
if call_flow_status == "true" then
app = row.call_flow_app;
data = row.call_flow_data;
else
app = row.call_flow_alternate_app;
data = row.call_flow_alternate_data;
end
end);
--check to see if the pin number should be required
pin_required = false;
if (feature_code == "true" and #pin_number > 0) then
pin_required = true;
end
if (#call_flow_feature_code == 0 and #pin_number > 0) then
pin_required = true;
end
--define the check pin number function
function validate_pin_number(pin_number)
if (session:ready()) then
if (#pin_number > 0) then
max_tries = 3;
local min_digits = #pin_number;
local max_digits = #pin_number+1;
session:answer();
local digits = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_pass:#", "", "\\d+");
if (digits == pin_number) then
return true;
else
return false;
end
end end
if call_flow_status == "true" then end
app = row.call_flow_app; end
data = row.call_flow_data
else --request the pin number
app = row.call_flow_alternate_app; if (pin_required) then
data = row.call_flow_alternate_data valid = validate_pin_number(pin_number);
end if (not valid) then
end); valid = validate_pin_number(pin_number);
end
if (not valid) then
valid = validate_pin_number(pin_number);
end
if (not valid) then
session:streamFile("phrase:voicemail_fail_auth:#");
session:hangup("NORMAL_CLEARING");
return;
end
end
--if feature code toggle the status or send to the destination --if feature code toggle the status or send to the destination
if (feature_code == "true") then if (feature_code == "true") then
--if the pin number is provided then require it
if (session:ready()) then
if #pin_number > 0 then
local min_digits = #pin_number;
local max_digits = #pin_number+1;
session:answer();
local digits = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_pass:#", "", "\\d+");
if digits ~= pin_number then
session:streamFile("phrase:voicemail_fail_auth:#");
session:hangup("NORMAL_CLEARING");
return;
end
end
end
--feature code - toggle the status --feature code - toggle the status
local toggle = (call_flow_status == "true") and "false" or "true" local toggle = (call_flow_status == "true") and "false" or "true"
-- turn the lamp -- turn the lamp
presence_in.turn_lamp( toggle == "false",
call_flow_feature_code.."@"..domain_name,
call_flow_uuid
);
if string.find(call_flow_feature_code, 'flow+', nil, true) ~= 1 then
presence_in.turn_lamp( toggle == "false", presence_in.turn_lamp( toggle == "false",
call_flow_feature_code.."@"..domain_name, 'flow+'..call_flow_feature_code.."@"..domain_name,
call_flow_uuid call_flow_uuid
); );
if string.find(call_flow_feature_code, 'flow+', nil, true) ~= 1 then end
presence_in.turn_lamp( toggle == "false",
'flow+'..call_flow_feature_code.."@"..domain_name, --active label
call_flow_uuid local active_flow_label = (toggle == "true") and call_flow_label or call_flow_alternate_label
);
--play info message
local audio_file = (toggle == "true") and call_flow_sound or call_flow_alternate_sound
--show in the console
log.noticef("label=%s,status=%s,uuid=%s,audio=%s", active_flow_label, toggle, call_flow_uuid, audio_file)
--store in database
dbh:query("UPDATE v_call_flows SET call_flow_status = :toggle WHERE call_flow_uuid = :call_flow_uuid", {
toggle = toggle, call_flow_uuid = call_flow_uuid
});
--answer
if (session:ready()) then
session:answer();
end
--display label on Phone (if support)
if (session:ready()) then
if #active_flow_label > 0 then
session:sleep(1000);
local api = freeswitch.API();
local reply = api:executeString("uuid_display "..session:get_uuid().." "..active_flow_label);
end end
end
--active label --play the audio fil or tone
local active_flow_label = (toggle == "true") and call_flow_label or call_flow_alternate_label if (session:ready()) then
if #audio_file > 0 then
--play info message session:sleep(1000);
local audio_file = (toggle == "true") and call_flow_sound or call_flow_alternate_sound play_file(dbh, domain_name, domain_uuid, audio_file)
session:sleep(1000);
--show in the console else
log.noticef("label=%s,status=%s,uuid=%s,audio=%s", active_flow_label, toggle, call_flow_uuid, audio_file) session:sleep(2000);
audio_file = "tone_stream://%(200,0,500,600,700)"
--store in database
dbh:query("UPDATE v_call_flows SET call_flow_status = :toggle WHERE call_flow_uuid = :call_flow_uuid", {
toggle = toggle, call_flow_uuid = call_flow_uuid
});
--answer
if (session:ready()) then
session:answer();
end end
end
--display label on Phone (if support) --hangup the call
if (session:ready()) then if (session:ready()) then
if #active_flow_label > 0 then session:hangup();
session:sleep(1000); end
local api = freeswitch.API(); else
local reply = api:executeString("uuid_display "..session:get_uuid().." "..active_flow_label); --send to the log
end log.notice("execute " .. app .. " " .. data);
end
--play the audio fil or tone --execute the application
if (session:ready()) then if (session:ready()) then
if #audio_file > 0 then session:execute(app, data);
session:sleep(1000); end
play_file(dbh, domain_name, domain_uuid, audio_file)
session:sleep(1000);
else
session:sleep(2000);
audio_file = "tone_stream://%(200,0,500,600,700)"
end
end
--hangup the call --timeout application
if (session:ready()) then --if (not session:answered()) then
session:hangup(); -- session:execute(ring_group_timeout_app, ring_group_timeout_data);
end --end
else end
--send to the log
log.notice("execute " .. app .. " " .. data);
--execute the application
if (session:ready()) then
session:execute(app, data);
end
--timeout application
--if (not session:answered()) then
-- session:execute(ring_group_timeout_app, ring_group_timeout_data);
--end
end