From 0b69837e457de9d7dd4b3e8bcd80af7e92304f89 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Fri, 22 Nov 2024 02:56:50 -0400 Subject: [PATCH 01/31] Initial commit Still TODO - Now has drag and drop but needs work - alignment of up/down arrows needs to be centered in the cell - action choice need to be reflected on the selection box - permissions missing (assumes superadmin) --- app/phrases/phrase_edit.php | 175 +++++++++++------- .../resources/javascript/phrase_edit.js | 103 +++++++++++ 2 files changed, 208 insertions(+), 70 deletions(-) create mode 100644 app/phrases/resources/javascript/phrase_edit.js diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index 050251f5ad..7a5e868a08 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -41,6 +41,11 @@ $language = new text; $text = $language->get(); +//ensure we have a database object + if (!($database instanceof database)) { + $database = database::new(); + } + //add the defaults $phrase_name = ''; $phrase_language = ''; @@ -162,8 +167,6 @@ //execute insert $p = new permissions; $p->add('phrase_detail_add', 'temp'); - - $database = new database; $database->app_name = 'phrases'; $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; $database->save($array); @@ -226,8 +229,6 @@ //execute update/insert $p = new permissions; $p->add('phrase_detail_add', 'temp'); - - $database = new database; $database->app_name = 'phrases'; $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; $database->save($array); @@ -276,7 +277,6 @@ $sql .= "and phrase_uuid = :phrase_uuid "; $parameters['domain_uuid'] = $domain_uuid; $parameters['phrase_uuid'] = $phrase_uuid; - $database = new database; $row = $database->select($sql, $parameters, 'row'); if (is_array($row) && @sizeof($row) != 0) { $phrase_name = $row["phrase_name"]; @@ -298,17 +298,15 @@ $sql .= "order by phrase_detail_order asc "; $parameters['domain_uuid'] = $_SESSION['domain_uuid']; $parameters['phrase_uuid'] = $phrase_uuid; - $database = new database; $phrase_details = $database->select($sql, $parameters, 'all'); unset($sql, $parameters); } //get the recording names from the database. - $sql = "select recording_name, recording_filename from v_recordings "; + $sql = "select recording_uuid, recording_name, recording_filename from v_recordings "; $sql .= "where domain_uuid = :domain_uuid "; $sql .= "order by recording_name asc "; $parameters['domain_uuid'] = $_SESSION['domain_uuid']; - $database = new database; $recordings = $database->select($sql, $parameters, 'all'); unset($sql, $parameters); @@ -321,8 +319,27 @@ if ($action == 'update') { $document['title'] = $text['title-edit_phrase']; } require_once "resources/header.php"; +//javascript constants for use in the selection option group + echo "\n"; + //js to control action form input - echo "\n"; + +/* old section + echo " \n"; - +//*/ //show the content echo "
\n"; @@ -495,55 +510,66 @@ echo ""; echo "".$text['label-structure'].""; echo ""; - echo " \n"; + //structure table + echo "
\n"; + //headings + echo " \n"; echo " \n"; - echo " \n"; + echo " \n"; echo " \n"; - echo " \n"; - if (!empty($phrase_details)) { - echo " \n"; - } + echo " \n"; +/* +// echo " \n"; +// if (!empty($phrase_details)) { +// echo " \n"; +// } +//*/ echo " \n"; - if (!empty($phrase_details)) { - foreach($phrase_details as $x => $field) { - //clean up output for display - if ($field['phrase_detail_function'] == 'play-file' && substr($field['phrase_detail_data'], 0, 21) == '${lua streamfile.lua ') { - $phrase_detail_function = $text['label-play']; - $phrase_detail_data = str_replace('${lua streamfile.lua ', '', $field['phrase_detail_data']); - $phrase_detail_data = str_replace('}', '', $phrase_detail_data); - } - else if ($field['phrase_detail_function'] == 'execute' && substr($field['phrase_detail_data'], 0, 6) == 'sleep(') { - $phrase_detail_function = $text['label-pause']; - $phrase_detail_data = str_replace('sleep(', '', $field['phrase_detail_data']); - $phrase_detail_data = str_replace(')', '', $phrase_detail_data); - $phrase_detail_data = ($phrase_detail_data / 1000).'s'; // seconds - } - else if ($field['phrase_detail_function'] == 'play-file') { - $phrase_detail_function = $text['label-play']; - $phrase_detail_data = str_replace($_SESSION['switch']['recordings']['dir'].'/'.$_SESSION['domain_name'].'/', '', $field['phrase_detail_data']); - } - else { - $phrase_detail_function = $field['phrase_detail_function']; - $phrase_detail_data = $field['phrase_detail_data']; - } - echo "\n"; - echo " \n"; - echo " \n"; - echo " \n"; - echo " \n"; - echo "\n"; - } - } - unset($phrase_details, $field); - echo "\n"; + echo " \n"; + echo "\n"; +/* +// if (!empty($phrase_details)) { +// foreach($phrase_details as $x => $field) { +// //clean up output for display +// if ($field['phrase_detail_function'] == 'play-file' && substr($field['phrase_detail_data'], 0, 21) == '${lua streamfile.lua ') { +// $phrase_detail_function = $text['label-play']; +// $phrase_detail_data = str_replace('${lua streamfile.lua ', '', $field['phrase_detail_data']); +// $phrase_detail_data = str_replace('}', '', $phrase_detail_data); +// } +// else if ($field['phrase_detail_function'] == 'execute' && substr($field['phrase_detail_data'], 0, 6) == 'sleep(') { +// $phrase_detail_function = $text['label-pause']; +// $phrase_detail_data = str_replace('sleep(', '', $field['phrase_detail_data']); +// $phrase_detail_data = str_replace(')', '', $phrase_detail_data); +// $phrase_detail_data = ($phrase_detail_data / 1000).'s'; // seconds +// } +// else if ($field['phrase_detail_function'] == 'play-file') { +// $phrase_detail_function = $text['label-play']; +// $phrase_detail_data = str_replace($_SESSION['switch']['recordings']['dir'].'/'.$_SESSION['domain_name'].'/', '', $field['phrase_detail_data']); +// } +// else { +// $phrase_detail_function = $field['phrase_detail_function']; +// $phrase_detail_data = $field['phrase_detail_data']; +// } +// echo "\n"; +// echo " \n"; +// echo " \n"; +// echo " \n"; +// echo " \n"; +// echo "\n"; +// } +// } +// unset($phrase_details, $field); +//*/ + echo "\n"; + echo " "; echo " \n"; - echo " \n"; - echo " \n"; - +/* +// echo " \n"; +// */ echo " \n"; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo "\n"; echo "
".$text['label-function']."" . ($text['label-order'] ?? 'Order') . "".$text['label-action']."".$text['label-order']."\n"; - echo " ".$text['label-delete']."\n"; - echo " \n"; - echo " ".($text['label-recording'] ?? 'Recording')."".$text['label-order']."\n"; +// echo " ".$text['label-delete']."\n"; +// echo " \n"; +// echo "
".escape($phrase_detail_function)." ".escape($phrase_detail_data)." ".$field['phrase_detail_order']." "; - if (is_uuid($field['phrase_detail_uuid'])) { - echo " \n"; - echo " \n"; - } - echo "
".escape($phrase_detail_function)." ".escape($phrase_detail_data)." ".$field['phrase_detail_order']." "; +// if (is_uuid($field['phrase_detail_uuid'])) { +// echo " \n"; +// echo " \n"; +// } +// echo "
 
\n"; echo " \n"; - echo " \n"; - echo " \n"; - echo button::create(['type'=>'submit','label'=>$text['button-add'],'icon'=>$_SESSION['theme']['button_icon_add']]); - echo " \n"; +// echo " \n"; +// echo "
 
"; + echo button::create(['type'=>'button','icon'=>$_SESSION['theme']['button_icon_add'], 'onclick' => 'add_row()']); + echo button::create(['type'=>'button','icon'=>'fa-solid fa-minus', 'onclick' => 'remove_row()']); + echo "
 
\n"; echo " ".$text['description-structure']."\n"; diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js new file mode 100644 index 0000000000..f1d92fcfab --- /dev/null +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -0,0 +1,103 @@ +document.addEventListener("DOMContentLoaded", function () { + // Initialize the select options + const select = document.getElementById('phrase_detail_data'); + const grp_rec = document.createElement('optgroup'); + const grp_snd = document.createElement('optgroup'); + + // Add a blank entry + select.appendChild(new Option('', '')); + + // Add recordings + grp_rec.label = 'Recordings'; + for (let i = 0; i < window.phrase_recordings.length; i++) { + grp_rec.appendChild(new Option(' ' + window.phrase_recordings[i].recording_name, window.phrase_recordings[i].recording_uuid)); + } + select.appendChild(grp_rec); + + // Add sounds + grp_snd.label = 'Sounds'; + for (let i = 0; i < window.phrase_sounds.length; i++) { + grp_snd.appendChild(new Option(' ' + window.phrase_sounds[i], i)); + } + select.appendChild(grp_snd); + + // Initialize draggable rows + add_draggable_rows(); +}); + +// Add draggable functionality to rows +function add_draggable_rows() { + const tableBody = document.getElementById('structure'); + let draggedRow = null; + + tableBody.querySelectorAll('tr').forEach((row) => { + // Make rows draggable + row.setAttribute('draggable', 'true'); + + // When dragging starts + row.addEventListener('dragstart', (e) => { + draggedRow = row; + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('text/plain', row.rowIndex); + + // Highlight the dragged row + row.style.backgroundColor = '#d1e7fd'; // Light blue color + row.style.opacity = '0.8'; // Slightly transparent for visual feedback + }); + + // When dragging ends + row.addEventListener('dragend', () => { + draggedRow = null; + + // Clear the background color + row.style.backgroundColor = ''; + row.style.opacity = '1'; // Reset opacity + }); + + // Allow drop (prevent default behavior) + row.addEventListener('dragover', (e) => { + e.preventDefault(); + }); + + // Handle drop + row.addEventListener('drop', (e) => { + e.preventDefault(); + + if (draggedRow && draggedRow !== row) { + // Insert the dragged row before the row it is dropped onto + tableBody.insertBefore(draggedRow, row.nextSibling || row); + } + }); + + // Optional: Highlight drop target + row.addEventListener('dragenter', () => { + row.style.backgroundColor = '#f0f0f0'; // Light gray for drop target + }); + + row.addEventListener('dragleave', () => { + row.style.backgroundColor = ''; // Clear drop target highlight + }); + }); +} + + +// Add a new row to the table +function add_row() { + const tbody = document.getElementById('structure'); + const newRow = document.getElementById('recordings_row').cloneNode(true); + newRow.id = `row_${tbody.childElementCount}`; + newRow.name = `recordings[${tbody.childElementCount}]`; + + tbody.appendChild(newRow); + + // Reinitialize draggable functionality + add_draggable_rows(); +} + +// Remove the last row in the table +function remove_row() { + const tbody = document.getElementById('structure'); + if (tbody && tbody.rows.length > 1) { + tbody.lastElementChild.remove(); + } +} From d7f0f0b94b9565e3ac4a2a550ddf472e6eab6838 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Fri, 22 Nov 2024 14:20:39 -0400 Subject: [PATCH 02/31] better dragging --- app/phrases/phrase_edit.php | 8 +- .../resources/javascript/phrase_edit.js | 76 +++++++------------ app/phrases/resources/styles/phrase_edit.css | 11 +++ 3 files changed, 44 insertions(+), 51 deletions(-) create mode 100644 app/phrases/resources/styles/phrase_edit.css diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index 7a5e868a08..c4db7a8bf7 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -510,6 +510,8 @@ echo ""; echo "".$text['label-structure'].""; echo ""; + //style for dragging rows + echo " "; //structure table echo " \n"; //headings @@ -568,8 +570,10 @@ // } // unset($phrase_details, $field); //*/ - echo "\n"; - echo " "; + + //draggable row + echo "\n"; + echo " "; echo " \n"; echo " \n"; /* // echo " \n"; echo "\n"; - + //structure row echo ""; echo ""; echo "\n"; echo " \n"; echo " \n"; -/* -// echo " \n"; -// if (!empty($phrase_details)) { -// echo " \n"; -// } -//*/ echo " \n"; echo " \n"; echo "\n"; -/* -// if (!empty($phrase_details)) { -// foreach($phrase_details as $x => $field) { -// //clean up output for display -// if ($field['phrase_detail_function'] == 'play-file' && substr($field['phrase_detail_data'], 0, 21) == '${lua streamfile.lua ') { -// $phrase_detail_function = $text['label-play']; -// $phrase_detail_data = str_replace('${lua streamfile.lua ', '', $field['phrase_detail_data']); -// $phrase_detail_data = str_replace('}', '', $phrase_detail_data); -// } -// else if ($field['phrase_detail_function'] == 'execute' && substr($field['phrase_detail_data'], 0, 6) == 'sleep(') { -// $phrase_detail_function = $text['label-pause']; -// $phrase_detail_data = str_replace('sleep(', '', $field['phrase_detail_data']); -// $phrase_detail_data = str_replace(')', '', $phrase_detail_data); -// $phrase_detail_data = ($phrase_detail_data / 1000).'s'; // seconds -// } -// else if ($field['phrase_detail_function'] == 'play-file') { -// $phrase_detail_function = $text['label-play']; -// $phrase_detail_data = str_replace($_SESSION['switch']['recordings']['dir'].'/'.$_SESSION['domain_name'].'/', '', $field['phrase_detail_data']); -// } -// else { -// $phrase_detail_function = $field['phrase_detail_function']; -// $phrase_detail_data = $field['phrase_detail_data']; -// } -// echo "\n"; -// echo " \n"; -// echo " \n"; -// echo " \n"; -// echo " \n"; -// echo "\n"; -// } -// } -// unset($phrase_details, $field); -//*/ - //draggable row echo "\n"; echo " "; echo " \n"; echo " \n"; -/* -// echo " \n"; -// */ echo " \n"; echo ""; echo ""; @@ -690,5 +630,3 @@ //include the footer require_once "resources/footer.php"; - -?> From ba64e7b6b2c872881e19cd97f2453b1d3110096f Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Sat, 23 Nov 2024 10:59:28 -0400 Subject: [PATCH 07/31] use array from POST to save --- app/phrases/phrase_edit.php | 404 +++++++++--------- .../resources/javascript/phrase_edit.js | 8 +- 2 files changed, 206 insertions(+), 206 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index d6e3435d62..415eee723a 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -25,245 +25,245 @@ */ //includes files - require_once dirname(__DIR__, 2) . "/resources/require.php"; - require_once "resources/check_auth.php"; +require_once dirname(__DIR__, 2) . "/resources/require.php"; +require_once "resources/check_auth.php"; //check permissions - if (permission_exists('phrase_add') || permission_exists('phrase_edit')) { - //access granted - } - else { - echo "access denied"; - exit; - } +if (permission_exists('phrase_add') || permission_exists('phrase_edit')) { + //access granted +} +else { + echo "access denied"; + exit; +} //add multi-lingual support - $language = new text; - $text = $language->get(); +$language = new text; +$text = $language->get(); //ensure we have a database object - if (!($database instanceof database)) { - $database = database::new(); - } +if (!($database instanceof database)) { + $database = database::new(); +} //add the defaults - $phrase_name = ''; - $phrase_language = ''; - $phrase_description = ''; +$phrase_name = ''; +$phrase_language = ''; +$phrase_description = ''; //set the action as an add or an update - if (!empty($_REQUEST["id"])) { - $action = "update"; - $phrase_uuid = $_REQUEST["id"]; - } - else { - $action = "add"; - } +if (!empty($_REQUEST["id"])) { + $action = "update"; + $phrase_uuid = $_REQUEST["id"]; +} +else { + $action = "add"; +} //get the form value and set to php variables - if (count($_POST) > 0) { +if (count($_POST) > 0) { - //process the http post data by submitted action - if (!empty($_POST['action']) && is_uuid($_POST['phrase_uuid'])) { - $array[0]['checked'] = 'true'; - $array[0]['uuid'] = $_POST['phrase_uuid']; + //process the http post data by submitted action + if (!empty($_POST['action']) && is_uuid($_POST['phrase_uuid'])) { + $array[0]['checked'] = 'true'; + $array[0]['uuid'] = $_POST['phrase_uuid']; - switch ($_POST['action']) { - case 'delete': - if (permission_exists('phrase_delete')) { - $obj = new phrases; - $obj->delete($array); - } - break; - } - - header('Location: phrases.php'); - exit; + switch ($_POST['action']) { + case 'delete': + if (permission_exists('phrase_delete')) { + $obj = new phrases; + $obj->delete($array); + } + break; } - if (permission_exists('phrase_domain')) { - $domain_uuid = $_POST["domain_uuid"]; + header('Location: phrases.php'); + exit; } - $phrase_name = $_POST["phrase_name"]; - $phrase_language = $_POST["phrase_language"]; - $phrase_enabled = $_POST["phrase_enabled"] ?? 'false'; - $phrase_description = $_POST["phrase_description"]; - $phrase_details_delete = $_POST["phrase_details_delete"] ?? ''; - //clean the name - $phrase_name = str_replace(" ", "_", $phrase_name); - $phrase_name = str_replace("'", "", $phrase_name); + if (permission_exists('phrase_domain')) { + $domain_uuid = $_POST["domain_uuid"]; } + $phrase_name = $_POST["phrase_name"]; + $phrase_language = $_POST["phrase_language"]; + $phrase_enabled = $_POST["phrase_enabled"] ?? 'false'; + $phrase_description = $_POST["phrase_description"]; + $phrase_details_delete = $_POST["phrase_details_delete"] ?? ''; + + //clean the name + $phrase_name = str_replace(" ", "_", $phrase_name); + $phrase_name = str_replace("'", "", $phrase_name); +} //process the changes from the http post if (count($_POST) > 0 && empty($_POST["persistformvar"])) { //get the uuid - if ($action == "update") { - $phrase_uuid = $_POST["phrase_uuid"]; - } + if ($action == "update") { + $phrase_uuid = $_POST["phrase_uuid"]; + } //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: phrases.php'); + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'],'negative'); + header('Location: phrases.php'); + exit; + } + + //check for all required data + $msg = ''; + if (empty($phrase_name)) { $msg .= $text['message-required']." ".$text['label-name']."
\n"; } + if (empty($phrase_language)) { $msg .= $text['message-required']." ".$text['label-language']."
\n"; } + if (!empty($msg) && empty($_POST["persistformvar"])) { + require_once "resources/header.php"; + require_once "resources/persist_form_var.php"; + echo "
\n"; + echo "
 
\n"; echo " \n"; echo " \n"; - echo " "; +// echo " "; + echo " "; if (if_group("superadmin")) { echo " \n"; } - echo " \n"; + //echo " \n"; echo " \n"; From 93025fcd1a81ac796380b9814ed21e4b7750dc2d Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Sat, 23 Nov 2024 00:53:46 -0400 Subject: [PATCH 05/31] fix id and name to be arrays when submitting POST data --- .../resources/javascript/phrase_edit.js | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index 88ff9588f7..4eff6902c7 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -1,6 +1,6 @@ document.addEventListener("DOMContentLoaded", function () { // Initialize the select options - const select = document.getElementById('phrase_detail_data'); + const select = document.getElementById('phrase_detail_data[0]'); const grp_rec = document.createElement('optgroup'); const grp_snd = document.createElement('optgroup'); @@ -77,11 +77,29 @@ function add_row() { const tbody = document.getElementById('structure'); const newRow = document.getElementById('recordings_row').cloneNode(true); - //set id + //reset id newRow.id = 'row_' + tbody.childElementCount - //set 'name' attribute + + //reset 'name' attribute newRow.setAttribute('name', 'recording_' + tbody.childElementCount); + //get the select boxes + const select_list = newRow.querySelectorAll('td select'); //action and recording select dropdown boxes + + //play, pause, execute select box + const select_action = select_list[0]; + + //recording select box + const select_recording = select_list[1]; + + //set the new id and name for action + select_action.id = 'phrase_detail_function[' + tbody.childElementCount - 1 + ']' + select_action.setAttribute('name', 'phrase_detail_function[' + tbody.childElementCount - 1 + ']'); + //set the new id and name for recording + select_recording.id = 'phrase_detail_data[' + tbody.childElementCount - 1 + ']' + select_recording.setAttribute('name', 'phrase_detail_data[' + tbody.childElementCount - 1 + ']'); + + //add the row to the table body tbody.appendChild(newRow); @@ -96,3 +114,7 @@ function remove_row() { tbody.lastElementChild.remove(); } } + +function create_new_name() { + +} From b8ec86671a889a004fc5d438dfe730f4ba093211 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Sat, 23 Nov 2024 00:54:08 -0400 Subject: [PATCH 06/31] remove commented code and update detail data --- app/phrases/phrase_edit.php | 72 +++---------------------------------- 1 file changed, 5 insertions(+), 67 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index e6e3eb1332..d6e3435d62 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -97,7 +97,7 @@ //process the changes from the http post if (count($_POST) > 0 && empty($_POST["persistformvar"])) { - + //get the uuid if ($action == "update") { $phrase_uuid = $_POST["phrase_uuid"]; @@ -506,7 +506,7 @@ echo " ".$text['description-language']."\n"; echo "
".$text['label-structure'].""; @@ -520,62 +520,14 @@ echo " " . ($text['label-order'] ?? 'Order') . "".$text['label-action']."".($text['label-recording'] ?? 'Recording')."".$text['label-order']."\n"; -// echo " ".$text['label-delete']."\n"; -// echo " \n"; -// echo "
".escape($phrase_detail_function)." ".escape($phrase_detail_data)." ".$field['phrase_detail_order']." "; -// if (is_uuid($field['phrase_detail_uuid'])) { -// echo " \n"; -// echo " \n"; -// } -// echo "
\n"; - echo " \n"; echo " \n"; echo " \n"; if (if_group("superadmin")) { @@ -584,23 +536,11 @@ echo " \n"; echo " \n"; -// echo " "; - echo " "; + echo " "; if (if_group("superadmin")) { - echo " \n"; + echo " \n"; } - //echo " \n"; echo " \n"; -// echo " \n"; -// echo "
\n"; + echo $msg."
"; + echo "
\n"; + persistformvar($_POST); + echo "\n"; + require_once "resources/footer.php"; + return; + } + + //add the phrase + if (empty($_POST["persistformvar"]) || $_POST["persistformvar"] != "true") { + if ($action == "add" && permission_exists('phrase_add')) { + //build data array + $phrase_uuid = uuid(); + $array['phrases'][0]['domain_uuid'] = $domain_uuid; + $array['phrases'][0]['phrase_uuid'] = $phrase_uuid; + $array['phrases'][0]['phrase_name'] = $phrase_name; + $array['phrases'][0]['phrase_language'] = $phrase_language; + $array['phrases'][0]['phrase_enabled'] = $phrase_enabled; + $array['phrases'][0]['phrase_description'] = $phrase_description; + + if ($_POST['phrase_detail_function'] != '') { + if ($_POST['phrase_detail_function'] == 'execute' && substr($_POST['phrase_detail_data'], 0,5) != "sleep" && !permission_exists("phrase_execute")) { + header("Location: phrase_edit.php"); + exit; + } + $_POST['phrase_detail_tag'] = 'action'; // default, for now + $_POST['phrase_detail_group'] = "0"; // one group, for now + + if ($_POST['phrase_detail_data'] != '') { + $phrase_detail_uuid = uuid(); + $array['phrase_details'][0]['phrase_detail_uuid'] = $phrase_detail_uuid; + $array['phrase_details'][0]['phrase_uuid'] = $phrase_uuid; + $array['phrase_details'][0]['domain_uuid'] = $domain_uuid; + $array['phrase_details'][0]['phrase_detail_order'] = $_POST['phrase_detail_order']; + $array['phrase_details'][0]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; + $array['phrase_details'][0]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; + $array['phrase_details'][0]['phrase_detail_function'] = $_POST['phrase_detail_function']; + $array['phrase_details'][0]['phrase_detail_data'] = $_POST['phrase_detail_data']; + $array['phrase_details'][0]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; + $array['phrase_details'][0]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; + $array['phrase_details'][0]['phrase_detail_group'] = $_POST['phrase_detail_group']; + } + } + + //execute insert + $p = new permissions; + $p->add('phrase_detail_add', 'temp'); + $database->app_name = 'phrases'; + $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; + $database->save($array); + unset($array); + + $p->delete('phrase_detail_add', 'temp'); + + //save the xml to the file system if the phrase directory is set + //save_phrases_xml(); + + //clear the cache + $cache = new cache; + $cache->delete("languages:".$phrase_language.".".$phrase_uuid); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //send a redirect + message::add($text['message-add']); + header("Location: phrase_edit.php?id=".$phrase_uuid); exit; } - //check for all required data - $msg = ''; - if (empty($phrase_name)) { $msg .= $text['message-required']." ".$text['label-name']."
\n"; } - if (empty($phrase_language)) { $msg .= $text['message-required']." ".$text['label-language']."
\n"; } - if (!empty($msg) && empty($_POST["persistformvar"])) { - require_once "resources/header.php"; - require_once "resources/persist_form_var.php"; - echo "
\n"; - echo "
\n"; - echo $msg."
"; - echo "
\n"; - persistformvar($_POST); - echo "
\n"; - require_once "resources/footer.php"; - return; - } - - //add the phrase - if (empty($_POST["persistformvar"]) || $_POST["persistformvar"] != "true") { - if ($action == "add" && permission_exists('phrase_add')) { - //build data array - $phrase_uuid = uuid(); - $array['phrases'][0]['domain_uuid'] = $domain_uuid; - $array['phrases'][0]['phrase_uuid'] = $phrase_uuid; - $array['phrases'][0]['phrase_name'] = $phrase_name; - $array['phrases'][0]['phrase_language'] = $phrase_language; - $array['phrases'][0]['phrase_enabled'] = $phrase_enabled; - $array['phrases'][0]['phrase_description'] = $phrase_description; - - if ($_POST['phrase_detail_function'] != '') { - if ($_POST['phrase_detail_function'] == 'execute' && substr($_POST['phrase_detail_data'], 0,5) != "sleep" && !permission_exists("phrase_execute")) { - header("Location: phrase_edit.php"); - exit; - } - $_POST['phrase_detail_tag'] = 'action'; // default, for now - $_POST['phrase_detail_group'] = "0"; // one group, for now - - if ($_POST['phrase_detail_data'] != '') { - $phrase_detail_uuid = uuid(); - $array['phrase_details'][0]['phrase_detail_uuid'] = $phrase_detail_uuid; - $array['phrase_details'][0]['phrase_uuid'] = $phrase_uuid; - $array['phrase_details'][0]['domain_uuid'] = $domain_uuid; - $array['phrase_details'][0]['phrase_detail_order'] = $_POST['phrase_detail_order']; - $array['phrase_details'][0]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; - $array['phrase_details'][0]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; - $array['phrase_details'][0]['phrase_detail_function'] = $_POST['phrase_detail_function']; - $array['phrase_details'][0]['phrase_detail_data'] = $_POST['phrase_detail_data']; - $array['phrase_details'][0]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; - $array['phrase_details'][0]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; - $array['phrase_details'][0]['phrase_detail_group'] = $_POST['phrase_detail_group']; - } - } - - //execute insert - $p = new permissions; - $p->add('phrase_detail_add', 'temp'); - $database->app_name = 'phrases'; - $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; - $database->save($array); - unset($array); - - $p->delete('phrase_detail_add', 'temp'); - - //save the xml to the file system if the phrase directory is set - //save_phrases_xml(); - - //clear the cache - $cache = new cache; - $cache->delete("languages:".$phrase_language.".".$phrase_uuid); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //send a redirect - message::add($text['message-add']); - header("Location: phrase_edit.php?id=".$phrase_uuid); - exit; - } - //update the phrase - if ($action == "update" && permission_exists('phrase_edit')) { - //build data array - $array['phrases'][0]['domain_uuid'] = $domain_uuid; - $array['phrases'][0]['phrase_uuid'] = $phrase_uuid; - $array['phrases'][0]['phrase_name'] = $phrase_name; - $array['phrases'][0]['phrase_language'] = $phrase_language; - $array['phrases'][0]['phrase_enabled'] = $phrase_enabled; - $array['phrases'][0]['phrase_description'] = $phrase_description; - - if ($_POST['phrase_detail_function'] != '') { - if ($_POST['phrase_detail_function'] == 'execute' && substr($_POST['phrase_detail_data'], 0,5) != "sleep" && !permission_exists("phrase_execute")) { - header("Location: phrase_edit.php?id=".$phrase_uuid); - exit; - } - $_POST['phrase_detail_tag'] = 'action'; // default, for now - $_POST['phrase_detail_group'] = "0"; // one group, for now - - if ($_POST['phrase_detail_data'] != '') { - $phrase_detail_uuid = uuid(); - $array['phrase_details'][0]['phrase_detail_uuid'] = $phrase_detail_uuid; - $array['phrase_details'][0]['phrase_uuid'] = $phrase_uuid; - $array['phrase_details'][0]['domain_uuid'] = $domain_uuid; - $array['phrase_details'][0]['phrase_detail_order'] = $_POST['phrase_detail_order']; - $array['phrase_details'][0]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; - $array['phrase_details'][0]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; - $array['phrase_details'][0]['phrase_detail_function'] = $_POST['phrase_detail_function']; - $array['phrase_details'][0]['phrase_detail_data'] = $_POST['phrase_detail_data']; - $array['phrase_details'][0]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; - $array['phrase_details'][0]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; - $array['phrase_details'][0]['phrase_detail_group'] = $_POST['phrase_detail_group']; - } + if ($action == "update" && permission_exists('phrase_edit')) { + $array = []; + if (!empty($_POST['phrase_detail_function'])) { + for ($i = 0; $i < count($_POST['phrase_detail_function']); $i++) { + //build data array + $array['phrases'][$i]['domain_uuid'] = $domain_uuid; + $array['phrases'][$i]['phrase_uuid'] = $phrase_uuid; + $array['phrases'][$i]['phrase_name'] = $phrase_name; + $array['phrases'][$i]['phrase_language'] = $phrase_language; + $array['phrases'][$i]['phrase_enabled'] = $phrase_enabled; + $array['phrases'][$i]['phrase_description'] = $phrase_description; + if ($_POST['phrase_detail_function'][$i] == 'execute' && substr($_POST['phrase_detail_data'][$i], 0,5) != "sleep" && !permission_exists("phrase_execute")) { + header("Location: phrase_edit.php?id=".$phrase_uuid); + exit; } + $_POST['phrase_detail_tag'] = 'action'; // default, for now + $_POST['phrase_detail_group'] = "0"; // one group, for now + + if (!empty($_POST['phrase_detail_data'][$i])) { + $phrase_detail_uuid = uuid(); + $array['phrase_details'][$i]['phrase_detail_uuid'] = $phrase_detail_uuid; + $array['phrase_details'][$i]['phrase_uuid'] = $phrase_uuid; + $array['phrase_details'][$i]['domain_uuid'] = $domain_uuid; + $array['phrase_details'][$i]['phrase_detail_order'] = $i; + $array['phrase_details'][$i]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; + $array['phrase_details'][$i]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; + $array['phrase_details'][$i]['phrase_detail_function'] = $_POST['phrase_detail_function'][$i]; + $array['phrase_details'][$i]['phrase_detail_data'] = $_POST['phrase_detail_data'][$i]; + $array['phrase_details'][$i]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; + $array['phrase_details'][$i]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; + $array['phrase_details'][$i]['phrase_detail_group'] = $_POST['phrase_detail_group']; + } + } //execute update/insert - $p = new permissions; - $p->add('phrase_detail_add', 'temp'); - $database->app_name = 'phrases'; - $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; + $p = new permissions; + $p->add('phrase_detail_add', 'temp'); + $database->app_name = 'phrases'; + $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; + if (count($array) > 0) { $database->save($array); - unset($array); - - $p->delete('phrase_detail_add', 'temp'); - - //remove checked phrase details - if ( - is_array($phrase_details_delete) - && @sizeof($phrase_details_delete) != 0 - ) { - $obj = new phrases; - $obj->phrase_uuid = $phrase_uuid; - $obj->delete_details($phrase_details_delete); - } - - //clear the cache - $cache = new cache; - $cache->delete("languages:".$phrase_language.".".$phrase_uuid); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //send a redirect - message::add($text['message-update']); - header("Location: phrase_edit.php?id=".$phrase_uuid); - exit;; - + } } + $p->delete('phrase_detail_add', 'temp'); + + //remove checked phrase details + if ( + is_array($phrase_details_delete) + && @sizeof($phrase_details_delete) != 0 + ) { + $obj = new phrases; + $obj->phrase_uuid = $phrase_uuid; + $obj->delete_details($phrase_details_delete); + } + + //clear the cache + $cache = new cache; + $cache->delete("languages:".$phrase_language.".".$phrase_uuid); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //send a redirect + message::add($text['message-update']); + header("Location: phrase_edit.php?id=".$phrase_uuid); + exit; } - + } } //pre-populate the form diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index 4eff6902c7..83cee83a34 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -93,11 +93,11 @@ function add_row() { const select_recording = select_list[1]; //set the new id and name for action - select_action.id = 'phrase_detail_function[' + tbody.childElementCount - 1 + ']' - select_action.setAttribute('name', 'phrase_detail_function[' + tbody.childElementCount - 1 + ']'); + select_action.id = 'phrase_detail_function[' + tbody.childElementCount + ']' + select_action.setAttribute('name', 'phrase_detail_function[' + tbody.childElementCount + ']'); //set the new id and name for recording - select_recording.id = 'phrase_detail_data[' + tbody.childElementCount - 1 + ']' - select_recording.setAttribute('name', 'phrase_detail_data[' + tbody.childElementCount - 1 + ']'); + select_recording.id = 'phrase_detail_data[' + tbody.childElementCount + ']' + select_recording.setAttribute('name', 'phrase_detail_data[' + tbody.childElementCount + ']'); //add the row to the table body From 66a1034ac0a1f440ea3254bacfc82b798b89721b Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Sun, 24 Nov 2024 09:08:28 -0400 Subject: [PATCH 08/31] use renumbering --- app/phrases/phrase_edit.php | 43 +++++- .../resources/javascript/phrase_edit.js | 124 +++++++++++++----- 2 files changed, 134 insertions(+), 33 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index 415eee723a..e783d63914 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -37,6 +37,16 @@ else { exit; } +//set default domain +if (empty($domain_uuid)) { + $domain_uuid = $_SESSION['domain_uuid'] ?? ''; +} + +//set default user +if (empty($user_uuid)) { + $user_uuid = $_SESSION['user_uuid'] ?? ''; +} + //add multi-lingual support $language = new text; $text = $language->get(); @@ -46,6 +56,11 @@ if (!($database instanceof database)) { $database = database::new(); } +//ensure we have a settings object +if (!($settings instanceof settings)) { + $settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid, 'user_uuid' => $user_uuid]); +} + //add the defaults $phrase_name = ''; $phrase_language = ''; @@ -196,6 +211,7 @@ if (count($_POST) > 0) { if ($action == "update" && permission_exists('phrase_edit')) { $array = []; if (!empty($_POST['phrase_detail_function'])) { + $recording_files = phrases::get_all_domain_recordings($settings); for ($i = 0; $i < count($_POST['phrase_detail_function']); $i++) { //build data array $array['phrases'][$i]['domain_uuid'] = $domain_uuid; @@ -213,6 +229,7 @@ if (count($_POST) > 0) { if (!empty($_POST['phrase_detail_data'][$i])) { $phrase_detail_uuid = uuid(); + $recording_uuid = $_POST['phrase_detail_data'][$i]; $array['phrase_details'][$i]['phrase_detail_uuid'] = $phrase_detail_uuid; $array['phrase_details'][$i]['phrase_uuid'] = $phrase_uuid; $array['phrase_details'][$i]['domain_uuid'] = $domain_uuid; @@ -220,7 +237,7 @@ if (count($_POST) > 0) { $array['phrase_details'][$i]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; $array['phrase_details'][$i]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; $array['phrase_details'][$i]['phrase_detail_function'] = $_POST['phrase_detail_function'][$i]; - $array['phrase_details'][$i]['phrase_detail_data'] = $_POST['phrase_detail_data'][$i]; + $array['phrase_details'][$i]['phrase_detail_data'] = $recording_files[$recording_uuid]; //path and filename of recording $array['phrase_details'][$i]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; $array['phrase_details'][$i]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; $array['phrase_details'][$i]['phrase_detail_group'] = $_POST['phrase_detail_group']; @@ -233,7 +250,7 @@ if (count($_POST) > 0) { $database->app_name = 'phrases'; $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; if (count($array) > 0) { - $database->save($array); + //$database->save($array); } } @@ -322,11 +339,31 @@ if (count($_POST) > 0) { //javascript constants for use in the selection option group echo "\n"; -/* old section - echo " \n"; -//*/ //show the content echo "\n"; @@ -566,7 +477,7 @@ if (count($_POST) > 0) { echo "\n"; echo "
"; echo " \n"; - echo " \n"; echo " \n"; echo " \n"; if (if_group("superadmin")) { @@ -575,10 +486,11 @@ if (count($_POST) > 0) { echo " \n"; echo " \n"; echo " \n"; - echo " "; - if (if_group("superadmin")) { - echo " \n"; - } + echo " "; +// if (if_group("superadmin")) { +// echo " \n"; +// } + echo " "; echo " \n"; echo " \n"; echo ""; diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index d060051155..da9de59f2e 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -1,6 +1,6 @@ document.addEventListener("DOMContentLoaded", function () { // Initialize the select options - const select = document.getElementById('phrase_detail_data[0]'); + const select = document.getElementById('phrase_detail_data_empty'); const grp_rec = document.createElement('optgroup'); const grp_snd = document.createElement('optgroup'); @@ -46,15 +46,21 @@ function add_existing() { //get the select boxes const select_list = newRow.querySelectorAll('td select'); //action and recording select dropdown boxes - //play, pause, execute select box const select_action = select_list[0]; select_by_text(select_action, 'Play'); //recording select box const select_recording = select_list[1]; + select_recording.setAttribute('tag', window.phrase_details[i]['phrase_detail_uuid']); select_by_text(select_recording, window.phrase_details[i]['phrase_detail_display_name']); + const input_fields = newRow.querySelectorAll('td input'); + const uuid_field = input_fields[0]; + uuid_field.setAttribute('id' , 'phrase_detail_uuid[' + i +']'); + uuid_field.setAttribute('name', 'phrase_detail_uuid[' + i +']'); + uuid_field.value = window.phrase_details[i]['phrase_detail_uuid']; + //add the row to the table body tbody.appendChild(newRow); } @@ -81,6 +87,10 @@ function select_by_text(selectElement, textToFind) { console.warn('Text not found in select options'); } +function update_id(element) { + index = element.index; + const hidden_input_field = document.getElementById('hidden_input_field[' + index +']'); +} // Add draggable functionality to rows function add_draggable_rows() { From 8845885d215360ff9d97cf78332fc87dd3dc362b Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Mon, 25 Nov 2024 21:16:32 -0400 Subject: [PATCH 15/31] create function for common code --- app/phrases/phrase_edit.php | 243 ++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 138 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index dd0212145c..c97460eed3 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -37,6 +37,64 @@ else { exit; } +function build_data_array_from_post() { + global $settings, $domain_uuid, $phrase_uuid, $phrase_name, $phrase_language, $phrase_enabled, $phrase_description; + global $drop_rows; + $array = []; + $drop_rows = []; + $drop_row_count = 0; + + $recording_files = phrases::get_all_domain_recordings($settings); + //update the phrase information + $array['phrases'][0]['domain_uuid'] = $domain_uuid; + $array['phrases'][0]['phrase_uuid'] = $phrase_uuid; + $array['phrases'][0]['phrase_name'] = $phrase_name; + $array['phrases'][0]['phrase_language'] = $phrase_language; + $array['phrases'][0]['phrase_enabled'] = $phrase_enabled; + $array['phrases'][0]['phrase_description'] = $phrase_description; + for ($i = 0; $i < count($_POST['phrase_detail_function']); $i++) { + //check for valid uuids + if (!empty($_POST['phrase_detail_uuid'][$i]) && !is_uuid($_POST['phrase_detail_uuid'][$i])) { + continue; + } + //check for the empty rows to delete + if (empty($_POST['phrase_detail_data'][$i]) && !empty($_POST['phrase_detail_uuid'][$i])) { + $drop_rows['phrase_details'][$drop_row_count++]['phrase_detail_uuid'] = $_POST['phrase_detail_uuid'][$i]; + continue; + } + //only save rows with data + if (!empty($_POST['phrase_detail_data'][$i])) { + //build data array + if ($_POST['phrase_detail_function'][$i] == 'execute' && substr($_POST['phrase_detail_data'][$i], 0,5) != "sleep" && !permission_exists("phrase_execute")) { + header("Location: phrase_edit.php?id=".$phrase_uuid); + exit; + } + $_POST['phrase_detail_tag'] = 'action'; // default, for now + $_POST['phrase_detail_group'] = "0"; // one group, for now + + //update existing records in the database + if (!empty($_POST['phrase_detail_uuid'][$i])) { + $phrase_detail_uuid = $_POST['phrase_detail_uuid'][$i]; + } else { + $phrase_detail_uuid = uuid(); + } + $recording_uuid = $_POST['phrase_detail_data'][$i]; + $array['phrase_details'][$i]['phrase_detail_uuid'] = $phrase_detail_uuid; + $array['phrase_details'][$i]['phrase_uuid'] = $phrase_uuid; + $array['phrase_details'][$i]['domain_uuid'] = $domain_uuid; + $array['phrase_details'][$i]['phrase_detail_order'] = $i; + $array['phrase_details'][$i]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; + $array['phrase_details'][$i]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; + $array['phrase_details'][$i]['phrase_detail_function'] = $_POST['phrase_detail_function'][$i]; + $array['phrase_details'][$i]['phrase_detail_data'] = $recording_files[$recording_uuid]; //path and filename of recording + $array['phrase_details'][$i]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; + $array['phrase_details'][$i]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; + $array['phrase_details'][$i]['phrase_detail_group'] = $_POST['phrase_detail_group']; + } + } + return $array; +} + //set default domain if (empty($domain_uuid)) { $domain_uuid = $_SESSION['domain_uuid'] ?? ''; @@ -145,124 +203,46 @@ if (count($_POST) > 0) { //add the phrase if (empty($_POST["persistformvar"]) || $_POST["persistformvar"] != "true") { - if ($action == "add" && permission_exists('phrase_add')) { - //build data array - $phrase_uuid = uuid(); - $array['phrases'][0]['domain_uuid'] = $domain_uuid; - $array['phrases'][0]['phrase_uuid'] = $phrase_uuid; - $array['phrases'][0]['phrase_name'] = $phrase_name; - $array['phrases'][0]['phrase_language'] = $phrase_language; - $array['phrases'][0]['phrase_enabled'] = $phrase_enabled; - $array['phrases'][0]['phrase_description'] = $phrase_description; - - if ($_POST['phrase_detail_function'] != '') { - if ($_POST['phrase_detail_function'] == 'execute' && substr($_POST['phrase_detail_data'], 0,5) != "sleep" && !permission_exists("phrase_execute")) { - header("Location: phrase_edit.php"); - exit; + $message = ''; + switch ($action) { + case 'add': + //redirect when they don't have permission to add a phrase + if (!permission_exists('phrase_add')) { + header('Location: phrases.php'); + exit(); } - $_POST['phrase_detail_tag'] = 'action'; // default, for now - $_POST['phrase_detail_group'] = "0"; // one group, for now - - if ($_POST['phrase_detail_data'] != '') { - $phrase_detail_uuid = uuid(); - $array['phrase_details'][0]['phrase_detail_uuid'] = $phrase_detail_uuid; - $array['phrase_details'][0]['phrase_uuid'] = $phrase_uuid; - $array['phrase_details'][0]['domain_uuid'] = $domain_uuid; - $array['phrase_details'][0]['phrase_detail_order'] = $_POST['phrase_detail_order']; - $array['phrase_details'][0]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; - $array['phrase_details'][0]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; - $array['phrase_details'][0]['phrase_detail_function'] = $_POST['phrase_detail_function']; - $array['phrase_details'][0]['phrase_detail_data'] = $_POST['phrase_detail_data']; - $array['phrase_details'][0]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; - $array['phrase_details'][0]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; - $array['phrase_details'][0]['phrase_detail_group'] = $_POST['phrase_detail_group']; + //set user feedback message to add + $message = $text['message-add']; + $phrase_uuid = uuid(); + //do not break + case 'update': + //redirect when not adding and don't have permission to edit a phrase + if (empty($message)) { + if (!permission_exists('phrase_edit')) { + header('Location: phrases.php'); + exit(); + } + //set user feedback message to update + $message = $text['message-update']; } - } - - //execute insert - $p = new permissions; - $p->add('phrase_detail_add', 'temp'); - $database->app_name = 'phrases'; - $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; - $database->save($array); - unset($array); - - $p->delete('phrase_detail_add', 'temp'); - - //save the xml to the file system if the phrase directory is set - //save_phrases_xml(); - - //clear the cache - $cache = new cache; - $cache->delete("languages:".$phrase_language.".".$phrase_uuid); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //send a redirect - message::add($text['message-add']); - header("Location: phrase_edit.php?id=".$phrase_uuid); - exit; - } - - //update the phrase - if ($action == "update" && permission_exists('phrase_edit')) { - $array = []; - $drop_rows = []; - $drop_row_count = 0; - if (!empty($_POST['phrase_detail_function'])) { - $recording_files = phrases::get_all_domain_recordings($settings); - //update the phrase information - $array['phrases'][0]['domain_uuid'] = $domain_uuid; - $array['phrases'][0]['phrase_uuid'] = $phrase_uuid; - $array['phrases'][0]['phrase_name'] = $phrase_name; - $array['phrases'][0]['phrase_language'] = $phrase_language; - $array['phrases'][0]['phrase_enabled'] = $phrase_enabled; - $array['phrases'][0]['phrase_description'] = $phrase_description; - for ($i = 0; $i < count($_POST['phrase_detail_function']); $i++) { - //check for valid uuids - if (!empty($_POST['phrase_detail_uuid'][$i]) && !is_uuid($_POST['phrase_detail_uuid'][$i])) { - continue; + if (!empty($_POST['phrase_detail_function'])) { + $array = build_data_array_from_post(); + //execute update/insert + $p = new permissions; + $p->add('phrase_detail_add', 'temp'); + $p->add('phrase_detail_edit', 'temp'); + $p->add('phrase_detail_delete', 'temp'); + $database->app_name = 'phrases'; + $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; + if (count($array) > 0) { + $database->save($array); } - //check for the empty rows to delete - if (empty($_POST['phrase_detail_data'][$i]) && !empty($_POST['phrase_detail_uuid'][$i])) { - $drop_rows['phrase_details'][$drop_row_count++]['phrase_detail_uuid'] = $_POST['phrase_detail_uuid'][$i]; - continue; - } - //only save rows with data - if (!empty($_POST['phrase_detail_data'][$i])) { - //build data array - if ($_POST['phrase_detail_function'][$i] == 'execute' && substr($_POST['phrase_detail_data'][$i], 0,5) != "sleep" && !permission_exists("phrase_execute")) { - header("Location: phrase_edit.php?id=".$phrase_uuid); - exit; - } - $_POST['phrase_detail_tag'] = 'action'; // default, for now - $_POST['phrase_detail_group'] = "0"; // one group, for now - - //update existing records in the database - if (!empty($_POST['phrase_detail_uuid'][$i])) { - $phrase_detail_uuid = $_POST['phrase_detail_uuid'][$i]; - } else { - $phrase_detail_uuid = uuid(); - } - $recording_uuid = $_POST['phrase_detail_data'][$i]; - $array['phrase_details'][$i]['phrase_detail_uuid'] = $phrase_detail_uuid; - $array['phrase_details'][$i]['phrase_uuid'] = $phrase_uuid; - $array['phrase_details'][$i]['domain_uuid'] = $domain_uuid; - $array['phrase_details'][$i]['phrase_detail_order'] = $i; - $array['phrase_details'][$i]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; - $array['phrase_details'][$i]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; - $array['phrase_details'][$i]['phrase_detail_function'] = $_POST['phrase_detail_function'][$i]; - $array['phrase_details'][$i]['phrase_detail_data'] = $recording_files[$recording_uuid]; //path and filename of recording - $array['phrase_details'][$i]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; - $array['phrase_details'][$i]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; - $array['phrase_details'][$i]['phrase_detail_group'] = $_POST['phrase_detail_group']; + if (count($drop_rows) > 0) { + $database->delete($drop_rows); } + $p->delete('phrase_detail_add', 'temp'); } - - //execute update/insert + //execute update/insert $p = new permissions; $p->add('phrase_detail_add', 'temp'); $p->add('phrase_detail_edit', 'temp'); @@ -270,38 +250,25 @@ if (count($_POST) > 0) { $database->app_name = 'phrases'; $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; if (count($array) > 0) { - $database->save($array); + //$database->save($array); } if (count($drop_rows) > 0) { $database->delete($drop_rows); } $p->delete('phrase_detail_add', 'temp'); - } + //clear the cache + $cache = new cache; + $cache->delete("languages:".$phrase_language.".".$phrase_uuid); + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } - //remove checked phrase details - if ( - is_array($phrase_details_delete) - && @sizeof($phrase_details_delete) != 0 - ) { - $obj = new phrases; - $obj->phrase_uuid = $phrase_uuid; - $obj->delete_details($phrase_details_delete); - } - - //clear the cache - $cache = new cache; - $cache->delete("languages:".$phrase_language.".".$phrase_uuid); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //send a redirect - message::add($text['message-update']); - header("Location: phrase_edit.php?id=".$phrase_uuid); - exit; + //send a redirect + message::add($message); + header("Location: phrase_edit.php?id=".$phrase_uuid); + exit; } } } From 9f2e4c4ba300bf7481e3c077aff9cbc8b6e9c8cf Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Tue, 26 Nov 2024 02:29:24 -0400 Subject: [PATCH 16/31] allow base64 recordings fix outstanding bugs - still must add sleep and execute functions --- app/phrases/phrase_edit.php | 53 ++++++++++--------- app/phrases/resources/classes/phrases.php | 24 +++++---- .../resources/javascript/phrase_edit.js | 21 ++++---- 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index c97460eed3..60a9df6c40 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -44,6 +44,13 @@ function build_data_array_from_post() { $drop_rows = []; $drop_row_count = 0; + //load sound files from the switch so we can validate selections + $sound_files = (new file)->sounds(); + + //recording_files are: + // 'recording_uuid' => 'recording.wav' + // OR + // 'recording_uuid' => '${lua streamfile.lua ' . base64_data .'}' $recording_files = phrases::get_all_domain_recordings($settings); //update the phrase information $array['phrases'][0]['domain_uuid'] = $domain_uuid; @@ -53,10 +60,6 @@ function build_data_array_from_post() { $array['phrases'][0]['phrase_enabled'] = $phrase_enabled; $array['phrases'][0]['phrase_description'] = $phrase_description; for ($i = 0; $i < count($_POST['phrase_detail_function']); $i++) { - //check for valid uuids - if (!empty($_POST['phrase_detail_uuid'][$i]) && !is_uuid($_POST['phrase_detail_uuid'][$i])) { - continue; - } //check for the empty rows to delete if (empty($_POST['phrase_detail_data'][$i]) && !empty($_POST['phrase_detail_uuid'][$i])) { $drop_rows['phrase_details'][$drop_row_count++]['phrase_detail_uuid'] = $_POST['phrase_detail_uuid'][$i]; @@ -64,6 +67,21 @@ function build_data_array_from_post() { } //only save rows with data if (!empty($_POST['phrase_detail_data'][$i])) { + $recording_uuid_or_file = $_POST['phrase_detail_data'][$i]; + //check for valid recordings and files + if (is_uuid($recording_uuid_or_file)) { + //recording UUID + $file = $recording_files[$recording_uuid_or_file]; + } else { + //not a recording so must be valid path inside the switch recording files + if (in_array($recording_uuid_or_file, $sound_files)) { + //valid switch audio file + $file = $recording_uuid_or_file; + } else { + //ignore an invalid audio file + continue; + } + } //build data array if ($_POST['phrase_detail_function'][$i] == 'execute' && substr($_POST['phrase_detail_data'][$i], 0,5) != "sleep" && !permission_exists("phrase_execute")) { header("Location: phrase_edit.php?id=".$phrase_uuid); @@ -78,7 +96,6 @@ function build_data_array_from_post() { } else { $phrase_detail_uuid = uuid(); } - $recording_uuid = $_POST['phrase_detail_data'][$i]; $array['phrase_details'][$i]['phrase_detail_uuid'] = $phrase_detail_uuid; $array['phrase_details'][$i]['phrase_uuid'] = $phrase_uuid; $array['phrase_details'][$i]['domain_uuid'] = $domain_uuid; @@ -86,7 +103,7 @@ function build_data_array_from_post() { $array['phrase_details'][$i]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; $array['phrase_details'][$i]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; $array['phrase_details'][$i]['phrase_detail_function'] = $_POST['phrase_detail_function'][$i]; - $array['phrase_details'][$i]['phrase_detail_data'] = $recording_files[$recording_uuid]; //path and filename of recording + $array['phrase_details'][$i]['phrase_detail_data'] = $file; //path and filename of recording $array['phrase_details'][$i]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; $array['phrase_details'][$i]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; $array['phrase_details'][$i]['phrase_detail_group'] = $_POST['phrase_detail_group']; @@ -227,22 +244,8 @@ if (count($_POST) > 0) { } if (!empty($_POST['phrase_detail_function'])) { $array = build_data_array_from_post(); - //execute update/insert - $p = new permissions; - $p->add('phrase_detail_add', 'temp'); - $p->add('phrase_detail_edit', 'temp'); - $p->add('phrase_detail_delete', 'temp'); - $database->app_name = 'phrases'; - $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; - if (count($array) > 0) { - $database->save($array); - } - if (count($drop_rows) > 0) { - $database->delete($drop_rows); - } - $p->delete('phrase_detail_add', 'temp'); } - //execute update/insert + //execute update/insert $p = new permissions; $p->add('phrase_detail_add', 'temp'); $p->add('phrase_detail_edit', 'temp'); @@ -250,10 +253,12 @@ if (count($_POST) > 0) { $database->app_name = 'phrases'; $database->app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; if (count($array) > 0) { - //$database->save($array); + $database->save($array); + unset($array); } if (count($drop_rows) > 0) { $database->delete($drop_rows); + unset($drop_rows); } $p->delete('phrase_detail_add', 'temp'); //clear the cache @@ -387,7 +392,7 @@ if (count($_POST) > 0) { if ($action == "update" && permission_exists('phrase_delete')) { echo button::create(['type'=>'button','label'=>$text['button-delete'],'icon'=>$_SESSION['theme']['button_icon_delete'],'name'=>'btn_delete','style'=>'margin-left: 15px;','onclick'=>"modal_open('modal-delete','btn_delete');"]); } - echo button::create(['type'=>'submit','label'=>$text['button-save'],'icon'=>$_SESSION['theme']['button_icon_save'],'id'=>'btn_save','style'=>'margin-left: 15px;']); + echo button::create(['type'=>'submit','onclick'=>'submit_phrase()','label'=>$text['button-save'],'icon'=>$_SESSION['theme']['button_icon_save'],'id'=>'btn_save','style'=>'margin-left: 15px;']); echo " \n"; echo "
\n"; echo "\n"; @@ -453,7 +458,7 @@ if (count($_POST) > 0) { echo " \n"; echo " \n"; echo " \n"; - echo " "; + echo " "; // if (if_group("superadmin")) { // echo " \n"; // } diff --git a/app/phrases/resources/classes/phrases.php b/app/phrases/resources/classes/phrases.php index f60dbea25b..9d06897356 100644 --- a/app/phrases/resources/classes/phrases.php +++ b/app/phrases/resources/classes/phrases.php @@ -451,6 +451,7 @@ if (!class_exists('phrases')) { /** * Returns an associative array of recordings with the uuid as key and recording filename as value. + * When the recording is a base64 encoded recording, the filename returned is the filename only with no path. * @param settings $settings Settings object * @param int $limit (Optional) Limit the number of results returned * @return array @@ -459,18 +460,19 @@ if (!class_exists('phrases')) { //set defaults $recordings = []; $parameters = []; - //get the database object and current domain_uuid + //get the database object from the settings object $database = $settings->database(); - //get the domain name - $domain_name = $database->select("SELECT domain_name from v_domains where domain_uuid = :domain_uuid", ['domain_uuid' => $database->domain_uuid], 'column'); + //get the domain name using the domain_uuid in the database object + $domain_uuid = $settings->domain_uuid(); + $domain_name = $database->select("SELECT domain_name from v_domains where domain_uuid = :domain_uuid", ['domain_uuid' => $domain_uuid], 'column'); //get the recording directory $recordings_dir = $settings->get('switch', 'recordings', '/var/lib/freeswitch/recordings') . DIRECTORY_SEPARATOR . $domain_name; - //build initial sql - $sql = "SELECT recording_uuid, recording_filename FROM v_recordings"; - //add domain_uuid to sql if needed - if (!empty($domain_name) && is_uuid($domain_name)) { + //build initial sql that ignores the domain_uuid + $sql = "SELECT recording_uuid, recording_filename, recording_base64 IS NOT NULL AS has_base64_recording FROM v_recordings"; + //add domain_uuid to sql when available + if (!empty($domain_name) && is_uuid($domain_uuid)) { $sql .= " where domain_uuid = :domain_uuid"; - $parameters['domain_uuid'] = $domain_name; + $parameters['domain_uuid'] = $domain_uuid; } //add limit to sql if needed if (!empty($limit)) { @@ -482,7 +484,11 @@ if (!class_exists('phrases')) { if (!empty($rows)) { //set the path and filename for each of the uuids foreach($rows as $row) { - $recordings[$row['recording_uuid']] = $recordings_dir . DIRECTORY_SEPARATOR . $row['recording_filename']; + if ($row['has_base64_recording']) { + $recordings[$row['recording_uuid']] = '${lua streamfile.lua ' . basename($row['recording_filename']) .'}'; + } else { + $recordings[$row['recording_uuid']] = $recordings_dir . DIRECTORY_SEPARATOR . $row['recording_filename']; + } } } //return recordings or empty array diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index da9de59f2e..6ffdf2f458 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -10,14 +10,14 @@ document.addEventListener("DOMContentLoaded", function () { // Add recordings grp_rec.label = 'Recordings'; for (let i = 0; i < window.phrase_recordings.length; i++) { - grp_rec.appendChild(new Option(' ' + window.phrase_recordings[i].recording_name, window.phrase_recordings[i].recording_uuid)); + grp_rec.appendChild(new Option(window.phrase_recordings[i].recording_name, window.phrase_recordings[i].recording_uuid)); } select.appendChild(grp_rec); // Add sounds grp_snd.label = 'Sounds'; for (let i = 0; i < window.phrase_sounds.length; i++) { - grp_snd.appendChild(new Option(' ' + window.phrase_sounds[i], i)); + grp_snd.appendChild(new Option(window.phrase_sounds[i], window.phrase_sounds[i])); } select.appendChild(grp_snd); @@ -27,9 +27,6 @@ document.addEventListener("DOMContentLoaded", function () { // add empty row add_row(); - // update order - update_order(); - // Initialize draggable rows add_draggable_rows(); }); @@ -52,7 +49,6 @@ function add_existing() { //recording select box const select_recording = select_list[1]; - select_recording.setAttribute('tag', window.phrase_details[i]['phrase_detail_uuid']); select_by_text(select_recording, window.phrase_details[i]['phrase_detail_display_name']); const input_fields = newRow.querySelectorAll('td input'); @@ -87,11 +83,6 @@ function select_by_text(selectElement, textToFind) { console.warn('Text not found in select options'); } -function update_id(element) { - index = element.index; - const hidden_input_field = document.getElementById('hidden_input_field[' + index +']'); -} - // Add draggable functionality to rows function add_draggable_rows() { const tableBody = document.getElementById('structure'); @@ -120,7 +111,6 @@ function add_draggable_rows() { tableBody.addEventListener('dragend', () => { draggedRow.classList.remove('dragging'); draggedRow = null; - update_order(); }); } @@ -154,6 +144,13 @@ function update_order() { }); } +function submit_phrase() { + //ensure order is updated before submitting form + update_order(); + //submit form + const form = document.getElementById('frm').submit(); +} + // Add a new row to the table function add_row() { const tbody = document.getElementById('structure'); From b083d687f4f93f1889d7c218f0de662d4d3f956c Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Tue, 26 Nov 2024 02:29:58 -0400 Subject: [PATCH 17/31] add domain_uuid and user_uuid methods to return loaded IDs --- resources/classes/settings.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/resources/classes/settings.php b/resources/classes/settings.php index acc348636a..c77d30d3a6 100644 --- a/resources/classes/settings.php +++ b/resources/classes/settings.php @@ -94,6 +94,22 @@ class settings { return $this->database; } + /** + * Returns the domain_uuid that was used to load the settings + * @return string domain_uuid or an empty string + */ + public function domain_uuid(): string { + return $this->domain_uuid; + } + + /** + * Returns the user_uuid that was used to load the settings + * @return string user_uuid or an empty string + */ + public function user_uuid(): string { + return $this->user_uuid; + } + /** * Reloads the settings from the database */ From da9be6e02ae9d097732745627a5b3d5cea3b83bd Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Tue, 26 Nov 2024 12:51:46 -0400 Subject: [PATCH 18/31] remove some dependencies on global variables and rename variables --- app/phrases/phrase_edit.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index 60a9df6c40..6e06f72dc5 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -37,9 +37,9 @@ else { exit; } -function build_data_array_from_post() { - global $settings, $domain_uuid, $phrase_uuid, $phrase_name, $phrase_language, $phrase_enabled, $phrase_description; - global $drop_rows; +function build_data_array_from_post(settings $settings) { + global $domain_uuid, $drop_rows; + $phrase_uuid = $_POST['phrase_uuid']; $array = []; $drop_rows = []; $drop_row_count = 0; @@ -55,10 +55,10 @@ function build_data_array_from_post() { //update the phrase information $array['phrases'][0]['domain_uuid'] = $domain_uuid; $array['phrases'][0]['phrase_uuid'] = $phrase_uuid; - $array['phrases'][0]['phrase_name'] = $phrase_name; - $array['phrases'][0]['phrase_language'] = $phrase_language; - $array['phrases'][0]['phrase_enabled'] = $phrase_enabled; - $array['phrases'][0]['phrase_description'] = $phrase_description; + $array['phrases'][0]['phrase_name'] = $_POST['phrase_name']; + $array['phrases'][0]['phrase_language'] = $_POST['phrase_language']; + $array['phrases'][0]['phrase_enabled'] = $_POST['phrase_enabled']; + $array['phrases'][0]['phrase_description'] = $_POST['phrase_description']; for ($i = 0; $i < count($_POST['phrase_detail_function']); $i++) { //check for the empty rows to delete if (empty($_POST['phrase_detail_data'][$i]) && !empty($_POST['phrase_detail_uuid'][$i])) { @@ -71,12 +71,12 @@ function build_data_array_from_post() { //check for valid recordings and files if (is_uuid($recording_uuid_or_file)) { //recording UUID - $file = $recording_files[$recording_uuid_or_file]; + $phrase_detail_data = $recording_files[$recording_uuid_or_file]; } else { //not a recording so must be valid path inside the switch recording files if (in_array($recording_uuid_or_file, $sound_files)) { //valid switch audio file - $file = $recording_uuid_or_file; + $phrase_detail_data = $recording_uuid_or_file; } else { //ignore an invalid audio file continue; @@ -103,7 +103,7 @@ function build_data_array_from_post() { $array['phrase_details'][$i]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; $array['phrase_details'][$i]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; $array['phrase_details'][$i]['phrase_detail_function'] = $_POST['phrase_detail_function'][$i]; - $array['phrase_details'][$i]['phrase_detail_data'] = $file; //path and filename of recording + $array['phrase_details'][$i]['phrase_detail_data'] = $phrase_detail_data; //path and filename of recording $array['phrase_details'][$i]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; $array['phrase_details'][$i]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; $array['phrase_details'][$i]['phrase_detail_group'] = $_POST['phrase_detail_group']; @@ -243,7 +243,7 @@ if (count($_POST) > 0) { $message = $text['message-update']; } if (!empty($_POST['phrase_detail_function'])) { - $array = build_data_array_from_post(); + $array = build_data_array_from_post($settings); } //execute update/insert $p = new permissions; From 81e842fd11c6e5050a710b827ca471d317288889 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Mon, 2 Dec 2024 11:44:00 -0400 Subject: [PATCH 19/31] use recording_name from recordings table for display and match Matching the display name in the phrase details is more difficult as the phrase_details table does not contain the name to match. This commit fixes the preselect that happens when the page is first loaded --- app/phrases/phrase_edit.php | 38 ++++++++++++------- .../resources/javascript/phrase_edit.js | 2 +- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index 6e06f72dc5..2d4efb859a 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -47,11 +47,6 @@ function build_data_array_from_post(settings $settings) { //load sound files from the switch so we can validate selections $sound_files = (new file)->sounds(); - //recording_files are: - // 'recording_uuid' => 'recording.wav' - // OR - // 'recording_uuid' => '${lua streamfile.lua ' . base64_data .'}' - $recording_files = phrases::get_all_domain_recordings($settings); //update the phrase information $array['phrases'][0]['domain_uuid'] = $domain_uuid; $array['phrases'][0]['phrase_uuid'] = $phrase_uuid; @@ -59,6 +54,16 @@ function build_data_array_from_post(settings $settings) { $array['phrases'][0]['phrase_language'] = $_POST['phrase_language']; $array['phrases'][0]['phrase_enabled'] = $_POST['phrase_enabled']; $array['phrases'][0]['phrase_description'] = $_POST['phrase_description']; + + //recording_files are: + // 'recording_uuid' => 'recording.wav' + // OR + // 'recording_uuid' => '${lua streamfile.lua ' . base64_data .'}' + $recording_files = phrases::get_all_domain_recordings($settings); + + // + // Create two arrays - one for rows to delete and one for new/updated rows + // for ($i = 0; $i < count($_POST['phrase_detail_function']); $i++) { //check for the empty rows to delete if (empty($_POST['phrase_detail_data'][$i]) && !empty($_POST['phrase_detail_uuid'][$i])) { @@ -246,7 +251,7 @@ if (count($_POST) > 0) { $array = build_data_array_from_post($settings); } //execute update/insert - $p = new permissions; + $p = permissions::new(); $p->add('phrase_detail_add', 'temp'); $p->add('phrase_detail_edit', 'temp'); $p->add('phrase_detail_delete', 'temp'); @@ -315,7 +320,7 @@ if (count($_POST) > 0) { } //get the recording names from the database. - $sql = "select recording_uuid, recording_name, recording_filename from v_recordings "; + $sql = "select recording_uuid, recording_name, recording_filename, domain_uuid from v_recordings "; $sql .= "where domain_uuid = :domain_uuid "; $sql .= "order by recording_name asc "; $parameters['domain_uuid'] = $_SESSION['domain_uuid']; @@ -337,16 +342,21 @@ if (count($_POST) > 0) { //existing details if (!empty($phrase_details)) { - //update the array to create the display name + //update the array to include the recording name for display foreach ($phrase_details as &$row) { $file = basename($row['phrase_detail_data']); - $basename = substr($file, 0, strlen($file) - 4); - $display_name = basename(str_replace($_SESSION['switch']['recordings']['dir'].'/'.$_SESSION['domain_name'].'/', '', $row['phrase_detail_data'])); - //remove the file ending - if (str_ends_with($display_name, '.wav') || str_ends_with($display_name, '.mp3') || str_ends_with($display_name, '.flac') || str_ends_with($display_name, '.mp4') || str_ends_with($display_name, '.gsm')) { - $display_name = substr($display_name, 0, strlen($display_name) - 4); + //get the recording name based on the file matched + $name_index = false; + foreach ($recordings as $key => $recordings_row) { + //match on filename first and then domain_uuid + if ($recordings_row['recording_filename'] === $file && $recordings_row['domain_uuid'] === $row['domain_uuid']) { + $name_index = $key; + break; + } + } + if ($name_index !== false) { + $row['recording_name'] = $recordings[$name_index]['recording_name']; } - $row['phrase_detail_display_name'] = ucfirst(str_replace('_', ' ', $basename)); } echo "window.phrase_details = " . json_encode($phrase_details, true) . ";\n"; } else { diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index 6ffdf2f458..f01980e06e 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -49,7 +49,7 @@ function add_existing() { //recording select box const select_recording = select_list[1]; - select_by_text(select_recording, window.phrase_details[i]['phrase_detail_display_name']); + select_by_text(select_recording, window.phrase_details[i]['recording_name']); const input_fields = newRow.querySelectorAll('td input'); const uuid_field = input_fields[0]; From 870ab765cadceaa22b93d66ac6ff1a9437a028f8 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Mon, 2 Dec 2024 14:16:48 -0400 Subject: [PATCH 20/31] fix sound files not showing --- app/phrases/phrase_edit.php | 38 ++++++++++++------- .../resources/javascript/phrase_edit.js | 2 +- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index 2d4efb859a..f6ff005a09 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -327,6 +327,10 @@ if (count($_POST) > 0) { $recordings = $database->select($sql, $parameters, 'all'); unset($sql, $parameters); +//get the switch sound files + $file = new file; + $sound_files = $file->sounds(); + //create token $object = new token; $token = $object->create($_SERVER['PHP_SELF']); @@ -342,47 +346,55 @@ if (count($_POST) > 0) { //existing details if (!empty($phrase_details)) { - //update the array to include the recording name for display + //update the array to include the recording name for display in select box foreach ($phrase_details as &$row) { + $row['display_name'] = ''; $file = basename($row['phrase_detail_data']); - //get the recording name based on the file matched - $name_index = false; + //get the display_name from recording name based on the file matched foreach ($recordings as $key => $recordings_row) { //match on filename first and then domain_uuid if ($recordings_row['recording_filename'] === $file && $recordings_row['domain_uuid'] === $row['domain_uuid']) { - $name_index = $key; + $row['display_name'] = $recordings[$key]['recording_name']; break; } } - if ($name_index !== false) { - $row['recording_name'] = $recordings[$name_index]['recording_name']; + //check if display_name was not found in the recording names + if (strlen($row['display_name']) === 0) { + //try finding display_name in the switch sound files + if (!empty($sound_files)) { + //use optimized php function with strict comparison + $i = array_search($row['phrase_detail_data'], $sound_files, true); + //if found in the switch sound files + if ($i !== false) { + //set the display_name to the switch sound file name + $row['display_name'] = $sound_files[$i]; + } + } } } + //send the phrase details to the browser as a global scope json array object echo "window.phrase_details = " . json_encode($phrase_details, true) . ";\n"; } else { - //send an empty array + //send an empty array to the browser as a global scope json array object echo "window.phrase_details = [];\n"; } //recording files if ($recordings !== false) { - //recordings + //send recordings to the browser as a global scope json array object echo "window.phrase_recordings = " . json_encode($recordings, true) . ";\n"; } else { //send an empty array echo "window.phrase_recordings = [];\n"; } - //sound files - $file = new file; - $sound_files = $file->sounds(); if (!empty($sound_files)) { - //sounds + //send sounds to the browser as a global scope json array object echo "window.phrase_sounds = " . json_encode($sound_files, true) . ";\n"; } echo "\n"; -//js to control action form input +//javascript to control action form input using drag and drop echo "\n"; //show the content diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index f01980e06e..537489bc15 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -49,7 +49,7 @@ function add_existing() { //recording select box const select_recording = select_list[1]; - select_by_text(select_recording, window.phrase_details[i]['recording_name']); + select_by_text(select_recording, window.phrase_details[i]['display_name']); const input_fields = newRow.querySelectorAll('td input'); const uuid_field = input_fields[0]; From b14e8f20c8a25440c224f8ade9de7342eaa3477e Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Mon, 2 Dec 2024 17:33:52 -0400 Subject: [PATCH 21/31] use labels --- app/phrases/phrase_edit.php | 4 +++- .../resources/javascript/phrase_edit.js | 23 +++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index f6ff005a09..7920aab996 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -342,7 +342,9 @@ if (count($_POST) > 0) { //javascript constants for use in the selection option group echo ""; diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index e8ba79f0af..e878f04247 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -414,10 +414,10 @@ if (count($_POST) > 0) { } } //send the phrase details to the browser as a global scope json array object - echo "window.phrase_details = " . json_encode($phrase_details, true) . ";\n"; + //echo "window.phrase_details = " . json_encode($phrase_details, true) . ";\n"; } else { //send an empty array to the browser as a global scope json array object - echo "window.phrase_details = [];\n"; + //echo "window.phrase_details = [];\n"; } //recording files diff --git a/app/phrases/phrase_responder.php b/app/phrases/phrase_responder.php new file mode 100644 index 0000000000..004042d8a4 --- /dev/null +++ b/app/phrases/phrase_responder.php @@ -0,0 +1,199 @@ + + * Portions created by the Initial Developer are Copyright (C) 2008-2024 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark J Crane + * Tim Fry + */ + +// require the class loader and global functions +//require dirname(__DIR__, 2) . '/resources/classes/auto_loader.php'; new auto_loader(); +//require dirname(__DIR__, 2) . '/resources/functions.php'; + +require_once dirname(__DIR__, 2) . '/resources/require.php'; + +// Disable output buffering and compression +ini_set('output_buffering', 'off'); +ini_set('zlib.output_compression', 'off'); +ini_set('implicit_flush', 1); +ob_implicit_flush(1); + +// Set headers to ensure immediate response +header('Content-Type: text/plain'); +header('Cache-Control: no-cache'); +header('Content-Encoding: none'); + +function fetch_recordings(database $database): array { + global $domain_uuid; + // guard against corrupt data + if (empty($domain_uuid) || !is_uuid($domain_uuid)) { + throw new Exception('Domain is invalid'); + } + // always return an array + $return_value = []; + $sql = "select recording_uuid, recording_name, recording_filename, domain_uuid from v_recordings "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "order by recording_name asc "; + $parameters['domain_uuid'] = $domain_uuid; + $recordings = $database->select($sql, $parameters, 'all'); + if (!empty($recordings)) { + $return_value = $recordings; + } + return $return_value; +} + +function fetch_sound_files(settings $settings) { + $return_value = []; + //get the switch sound files + $file = new file($settings); + $sound_files = $file->sounds(); + + //try finding display_name in the switch sound files + if (!empty($sound_files)) { + $return_value = $sound_files; + } + return $return_value; +} + +function fetch_phrase_details(settings $settings, string $phrase_uuid): array { + global $domain_uuid; + // guard against corrupt data + if (empty($domain_uuid) || !is_uuid($domain_uuid)) { + throw new Exception('Domain is invalid'); + } + if (empty($phrase_uuid) || !is_uuid($phrase_uuid)) { + throw new Exception('Phrase UUID is invalid'); + } + + $database = $settings->database(); + // set the return value to be an empty array + $return_value = []; + // get the phrase details + if (!empty($phrase_uuid)) { + $sql = "select * from v_phrase_details "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and phrase_uuid = :phrase_uuid "; + $sql .= "order by phrase_detail_order asc "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['phrase_uuid'] = $phrase_uuid; + $phrase_details = $database->select($sql, $parameters, 'all'); + } + //existing details + if (!empty($phrase_details)) { + $recordings = fetch_recordings($database); + $sound_files = fetch_sound_files($settings); + //update the array to include the recording name for display in select box + foreach ($phrase_details as &$row) { + $row['display_name'] = ''; + $file = basename($row['phrase_detail_data']); + //get the display_name from recording name based on the file matched + foreach ($recordings as $key => $recordings_row) { + //match on filename first and then domain_uuid + if ($recordings_row['recording_filename'] === $file && $recordings_row['domain_uuid'] === $row['domain_uuid']) { + $row['display_name'] = $recordings[$key]['recording_name']; + break; + } + } + //check if display_name was not found in the recording names + if (strlen($row['display_name']) === 0) { + //try finding display_name in the switch sound files + if (!empty($sound_files)) { + //use optimized php function with strict comparison + $i = array_search($row['phrase_detail_data'], $sound_files, true); + //if found in the switch sound files + if ($i !== false) { + //set the display_name to the switch sound file name + $row['display_name'] = $sound_files[$i]; + } + } + } + } + $return_value = $phrase_details; + } + return $return_value; +} + +function fetch_domain_uuid(database $database): string { + $domain = $_SERVER['HTTP_HOST']; + $domain_uuid = ''; + $sql = 'select domain_uuid from v_domains where domain_name = :domain'; + $parameters = []; + $parameters['domain'] = $domain; + $result = $database->select($sql, $parameters, 'column'); + if (!empty($result)) { + $domain_uuid = $result; + } + return $domain_uuid; +} + +function send_message(string $json_data) { + echo $json_data . "\n"; + ob_flush(); + flush(); +} + +$config = config::load(); +$database = database::new(['config' => $config]); +$domain_uuid = fetch_domain_uuid($database); +$settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); + +// Set default response +$response = ['code' => 200, 'message' => '']; + +// Check if the request method is POST +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $message = ''; + // Get the raw POST data + $input = file_get_contents('php://input'); + + // Parse JSON data + $data = json_decode($input, true); // Decode JSON as associative array + + if (isset($data['request'])) { + try { + //check the data source requested + switch ($data['request']) { + case 'sound_files': + $message = fetch_sound_files($settings); + break; + case 'recordings': + $message = fetch_recordings($database); + break; + case 'phrase_details': + $phrase_uuid = $data['data']; + $message = fetch_phrase_details($settings, $phrase_uuid); + break; + } + } catch (Exception $e) { + $response['code'] = 500; + $message = $e->getMessage(); + } + } + //save the message + $response['message'] = $message; + //send the response + send_message(json_encode($response)); + exit(); +} + +exit(); diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index 1385f5a769..e226919a39 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -1,4 +1,4 @@ -document.addEventListener("DOMContentLoaded", function () { +document.addEventListener("DOMContentLoaded", async function () { // Initialize the select options const select = document.getElementById('phrase_detail_data_empty'); const grp_rec = document.createElement('optgroup'); @@ -9,17 +9,27 @@ document.addEventListener("DOMContentLoaded", function () { // Add recordings grp_rec.label = window.phrase_label_recordings; - for (let i = 0; i < window.phrase_recordings.length; i++) { - grp_rec.appendChild(new Option(window.phrase_recordings[i].recording_name, window.phrase_recordings[i].recording_uuid)); + try { + const phrase_recordings = await fetch_data({request: 'recordings', data: ''}); + for (let i = 0; i < phrase_recordings.length; i++) { + grp_rec.appendChild(new Option(phrase_recordings[i].recording_name, phrase_recordings[i].recording_uuid)); + } + select.appendChild(grp_rec); + } catch (error) { + console.error("Error fetching recordings:", error); } - select.appendChild(grp_rec); // Add sounds grp_snd.label = window.phrase_label_sounds; - for (let i = 0; i < window.phrase_sounds.length; i++) { - grp_snd.appendChild(new Option(window.phrase_sounds[i], window.phrase_sounds[i])); + try { + const phrase_sounds = await fetch_data({request: 'sound_files', data: ''}); + for (let i = 0; i < phrase_sounds.length; i++) { + grp_snd.appendChild(new Option(phrase_sounds[i], phrase_sounds[i])); + } + select.appendChild(grp_snd); + } catch (error) { + console.error("Error fetching recordings:", error); } - select.appendChild(grp_snd); // add the existing data add_existing(); @@ -31,34 +41,65 @@ document.addEventListener("DOMContentLoaded", function () { add_draggable_rows(); }); +async function fetch_data(command) { + try { + const response = await fetch('phrase_responder.php', { + method: 'POST', // or 'GET' depending on your requirement + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(command) // If sending data with POST + }); + + const data = await response.json(); + + return data.message; + + } catch (error) { + console.error('Error:', error); + } +} + // // Inserts all existing records before the empty one // -function add_existing() { +async function add_existing() { + //get the body structure const tbody = document.getElementById('structure'); - - for (let index=0; index < window.phrase_details.length; index++) { + //get the phrase id + const urlParams = new URLSearchParams(window.location.search); + const phrase_uuid = urlParams.get('id'); + //fetch the phrase details from the database + const phrase_details = await fetch_data({request: 'phrase_details', data: phrase_uuid}); + //display the phrase details + for (let index=0; index < phrase_details.length; index++) { + //add an empty row add_row(); + //get the action select box const select_action = document.getElementById('phrase_detail_function[' + index + ']'); - select_by_value(select_action, window.phrase_details[index].phrase_detail_function); + //set the chosen option + select_by_value(select_action, phrase_details[index].phrase_detail_function); + //get the data select box const select_data = document.getElementById('phrase_detail_data[' + index + ']'); - select_by_text(select_data, window.phrase_details[index]['display_name']); + //set the chosen option + select_by_text(select_data, phrase_details[index]['display_name']); const uuid_field = document.getElementById('phrase_detail_uuid[' +index+']'); - uuid_field.value = window.phrase_details[index]['phrase_detail_uuid']; + uuid_field.value = phrase_details[index]['phrase_detail_uuid']; + //set the slider value const slider = document.getElementById('slider['+index+']'); const sleep = document.getElementById('sleep['+index+']'); const phrase_detail_text = document.getElementById('phrase_detail_text['+index+']'); //update the sleep data - if (window.phrase_details[index].phrase_detail_function === 'pause') { - sleep.value = window.phrase_details[index].phrase_detail_data; - slider.value = window.phrase_details[index].phrase_detail_data; + if (phrase_details[index].phrase_detail_function === 'pause') { + sleep.value = phrase_details[index].phrase_detail_data; + slider.value = phrase_details[index].phrase_detail_data; } //update the execute text - if (window.phrase_details[index].phrase_detail_function === 'execute') { - phrase_detail_text.value = window.phrase_details[index].phrase_detail_data; + if (phrase_details[index].phrase_detail_function === 'execute') { + phrase_detail_text.value = phrase_details[index].phrase_detail_data; } // Manually trigger the change event to select the proper display - if (window.phrase_details[index].phrase_detail_function !== 'play-file') { + if (phrase_details[index].phrase_detail_function !== 'play-file') { const changeEvent = new Event('change', { bubbles: true }); select_action.dispatchEvent(changeEvent); } diff --git a/app/phrases/resources/javascript/phrase_fetch.js b/app/phrases/resources/javascript/phrase_fetch.js new file mode 100644 index 0000000000..2e899040b0 --- /dev/null +++ b/app/phrases/resources/javascript/phrase_fetch.js @@ -0,0 +1,52 @@ +/* + * FusionPBX + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FusionPBX + * + * The Initial Developer of the Original Code is + * Mark J Crane + * Portions created by the Initial Developer are Copyright (C) 2008-2024 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark J Crane + * Tim Fry + */ + +async function fetchData() { + try { + const response = await fetch('phrase_responder.php', { + method: 'POST', // or 'GET' depending on your requirement + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ request: 'phrase_details', phrase_uuid: '86141ace-b218-4f07-b412-fe02d4fdde17' }) // If sending data with POST + }); + + const data = await response.text(); + const json = JSON.parse(data); + + const body = document.body; + const input = document.createElement('input'); + input.type = 'text'; + input.value = json.message; + body.appendChild(input); + + console.log(data); + } catch (error) { + console.error('Error:', error); + } +} + +fetchData(); From 29962bb4b2e81312698bdcc1c8db56ed4f45481a Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Fri, 13 Dec 2024 16:45:02 -0400 Subject: [PATCH 25/31] add a Loading indicator to show fetching data in progress --- app/phrases/phrase_edit.php | 2 ++ app/phrases/resources/javascript/phrase_edit.js | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index e878f04247..e5167be1f3 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -507,6 +507,8 @@ if (count($_POST) > 0) { //draggable rows are initially empty echo "\n"; echo ""; + //show loading + echo " 
Loading...
 \n"; //cloning row and buttons created outside of 'structure' table body echo ""; echo "\n"; diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index e226919a39..025cd6f718 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -41,6 +41,14 @@ document.addEventListener("DOMContentLoaded", async function () { add_draggable_rows(); }); +function remove_loading() { + //remove loading + const loading = document.getElementById('loading'); + if (loading) { + loading.remove(); + } +} + async function fetch_data(command) { try { const response = await fetch('phrase_responder.php', { @@ -104,6 +112,8 @@ async function add_existing() { select_action.dispatchEvent(changeEvent); } } + + remove_loading(); } // From ba8e092d87d2f6e4a5a7fdbcce3c1b80b0ae2d8c Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Fri, 13 Dec 2024 16:47:16 -0400 Subject: [PATCH 26/31] add text of "Add" and "Delete" to plus and minus buttons --- app/phrases/phrase_edit.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index e5167be1f3..5fb2aaf682 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -538,8 +538,8 @@ if (count($_POST) > 0) { echo ""; echo " "; echo "
"; - echo button::create(['type'=>'button','icon'=>$_SESSION['theme']['button_icon_add'], 'onclick' => 'add_row()']); - echo button::create(['type'=>'button','icon'=>'fa-solid fa-minus', 'onclick' => 'remove_row()']); + echo button::create(['type'=>'button','icon'=>$_SESSION['theme']['button_icon_add'], 'label' => $text['label-add'], 'onclick' => 'add_row()']); + echo button::create(['type'=>'button','icon'=>'fa-solid fa-minus', 'label' => $text['label-delete'], 'onclick' => 'remove_row()']); echo "
"; echo " "; echo ""; From 4e375c6d46bfaf984a927a888bdc45a922a13753 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Fri, 13 Dec 2024 16:54:28 -0400 Subject: [PATCH 27/31] remove console logging statements --- app/phrases/resources/javascript/phrase_edit.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index 025cd6f718..ba6e6cee4c 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -213,7 +213,6 @@ function update_order() { //get the input boxes const input_boxes = row.querySelectorAll('td input'); - console.log(input_boxes); //uuid const phrase_detail_uuid = input_boxes[0]; phrase_detail_uuid.removeAttribute('id'); @@ -222,7 +221,6 @@ function update_order() { //execute action const phrase_detail_text = input_boxes[1]; temp_value = phrase_detail_text.value; - console.log('phrase_detail_text', temp_value); phrase_detail_text.removeAttribute('id'); phrase_detail_text.id = 'phrase_detail_text[' + index + ']'; phrase_detail_text.name = phrase_detail_text.id; From b24ea673bb900b70680e1f9f0ded2d2525a638f4 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Wed, 18 Dec 2024 01:49:04 -0400 Subject: [PATCH 28/31] move phrase responder to resource folder --- .../resources/javascript/phrase_edit.js | 3 +- app/phrases/resources/phrase_responder.php | 204 ++++++++++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 app/phrases/resources/phrase_responder.php diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index ba6e6cee4c..fa38b1b2ba 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -1,3 +1,4 @@ +// use an async function so page works without delays document.addEventListener("DOMContentLoaded", async function () { // Initialize the select options const select = document.getElementById('phrase_detail_data_empty'); @@ -51,7 +52,7 @@ function remove_loading() { async function fetch_data(command) { try { - const response = await fetch('phrase_responder.php', { + const response = await fetch('resources/phrase_responder.php', { method: 'POST', // or 'GET' depending on your requirement headers: { 'Content-Type': 'application/json' diff --git a/app/phrases/resources/phrase_responder.php b/app/phrases/resources/phrase_responder.php new file mode 100644 index 0000000000..9ac9b76d2e --- /dev/null +++ b/app/phrases/resources/phrase_responder.php @@ -0,0 +1,204 @@ + + * Portions created by the Initial Developer are Copyright (C) 2008-2024 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark J Crane + * Tim Fry + */ + +require_once dirname(__DIR__, 3) . '/resources/require.php'; + +//check permissions +if (permission_exists('phrase_add') || permission_exists('phrase_edit')) { + //access granted +} +else { + echo "access denied"; + exit; +} + +// Disable output buffering and compression +ini_set('output_buffering', 'off'); +ini_set('zlib.output_compression', 'off'); +ini_set('implicit_flush', 1); +ob_implicit_flush(1); + +// Set headers to ensure immediate response +header('Content-Type: text/plain'); +header('Cache-Control: no-cache'); +header('Content-Encoding: none'); + +function fetch_recordings(database $database): array { + global $domain_uuid; + // guard against corrupt data + if (empty($domain_uuid) || !is_uuid($domain_uuid)) { + throw new Exception('Domain is invalid'); + } + // always return an array + $return_value = []; + $sql = "select recording_uuid, recording_name, recording_filename, domain_uuid from v_recordings "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "order by recording_name asc "; + $parameters['domain_uuid'] = $domain_uuid; + $recordings = $database->select($sql, $parameters, 'all'); + if (!empty($recordings)) { + $return_value = $recordings; + } + return $return_value; +} + +function fetch_sound_files(settings $settings) { + $return_value = []; + //get the switch sound files + $file = new file($settings); + $sound_files = $file->sounds(); + + //try finding display_name in the switch sound files + if (!empty($sound_files)) { + $return_value = $sound_files; + } + return $return_value; +} + +function fetch_phrase_details(settings $settings, string $phrase_uuid): array { + global $domain_uuid; + // guard against corrupt data + if (empty($domain_uuid) || !is_uuid($domain_uuid)) { + throw new Exception('Domain is invalid'); + } + if (empty($phrase_uuid) || !is_uuid($phrase_uuid)) { + throw new Exception('Phrase UUID is invalid'); + } + + $database = $settings->database(); + // set the return value to be an empty array + $return_value = []; + // get the phrase details + if (!empty($phrase_uuid)) { + $sql = "select * from v_phrase_details "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and phrase_uuid = :phrase_uuid "; + $sql .= "order by phrase_detail_order asc "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['phrase_uuid'] = $phrase_uuid; + $phrase_details = $database->select($sql, $parameters, 'all'); + } + //existing details + if (!empty($phrase_details)) { + $recordings = fetch_recordings($database); + $sound_files = fetch_sound_files($settings); + //update the array to include the recording name for display in select box + foreach ($phrase_details as &$row) { + $row['display_name'] = ''; + $file = basename($row['phrase_detail_data']); + //get the display_name from recording name based on the file matched + foreach ($recordings as $key => $recordings_row) { + //match on filename first and then domain_uuid + if ($recordings_row['recording_filename'] === $file && $recordings_row['domain_uuid'] === $row['domain_uuid']) { + $row['display_name'] = $recordings[$key]['recording_name']; + break; + } + } + //check if display_name was not found in the recording names + if (strlen($row['display_name']) === 0) { + //try finding display_name in the switch sound files + if (!empty($sound_files)) { + //use optimized php function with strict comparison + $i = array_search($row['phrase_detail_data'], $sound_files, true); + //if found in the switch sound files + if ($i !== false) { + //set the display_name to the switch sound file name + $row['display_name'] = $sound_files[$i]; + } + } + } + } + $return_value = $phrase_details; + } + return $return_value; +} + +function fetch_domain_uuid(database $database): string { + $domain = $_SERVER['HTTP_HOST']; + $domain_uuid = ''; + $sql = 'select domain_uuid from v_domains where domain_name = :domain'; + $parameters = []; + $parameters['domain'] = $domain; + $result = $database->select($sql, $parameters, 'column'); + if (!empty($result)) { + $domain_uuid = $result; + } + return $domain_uuid; +} + +function send_message(string $json_data) { + echo $json_data . "\n"; + ob_flush(); + flush(); +} + +$config = config::load(); +$database = database::new(['config' => $config]); +$domain_uuid = fetch_domain_uuid($database); +$settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); + +// Set default response +$response = ['code' => 200, 'message' => '']; + +// Check if the request method is POST +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $message = ''; + // Get the raw POST data + $input = file_get_contents('php://input'); + + // Parse JSON data + $data = json_decode($input, true); // Decode JSON as associative array + + if (isset($data['request'])) { + try { + //check the data source requested + switch ($data['request']) { + case 'sound_files': + $message = fetch_sound_files($settings); + break; + case 'recordings': + $message = fetch_recordings($database); + break; + case 'phrase_details': + $phrase_uuid = $data['data']; + $message = fetch_phrase_details($settings, $phrase_uuid); + break; + } + } catch (Exception $e) { + $response['code'] = 500; + $message = $e->getMessage(); + } + } + //save the message + $response['message'] = $message; + //send the response + send_message(json_encode($response)); + exit(); +} + +exit(); From b95937842ea68a9cdc189843513a62a7fc1e6492 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Wed, 18 Dec 2024 14:18:49 -0400 Subject: [PATCH 29/31] use permission_exists instead of if_group --- app/phrases/phrase_edit.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index 5fb2aaf682..899dc8a2dc 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -517,14 +517,14 @@ if (count($_POST) > 0) { echo " \n"; echo " \n"; echo " \n"; echo " "; -// if (if_group("superadmin")) { +// if (permission_exists('phrase_execute')) { // echo " \n"; // } echo " "; From 91cdadcc63cfb64b74f283e2d2bb058f5e2b9cb3 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Thu, 19 Dec 2024 16:26:34 -0400 Subject: [PATCH 30/31] update file class to use settings when retrieving sound files --- resources/classes/file.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/resources/classes/file.php b/resources/classes/file.php index 26c3c8f9ec..41d7b3a5b4 100644 --- a/resources/classes/file.php +++ b/resources/classes/file.php @@ -2,8 +2,6 @@ /** * cache class provides an abstracted cache - * - * @method string glob */ class file { @@ -12,12 +10,17 @@ class file { */ public $recursive; public $files; + private $settings; /** * Called when the object is created + * @param settings $settings Settings object */ - public function __construct() { - //place holder + public function __construct($settings = null) { + if ($settings === null) { + $settings = new settings(); + } + $this->settings = $settings; } /** @@ -66,8 +69,8 @@ class file { if (!isset($voice)) { $voice = 'callie'; } //set the variables - if (!empty($_SESSION['switch']['sounds']['dir']) && file_exists($_SESSION['switch']['sounds']['dir'])) { - $dir = $_SESSION['switch']['sounds']['dir'].'/'.$language.'/'.$dialect.'/'.$voice; + if (!empty($this->settings->get('switch', 'sounds')) && file_exists($this->settings->get('switch', 'sounds'))) { + $dir = $this->settings->get('switch', 'sounds').'/'.$language.'/'.$dialect.'/'.$voice; $rate = '8000'; $files = $this->glob($dir.'/*/'.$rate, true); } @@ -93,5 +96,3 @@ class file { $files = $file->sounds(); print_r($files); */ - -?> From 1fe34d6899d429b785814a10e0588c25b226a0e2 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Fri, 17 Jan 2025 15:12:42 -0400 Subject: [PATCH 31/31] remove not needed if statement --- app/phrases/phrase_edit.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index 899dc8a2dc..878542bc0d 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -160,14 +160,10 @@ $language = new text; $text = $language->get(); //ensure we have a database object -if (!($database instanceof database)) { - $database = database::new(); -} +$database = database::new(); //ensure we have a settings object -if (!($settings instanceof settings)) { - $settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid, 'user_uuid' => $user_uuid]); -} +$settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid, 'user_uuid' => $user_uuid]); //add the defaults $phrase_name = '';