diff --git a/.github/emass.json b/.github/emass.json
new file mode 100644
index 000000000..6fce935cc
--- /dev/null
+++ b/.github/emass.json
@@ -0,0 +1,6 @@
+{
+ "systemID": 999,
+ "systemName": "LEAF",
+ "systemOwnerName": "Michael Gao",
+ "systemOwnerEmail": "michael.gao@va.gov"
+}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 000000000..f34dddd05
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,31 @@
+name: CodeQL
+'on':
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ schedule:
+ - cron: 1 21 * * 2
+ workflow_dispatch: null
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ concurrency: ${{ github.workflow }}-${{ matrix.language }}-${{ github.ref }}
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+ strategy:
+ fail-fast: false
+ matrix:
+ language:
+ - javascript
+ - java
+ steps:
+ - name: Run Code Scanning
+ uses: department-of-veterans-affairs/codeql-tools/codeql-analysis@main
+ with:
+ language: ${{ matrix.language }}
diff --git a/LEAF_Nexus/sources/Employee.php b/LEAF_Nexus/sources/Employee.php
index cb2979208..485e68c75 100644
--- a/LEAF_Nexus/sources/Employee.php
+++ b/LEAF_Nexus/sources/Employee.php
@@ -496,7 +496,7 @@ private function isActiveNationally(array $user): bool
*
* Created at: 6/9/2023, 2:31:07 PM (America/New_York)
*/
- private function getEmployeeByUserName(array $user_names, Db $db): array
+ public function getEmployeeByUserName(array $user_names, Db $db): array
{
$sql = "SELECT `empUID`, `userName`, `lastName`, `firstName`, `middleName`,
`phoneticLastName`, `phoneticFirstName`, `domain`, `deleted`,
@@ -562,7 +562,7 @@ private function getEmployeeDataByEmpUID(array $empUID, Db $db): array
private function updateEmployeeByUserName(string $user_name, array $national_user, Db $db): array
{
$vars = array(
- ':userName' => $user_name,
+ ':userName' => $national_user['user_name'],
':lastName' => $national_user['lastName'],
':firstName' => $national_user['firstName'],
':midInit' => $national_user['middleName'],
@@ -570,10 +570,12 @@ private function updateEmployeeByUserName(string $user_name, array $national_use
':phoneticLname' => $national_user['phoneticLastName'],
':domain' => $national_user['domain'],
':deleted' => $national_user['deleted'],
- ':lastUpdated' => $national_user['lastUpdated']
+ ':lastUpdated' => $national_user['lastUpdated'],
+ ':localUserName' => $user_name
);
$sql = "UPDATE `employee`
- SET `lastName` = :lastName,
+ SET `userName` = :userName,
+ `lastName` = :lastName,
`firstName` = :firstName,
`middleName` = :midInit,
`phoneticFirstName` = :phoneticFname,
@@ -581,7 +583,7 @@ private function updateEmployeeByUserName(string $user_name, array $national_use
`domain` = :domain,
`deleted` = :deleted,
`lastUpdated` = :lastUpdated
- WHERE `userName` = :userName";
+ WHERE `userName` = :localUserName";
$result = $db->prepared_query($sql, $vars);
$return_value = array(
@@ -676,8 +678,8 @@ public function addNew($firstName, $lastName, $middleName = '', $userName = '',
':phoLastName' => metaphone($this->sanitizeInput($lastName)),
':lastUpdated' => time(), );
$this->db->prepared_query('INSERT INTO employee (firstName, lastName, middleName, userName, phoneticFirstName, phoneticLastName, lastUpdated, new_empUUID)
- VALUES (:firstName, :lastName, :middleName, :userName, :phoFirstName, :phoLastName, :lastUpdated, UUID())
- ON DUPLICATE KEY UPDATE deleted=0', $vars);
+ VALUES (:firstName, :lastName, :middleName, :userName, :phoFirstName, :phoLastName, :lastUpdated, UUID())
+ ON DUPLICATE KEY UPDATE deleted=0', $vars);
$empUID = $this->lookupLogin($this->sanitizeInput($userName))[0]['empUID'];
@@ -736,8 +738,8 @@ public function importFromNational($userName)
':timestamp' => time(),
':author' => 'imported', );
$this->db->prepared_query("INSERT INTO {$this->dataTable} ({$this->dataTableUID}, indicatorID, data, timestamp, author)
- VALUES (:UID, :indicatorID, :data, :timestamp, :author)
- ON DUPLICATE KEY UPDATE data=:data, timestamp=:timestamp, author=:author", $vars);
+ VALUES (:UID, :indicatorID, :data, :timestamp, :author)
+ ON DUPLICATE KEY UPDATE data=:data, timestamp=:timestamp, author=:author", $vars);
}
// Email
@@ -747,8 +749,8 @@ public function importFromNational($userName)
':timestamp' => time(),
':author' => 'imported', );
$this->db->prepared_query("INSERT INTO {$this->dataTable} ({$this->dataTableUID}, indicatorID, data, timestamp, author)
- VALUES (:UID, :indicatorID, :data, :timestamp, :author)
- ON DUPLICATE KEY UPDATE data=:data, timestamp=:timestamp, author=:author", $vars);
+ VALUES (:UID, :indicatorID, :data, :timestamp, :author)
+ ON DUPLICATE KEY UPDATE data=:data, timestamp=:timestamp, author=:author", $vars);
if ($res[0]['data'][8]['data'] != '')
{
@@ -759,8 +761,8 @@ public function importFromNational($userName)
':timestamp' => time(),
':author' => 'imported', );
$this->db->prepared_query("INSERT INTO {$this->dataTable} ({$this->dataTableUID}, indicatorID, data, timestamp, author)
- VALUES (:UID, :indicatorID, :data, :timestamp, :author)
- ON DUPLICATE KEY UPDATE data=:data, timestamp=:timestamp, author=:author", $vars);
+ VALUES (:UID, :indicatorID, :data, :timestamp, :author)
+ ON DUPLICATE KEY UPDATE data=:data, timestamp=:timestamp, author=:author", $vars);
}
if ($res[0]['data'][23]['data'] != '')
@@ -772,8 +774,8 @@ public function importFromNational($userName)
':timestamp' => time(),
':author' => 'imported', );
$this->db->prepared_query("INSERT INTO {$this->dataTable} ({$this->dataTableUID}, indicatorID, data, timestamp, author)
- VALUES (:UID, :indicatorID, :data, :timestamp, :author)
- ON DUPLICATE KEY UPDATE data=:data, timestamp=:timestamp, author=:author", $vars);
+ VALUES (:UID, :indicatorID, :data, :timestamp, :author)
+ ON DUPLICATE KEY UPDATE data=:data, timestamp=:timestamp, author=:author", $vars);
}
return $empUID;
@@ -930,7 +932,7 @@ public function lookupEmpUID($empUID)
$sqlVars = array(':empUID' => $empUID);
$result = $this->db->prepared_query($strSQL, $sqlVars);
- $strSQL = "SELECT data AS email FROM {$this->dataTable} WHERE empUID=:empUID AND indicatorID = 6";
+ $strSQL = "SELECT data AS email FROM {$this->dataTable} WHERE empUID=:empUID AND indicatorID = 6";
$resEmail = $this->db->prepared_query($strSQL, $sqlVars);
if(isset($result[0]) && isset($resEmail[0])) {
@@ -1091,12 +1093,13 @@ public function lookupName($lastName, $firstName, $middleName = '')
public function lookupEmail($email)
{
- $sql = "SELECT * FROM {$this->dataTable}
- LEFT JOIN {$this->tableName} USING (empUID)
- WHERE indicatorID = 6
- AND data = :email
- AND deleted = 0
- {$this->limit}";
+ $sql = "SELECT *
+ FROM {$this->dataTable}
+ LEFT JOIN {$this->tableName} USING (empUID)
+ WHERE indicatorID = 6
+ AND data = :email
+ AND deleted = 0
+ {$this->limit}";
$vars = array(':email' => $email);
@@ -1106,11 +1109,11 @@ public function lookupEmail($email)
public function lookupPhone($phone)
{
$sql = "SELECT * FROM {$this->dataTable}
- LEFT JOIN {$this->tableName} USING (empUID)
- WHERE indicatorID = 5
- AND data LIKE :phone
- AND deleted = 0
- {$this->limit}";
+ LEFT JOIN {$this->tableName} USING (empUID)
+ WHERE indicatorID = 5
+ AND data LIKE :phone
+ AND deleted = 0
+ {$this->limit}";
$vars = array(':phone' => $this->parseWildcard('*' . $phone));
@@ -1124,8 +1127,8 @@ public function lookupByIndicatorID($indicatorID, $query)
);
$res = $this->db->prepared_query("SELECT * FROM {$this->dataTable}
- LEFT JOIN {$this->tableName} USING ({$this->dataTableUID})
- WHERE indicatorID = :indicatorID
+ LEFT JOIN {$this->tableName} USING ({$this->dataTableUID})
+ WHERE indicatorID = :indicatorID
AND data LIKE :query
AND deleted=0", $vars);
@@ -1144,9 +1147,9 @@ public function getBackups($empUID)
}
$vars = array(':empUID' => $empUID);
$res = $this->db->prepared_query('SELECT * FROM relation_employee_backup
- LEFT JOIN employee ON
- relation_employee_backup.backupEmpUID = employee.empUID
- WHERE relation_employee_backup.empUID=:empUID', $vars);
+ LEFT JOIN employee ON
+ relation_employee_backup.backupEmpUID = employee.empUID
+ WHERE relation_employee_backup.empUID=:empUID', $vars);
$this->cache["getBackups_{$empUID}"] = $res;
@@ -1169,8 +1172,8 @@ public function getBackupsFor($empUID)
}
$vars = array(':empUID' => $empUID);
$res = $this->db->prepared_query('SELECT * FROM relation_employee_backup
- LEFT JOIN employee USING (empUID)
- WHERE relation_employee_backup.backupEmpUID=:empUID', $vars);
+ LEFT JOIN employee USING (empUID)
+ WHERE relation_employee_backup.backupEmpUID=:empUID', $vars);
$this->cache["getBackupsFor_{$empUID}"] = $res;
@@ -1199,7 +1202,7 @@ public function setBackup($primaryEmpUID, $backupEmpUID)
':backupEmpUID' => $backupEmpUID,
':approver' => $this->login->getUserID(), );
$res = $this->db->prepared_query('INSERT INTO relation_employee_backup (empUID, backupEmpUID, approved, approverUserName)
- VALUES (:empUID, :backupEmpUID, 1, :approver)', $vars);
+ VALUES (:empUID, :backupEmpUID, 1, :approver)', $vars);
return true;
}
@@ -1225,7 +1228,7 @@ public function removeBackup($primaryEmpUID, $backupEmpUID)
$vars = array(':empUID' => $primaryEmpUID,
':backupEmpUID' => $backupEmpUID, );
$res = $this->db->prepared_query('DELETE FROM relation_employee_backup
- WHERE empUID=:empUID AND backupEmpUID=:backupEmpUID', $vars);
+ WHERE empUID=:empUID AND backupEmpUID=:backupEmpUID', $vars);
return true;
}
diff --git a/LEAF_Request_Portal/admin/ajaxJSON.php b/LEAF_Request_Portal/admin/ajaxJSON.php
index bb78884e5..53302f475 100644
--- a/LEAF_Request_Portal/admin/ajaxJSON.php
+++ b/LEAF_Request_Portal/admin/ajaxJSON.php
@@ -7,6 +7,10 @@
JSON index for legacy ajax endpoints
Date Created: August 13, 2009
+ This file has been deprecated, as of June 28, 2023 there is nothing in here
+ that is used in the general LEAF application, It is being left until we can
+ verify that it is not used in any custom setups.
+
*/
error_reporting(E_ERROR);
@@ -29,7 +33,7 @@
case 'mod_groups_getMembers':
$group = new Portal\Group($db, $login);
- echo json_encode($group->getMembers($_GET['groupID']));
+ echo $group->getMembers($_GET['groupID'])['data'];
break;
case 'directory_lookup':
diff --git a/LEAF_Request_Portal/admin/index.php b/LEAF_Request_Portal/admin/index.php
index 70469ca3b..49220feb3 100644
--- a/LEAF_Request_Portal/admin/index.php
+++ b/LEAF_Request_Portal/admin/index.php
@@ -197,6 +197,7 @@ function hasDevConsoleAccess($login, $oc_db)
$libsPath.'js/codemirror/lib/codemirror.css',
$libsPath.'js/codemirror/addon/display/fullscreen.css',
$libsPath.'js/choicesjs/choices.min.css',
+ $libsPath.'js/vue-dest/form_editor/LEAF_FormEditor.css',
$site_paths['orgchart_path'] . '/css/employeeSelector.css',
$site_paths['orgchart_path'] . '/css/groupSelector.css',
$site_paths['orgchart_path'] . '/css/positionSelector.css'
@@ -537,6 +538,37 @@ function hasDevConsoleAccess($login, $oc_db)
$main->assign('body', 'You require System Administrator level access to view this section.');
}
+ break;
+ case 'site_designer':
+ $t_form = new Smarty;
+ $t_form->left_delimiter = '';
+ $libsPath = '../../libs/';
+ $t_form->assign('CSRFToken', $_SESSION['CSRFToken']);
+ $t_form->assign('APIroot', '../api/');
+ $t_form->assign('libsPath', $libsPath);
+ $t_form->assign('orgchartPath', '../..'.$site_paths['orgchart_path']);
+ $t_form->assign('userID', Leaf\XSSHelpers::sanitizeHTML($login->getUserID()));
+
+ $main->assign('javascripts', array(
+ '../js/form.js', '../js/formGrid.js', '../js/formQuery.js', '../js/formSearch.js',
+ $libsPath.'js/jquery/chosen/chosen.jquery.min.js',
+ $libsPath.'js/choicesjs/choices.min.js',
+ $libsPath.'js/LEAF/XSSHelpers.js',
+ $libsPath.'js/jquery/jquery-ui.custom.min.js',
+ $libsPath.'js/jquery/trumbowyg/trumbowyg.min.js'
+ ));
+ $main->assign('stylesheets', array(
+ $libsPath.'js/jquery/chosen/chosen.min.css',
+ $libsPath.'js/choicesjs/choices.min.css',
+ $libsPath.'js/vue-dest/site_designer/LEAF_Designer.css'
+ ));
+
+ if ($login->checkGroup(1)) {
+ $main->assign('body', $t_form->fetch('site_designer_vue.tpl'));
+ } else {
+ $main->assign('body', 'You require System Administrator level access to view this section.');
+ }
break;
default:
// $main->assign('useDojo', false);
diff --git a/LEAF_Request_Portal/admin/templates/form_editor_vue.tpl b/LEAF_Request_Portal/admin/templates/form_editor_vue.tpl
index 78d0601d1..0579e8fe1 100644
--- a/LEAF_Request_Portal/admin/templates/form_editor_vue.tpl
+++ b/LEAF_Request_Portal/admin/templates/form_editor_vue.tpl
@@ -19,7 +19,7 @@
-
+
+
+
+
+
The page you are looking for does not exist or may have been moved. Please update your bookmarks.
+
\ No newline at end of file
diff --git a/LEAF_Request_Portal/admin/templates/site_elements/generic_OkDialog.tpl b/LEAF_Request_Portal/admin/templates/site_elements/generic_OkDialog.tpl
new file mode 100644
index 000000000..f6221b74f
--- /dev/null
+++ b/LEAF_Request_Portal/admin/templates/site_elements/generic_OkDialog.tpl
@@ -0,0 +1,6 @@
+
+
+
+
Ok
+
+
diff --git a/LEAF_Request_Portal/admin/templates/view_admin_menu.tpl b/LEAF_Request_Portal/admin/templates/view_admin_menu.tpl
index 1e23aeac3..6afad3878 100644
--- a/LEAF_Request_Portal/admin/templates/view_admin_menu.tpl
+++ b/LEAF_Request_Portal/admin/templates/view_admin_menu.tpl
@@ -1,35 +1,42 @@
+
Get Help
+
+
+
+ LEAF Support
+ Access VA LEAF Support Services
+
+
+
User Access
-
+
User Access Groups
Modify users and groups
-
+
Service Chiefs
Review service chiefs and set backups
-
+
Access Matrix
Configure group access to tasks
+
Site Configuration
-
+
Workflow Editor
Edit flowcharts for workflows
@@ -37,8 +44,7 @@
-
+
Form Editor
Create and Modify Forms
@@ -46,15 +52,14 @@
-
+
LEAF Library
Use a form made by the LEAF community
-
+
Site Settings
Edit site name, time zone, and other labels
@@ -62,126 +67,124 @@
-
+
Site Distribution
Deploy changes to subordinate sites
+
Admin Oversight Tools
-
+
Unresolved Requests
Examine potential delays
-
+
Timeline Explorer
Analyze timeline data
-
+
Report Builder
Create custom reports
+
LEAF Developer Console
-
+
Template Editor
Edit HTML Templates
-
+
Email Template Editor
Add and Edit Email Templates
-
+
LEAF Programmer
Advanced Reports and Custom Pages
-
+
File Manager
Upload custom images and documents
-
+
Search Database
Perform custom queries
-
+
Sync Services
Update Service listing from Org Chart
-
+
Update Database
Updates the system database, if available
+
Toolbox
-
+
Import Spreadsheet
Rows to requests, columns as fields
-
+
Mass Actions
Apply bulk actions to requests
-
+
New Account Updater
Update records with new account
+
-
+
Sitemap Editor
Edit portal Sitemap links
+
+
-
+
Combined Inbox Editor
Edit combined inbox
-
+
Grid Splitter
Export grid form data to Excel spreadsheet
diff --git a/LEAF_Request_Portal/api/controllers/GroupController.php b/LEAF_Request_Portal/api/controllers/GroupController.php
index 7171c12fb..19b12fb81 100644
--- a/LEAF_Request_Portal/api/controllers/GroupController.php
+++ b/LEAF_Request_Portal/api/controllers/GroupController.php
@@ -47,6 +47,11 @@ public function get($act)
});
$this->index['GET']->register('group/[digit]/members', function ($args) use ($group) {
+ $members = $group->getMembers($args[0]);
+ return $members['data'];
+ });
+
+ $this->index['GET']->register('group/[digit]/list_members', function ($args) use ($group) {
return $group->getMembers($args[0]);
});
diff --git a/LEAF_Request_Portal/api/controllers/SiteController.php b/LEAF_Request_Portal/api/controllers/SiteController.php
index 3c99d3379..3e60d1cb3 100644
--- a/LEAF_Request_Portal/api/controllers/SiteController.php
+++ b/LEAF_Request_Portal/api/controllers/SiteController.php
@@ -48,6 +48,18 @@ public function post($act)
$this->index['POST']->register('site/settings/sitemap_json', function ($args) use ($site) {
return $site->setSitemapJSON();
});
+ $this->index['POST']->register('site/settings/homepage_design_json', function ($args) use ($site) {
+ $list = $_POST['home_menu_list'] ?? [];
+ $direction = $_POST['menu_direction'] ?? 'v';
+ return $site->setHomeDesignJSON($list, $direction);
+ });
+ $this->index['POST']->register('site/settings/search_design_json', function ($args) use ($site) {
+ $list = $_POST['chosen_headers'] ?? [];
+ return $site->setSearchDesignJSON($list);
+ });
+ $this->index['POST']->register('site/settings/enable_homepage', function ($args) use ($site) {
+ return $site->enableNoCodeHomepage((int)$_POST['enabled']);
+ });
return $this->index['POST']->runControl($act['key'], $act['args']);
}
diff --git a/LEAF_Request_Portal/index.php b/LEAF_Request_Portal/index.php
index bf2e3224a..137e549ea 100644
--- a/LEAF_Request_Portal/index.php
+++ b/LEAF_Request_Portal/index.php
@@ -503,7 +503,7 @@ function customTemplate($tpl) {
exit();
default:
- $main->assign('javascripts', array('js/form.js', 'js/formGrid.js', 'js/formQuery.js', 'js/formSearch.js'));
+ $main->assign('javascripts', array('js/form.js', 'js/formGrid.js', 'js/formQuery.js', 'js/formSearch.js','../libs/js/LEAF/XSSHelpers.js',));
$main->assign('useLiteUI', true);
$o_login = $t_login->fetch('login.tpl');
@@ -521,14 +521,19 @@ function customTemplate($tpl) {
$t_form->assign('orgchartPath', $site_paths['orgchart_path']);
$t_form->assign('CSRFToken', $_SESSION['CSRFToken']);
- $t_form->assign('tpl_search', customTemplate('view_search.tpl'));
-
$inbox = new Portal\Inbox($db, $login);
//$t_form->assign('inbox_status', $inbox->getInboxStatus()); // see Inbox.php -> getInboxStatus()
$t_form->assign('inbox_status', 1);
-
- $main->assign('body', $t_form->fetch(customTemplate('view_homepage.tpl')));
+ if (isset($settings['homepage_enabled']) && $settings['homepage_enabled'] == 1) {
+ $t_form->assign('homeDesignJSON', json_encode($settings['homepage_design_json']));
+ $t_form->assign('searchDesignJSON', json_encode($settings['search_design_json']));
+ $t_form->assign('tpl_search', 'nocode_templates/view_search.tpl');
+ $main->assign('body', $t_form->fetch('./templates/nocode_templates/view_homepage.tpl'));
+ } else {
+ $t_form->assign('tpl_search', customTemplate('view_search.tpl'));
+ $main->assign('body', $t_form->fetch(customTemplate('view_homepage.tpl')));
+ }
if ($action != 'menu' && $action != '' && $action != 'dosubmit') {
$main->assign('status', 'The page you are looking for does not exist or may have been moved. Please update your bookmarks.');
diff --git a/LEAF_Request_Portal/js/formSearch.js b/LEAF_Request_Portal/js/formSearch.js
index 0fbf0b537..e96b77740 100644
--- a/LEAF_Request_Portal/js/formSearch.js
+++ b/LEAF_Request_Portal/js/formSearch.js
@@ -579,6 +579,7 @@ var LeafFormSearch = function (containerID) {
* @memberOf LeafFormSearch
*/
function renderWidget(widgetID, callback) {
+ let url;
switch ($("#" + prefixID + "widgetTerm_" + widgetID).val()) {
case "title":
$("#" + prefixID + "widgetCondition_" + widgetID).html(
@@ -612,9 +613,10 @@ var LeafFormSearch = function (containerID) {
IS NOT \
'
);
+ url = rootURL === '' ? './api/system/services' : rootURL + 'api/system/services';
$.ajax({
type: "GET",
- url: "./api/system/services",
+ url,
dataType: "json",
success: function (res) {
var services =
@@ -680,9 +682,10 @@ var LeafFormSearch = function (containerID) {
IS NOT \
'
);
+ url = rootURL === '' ? './api/workflow/categoriesUnabridged' : rootURL + 'api/workflow/categoriesUnabridged';
$.ajax({
type: "GET",
- url: "./api/workflow/categoriesUnabridged",
+ url,
dataType: "json",
success: function (res) {
var categories =
@@ -738,9 +741,10 @@ var LeafFormSearch = function (containerID) {
widgetID +
'" value="=" /> ='
);
+ url = rootURL === '' ? './api/workflow/dependencies' : rootURL + 'api/workflow/dependencies';
$.ajax({
type: "GET",
- url: "./api/workflow/dependencies",
+ url,
dataType: "json",
success: function (res) {
var dependencies =
@@ -796,9 +800,10 @@ var LeafFormSearch = function (containerID) {
IS NOT \
'
);
+ url = rootURL === '' ? './api/workflow/steps' : rootURL + 'api/workflow/steps';
$.ajax({
type: "GET",
- url: "./api/workflow/steps",
+ url,
dataType: "json",
success: function (res) {
var categories =
@@ -833,9 +838,10 @@ var LeafFormSearch = function (containerID) {
});
break;
case "data":
+ url = rootURL === '' ? './api/form/indicator/list' : rootURL + 'api/form/indicator/list';
$.ajax({
type: "GET",
- url: "./api/form/indicator/list",
+ url,
dataType: "json",
success: function (res) {
var indicators =
diff --git a/LEAF_Request_Portal/js/formSearchMultisite.js b/LEAF_Request_Portal/js/formSearchMultisite.js
new file mode 100644
index 000000000..797b9b74f
--- /dev/null
+++ b/LEAF_Request_Portal/js/formSearchMultisite.js
@@ -0,0 +1,1111 @@
+/************************
+ Form Search Widget for multiple sites
+ Search features are limited to common denominators across all LEAF sites.
+ */
+
+var LeafFormSearchMultisite = function (containerID) {
+ let containerID = containerID;
+ let prefixID = "LeafFormSearchMultisite" + Math.floor(Math.random() * 1000) + "_";
+ let localStorageNamespace = "LeafFormSearchMultisite" + getLocalStorageHash();
+ let orgchartPath = "";
+ let timer = 0;
+ let q = "";
+ let intervalID = null;
+ let currRequest = null;
+ let numResults = 0;
+ let searchFunc = null;
+ let leafFormQuery = new LeafFormQuery();
+ let widgetCounter = 0;
+ let rootURL = "";
+
+ // constants
+ const ALL_DATA_FIELDS = "0";
+ const ALL_OC_EMPLOYEE_DATA_FIELDS = "0.0";
+
+ function renderUI() {
+ $("#" + containerID).html(
+ '
\
+
\
+
\
+
\
+
\
+
Advanced Options \
+
\
+ Advanced Search Options \
+ Close advanced search \
+ Find items where...
\
+ \
+ And... \
+ Or... \
+ \
+ Apply Filters \
+ \
+
\
+
\
+
'
+ );
+
+ let searchOrigWidth = 0;
+ $("#" + prefixID + "advancedOptionsClose").on("click", function () {
+ localStorage.setItem(localStorageNamespace + ".search", "");
+ $("#" + prefixID + "searchtxt").val("");
+ search("");
+ $("#" + prefixID + "advancedOptionsClose").css("display", "none");
+ $("#" + prefixID + "advancedOptions").slideUp(function () {
+ $("#" + prefixID + "advancedSearchButton").fadeIn();
+ $("#" + prefixID + "searchtxt").css("display", "inline");
+ $("#" + prefixID + "searchtxt").animate(
+ { width: searchOrigWidth },
+ 400,
+ "swing"
+ );
+ $("#" + prefixID + "searchtxt").focus();
+ });
+ });
+ //added for keyboard navigation and accessibility to close advanced search options
+
+ $("#" + prefixID + "advancedOptionsClose").on("keydown", function (e) {
+ if (e.keyCode == 13) {
+ localStorage.setItem(localStorageNamespace + ".search", "");
+ $("#" + prefixID + "searchtxt").val("");
+ search("");
+ $("#" + prefixID + "advancedOptionsClose").css("display", "none");
+ $("#" + prefixID + "advancedOptions").slideUp(function () {
+ $("#" + prefixID + "advancedSearchButton").fadeIn();
+ $("#" + prefixID + "searchtxt").css("display", "inline");
+ $("#" + prefixID + "searchtxt").animate(
+ { width: searchOrigWidth },
+ 400,
+ "swing"
+ );
+ $("#" + prefixID + "searchtxt").focus();
+ });
+ }
+ });
+
+ $("#" + prefixID + "advancedSearchButton").on("click", function () {
+ searchOrigWidth = $("#" + prefixID + "searchtxt").width();
+ $("#" + prefixID + "advancedSearchButton").fadeOut();
+ $("#" + prefixID + "searchtxt").animate(
+ { width: "0px" },
+ 400,
+ "swing",
+ function () {
+ $("#" + prefixID + "searchtxt").css("display", "none");
+ $("#" + prefixID + "advancedOptions").slideDown(function () {
+ $("#" + prefixID + "advancedOptionsClose").fadeIn();
+ });
+ $("#" + prefixID + "advancedOptions").css("display", "inline");
+ chosenOptions();
+ renderPreviousAdvancedSearch();
+ $("#" + prefixID + "widgetMat_0").focus();
+ }
+ );
+ });
+
+ $("#" + prefixID + "advancedSearchApply").on("click", function () {
+ showBusy();
+ generateSearchQuery();
+ });
+ $("#" + prefixID + "addTerm").on("click", function () {
+ newSearchWidget("AND");
+ chosenOptions();
+ });
+ $("#" + prefixID + "orTerm").on("click", function () {
+ newSearchWidget("OR");
+ chosenOptions();
+ });
+
+ $("#" + prefixID + "searchtxt").on("keydown", function (e) {
+ showBusy();
+ timer = 0;
+ if (e.keyCode == 13) {
+ // enter key
+ search($("#" + prefixID + "searchtxt").val());
+ }
+ });
+
+ newSearchWidget();
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function init() {
+ renderUI();
+
+ intervalID = setInterval(function () {
+ inputLoop();
+ }, 200);
+ if (
+ !/Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
+ navigator.userAgent
+ ) &&
+ window.location.search !== ""
+ ) {
+ focus();
+ }
+ if (getLastSearch() == null) {
+ search("*");
+ } else {
+ let lastSearch = getLastSearch();
+
+ let isJSON = true;
+ let advSearch = {};
+ try {
+ advSearch = JSON.parse(lastSearch);
+ } catch (err) {
+ isJSON = false;
+ }
+
+ if (lastSearch.substr(0, 1) != "[") {
+ isJSON = false;
+ }
+
+ if (isJSON) {
+ $("#" + prefixID + "advancedSearchButton").click();
+ search(lastSearch);
+ } else {
+ if (lastSearch == "") {
+ search("*");
+ }
+ $("#" + prefixID + "searchtxt").val(lastSearch);
+ }
+ }
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ * prevQuery - optional JSON object
+ */
+ function renderPreviousAdvancedSearch(prevQuery) {
+ let isJSON = true;
+ let advSearch = {};
+ try {
+ if (prevQuery != undefined) {
+ advSearch = prevQuery;
+ } else {
+ advSearch = JSON.parse(getLastSearch());
+ }
+ } catch (err) {
+ isJSON = false;
+ }
+ if (isJSON && advSearch != null && widgetCounter <= advSearch.length) {
+ for (let i = 1; i < advSearch.length; i++) {
+ newSearchWidget(advSearch[i].gate);
+ firstChild();
+ }
+ for (let i = 0; i < advSearch.length; i++) {
+ $("#" + prefixID + "widgetTerm_" + i).val(advSearch[i].id);
+ $("#" + prefixID + "widgetTerm_" + i).trigger("chosen:updated");
+ if (
+ advSearch[i].indicatorID != undefined ||
+ advSearch[i].id == "serviceID" ||
+ advSearch[i].id == "categoryID" ||
+ advSearch[i].id == "stepID"
+ ) {
+ renderWidget(
+ i,
+ (function (widgetID, indicatorID, operator, match, gate) {
+ return function () {
+ $("#" + prefixID + "widgetIndicator_" + widgetID).val(
+ indicatorID
+ );
+ $("#" + prefixID + "widgetIndicator_" + widgetID).trigger(
+ "chosen:updated"
+ );
+ $("#" + prefixID + "widgetCod_" + widgetID).val(operator);
+ $("#" + prefixID + "widgetCod_" + widgetID).trigger("change");
+ $("#" + prefixID + "widgetCod_" + widgetID).trigger(
+ "chosen:updated"
+ );
+ $("#" + prefixID + "widgetMat_" + widgetID).val(
+ match.replace(/\*/g, "")
+ );
+ $("#" + prefixID + "widgetMat_" + widgetID).trigger(
+ "chosen:updated"
+ );
+ };
+ })(
+ i,
+ advSearch[i].indicatorID,
+ advSearch[i].operator,
+ advSearch[i].match,
+ advSearch[i].gate
+ )
+ );
+ } else {
+ renderWidget(i);
+ }
+ $("#" + prefixID + "widgetCod_" + i).val(advSearch[i].operator);
+ if (typeof advSearch[i].match == "string") {
+ $("#" + prefixID + "widgetMat_" + i).val(
+ advSearch[i].match.replace(/\*/g, "")
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ * From: http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
+ */
+ function getLocalStorageHash() {
+ let hash = 0,
+ i,
+ chr,
+ len;
+ if (document.URL.length == 0) return hash;
+ for (i = 0, len = document.URL.length; i < len; i++) {
+ chr = document.URL.charCodeAt(i);
+ hash = (hash << 5) - hash + chr;
+ hash |= 0; // Convert to 32bit integer
+ }
+ return hash;
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function setOrgchartPath(path) {
+ orgchartPath = path;
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function getLastSearch() {
+ return localStorage.getItem(localStorageNamespace + ".search");
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function setSearchFunc(func) {
+ searchFunc = func;
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function search(txt) {
+ if (txt != "*") {
+ localStorage.setItem(localStorageNamespace + ".search", txt);
+ }
+ return searchFunc(txt);
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function inputLoop() {
+ if ($("#" + prefixID + "searchtxt") == null) {
+ clearInterval(intervalID);
+ return false;
+ }
+ timer += timer > 5000 ? 0 : 200;
+ if (timer > 400) {
+ let txt = $("#" + prefixID + "searchtxt").val();
+
+ if (txt != "" && txt != q) {
+ q = txt;
+
+ if (
+ currRequest != null &&
+ currRequest.abort != undefined &&
+ typeof currRequest.abort == "function"
+ ) {
+ currRequest.abort();
+ }
+
+ currRequest = search(txt);
+ } else if (txt == "") {
+ if (txt != q) {
+ search("");
+ }
+ q = txt;
+ $("#" + this.prefixID + "_result").html("");
+ numResults = 0;
+ showNotBusy();
+ } else {
+ showNotBusy();
+ }
+ }
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function focus() {
+ $("#" + prefixID + "searchtxt").focus();
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function showBusy() {
+ $("#" + prefixID + "searchIcon").css("display", "none");
+ $("#" + prefixID + "searchIconBusy").css("display", "inline");
+ $(".status").text("Loading");
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function showNotBusy() {
+ $("#" + prefixID + "searchIcon").css("display", "inline");
+ $("#" + prefixID + "searchIconBusy").css("display", "none");
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function createEmployeeSelectorWidget(widgetID, type) {
+ if (type == undefined) {
+ type = "userName";
+ }
+ if (typeof employeeSelector == "undefined") {
+ $("head").append(
+ '
'
+ );
+ $.ajax({
+ type: "GET",
+ url: orgchartPath + "/js/employeeSelector.js",
+ dataType: "script",
+ success: function () {
+ let empSel = new employeeSelector(prefixID + "widgetEmp_" + widgetID);
+ empSel.apiPath = orgchartPath + "/api/";
+ empSel.rootPath = orgchartPath + "/";
+ empSel.outputStyle = "micro";
+
+ empSel.setSelectHandler(function () {
+ if (empSel.selectionData[empSel.selection] != undefined) {
+ selection =
+ type == "empUID"
+ ? empSel.selection
+ : empSel.selectionData[empSel.selection].userName;
+ $("#" + prefixID + "widgetMat_" + widgetID).val(selection);
+ //uses id. report builder/search will not take userName:
+ $("#" + empSel.prefixID + "input").val("#" + empSel.selection);
+ }
+ });
+ empSel.setResultHandler(function () {
+ if (empSel.selectionData[empSel.selection] != undefined) {
+ selection =
+ type == "empUID"
+ ? empSel.selection
+ : empSel.selectionData[empSel.selection].userName;
+ $("#" + prefixID + "widgetMat_" + widgetID).val(selection);
+ }
+ });
+ empSel.initialize();
+ },
+ });
+ } else {
+ let empSel = new employeeSelector(prefixID + "widgetEmp_" + widgetID);
+ empSel.apiPath = orgchartPath + "/api/";
+ empSel.rootPath = orgchartPath + "/";
+ empSel.outputStyle = "micro";
+
+ empSel.setSelectHandler(function () {
+ if (empSel.selectionData[empSel.selection] != undefined) {
+ selection =
+ type == "empUID"
+ ? empSel.selection
+ : empSel.selectionData[empSel.selection].userName;
+ $("#" + prefixID + "widgetMat_" + widgetID).val(selection);
+ $("#" + empSel.prefixID + "input").val("#" + empSel.selection);
+ }
+ });
+ empSel.setResultHandler(function () {
+ if (empSel.selectionData[empSel.selection] != undefined) {
+ selection =
+ type == "empUID"
+ ? empSel.selection
+ : empSel.selectionData[empSel.selection].userName;
+ $("#" + prefixID + "widgetMat_" + widgetID).val(selection);
+ }
+ });
+ empSel.initialize();
+ }
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function createPositionSelectorWidget(widgetID) {
+ if (typeof positionSelector == "undefined") {
+ $("head").append(
+ ' '
+ );
+ $.ajax({
+ type: "GET",
+ url: orgchartPath + "/js/positionSelector.js",
+ dataType: "script",
+ success: function () {
+ let posSel = new positionSelector(prefixID + "widgetPos_" + widgetID);
+ posSel.apiPath = orgchartPath + "/api/";
+ posSel.rootPath = orgchartPath + "/";
+
+ posSel.setSelectHandler(function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).val(posSel.selection);
+ $("#" + posSel.prefixID + "input").val("#" + posSel.selection);
+ });
+ posSel.setResultHandler(function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).val(posSel.selection);
+ });
+ posSel.initialize();
+ },
+ });
+ } else {
+ let posSel = new positionSelector(prefixID + "widgetPos_" + widgetID);
+ posSel.apiPath = orgchartPath + "/api/";
+ posSel.rootPath = orgchartPath + "/";
+
+ posSel.setSelectHandler(function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).val(posSel.selection);
+ $("#" + posSel.prefixID + "input").val("#" + posSel.selection);
+ });
+ posSel.setResultHandler(function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).val(posSel.selection);
+ });
+ posSel.initialize();
+ }
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function createGroupSelectorWidget(widgetID) {
+ if (typeof groupSelector == "undefined") {
+ $("head").append(
+ ' '
+ );
+ $.ajax({
+ type: "GET",
+ url: orgchartPath + "/js/groupSelector.js",
+ dataType: "script",
+ success: function () {
+ let grpSel = new groupSelector(prefixID + "widgetGrp_" + widgetID);
+ grpSel.apiPath = orgchartPath + "/api/";
+ grpSel.rootPath = orgchartPath + "/";
+
+ grpSel.setSelectHandler(function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).val(grpSel.selection);
+ $("#" + grpSel.prefixID + "input").val("group#" + grpSel.selection);
+ });
+ grpSel.setResultHandler(function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).val(grpSel.selection);
+ });
+ grpSel.initialize();
+ },
+ });
+ } else {
+ let grpSel = new groupSelector(prefixID + "widgetGrp_" + widgetID);
+ grpSel.apiPath = orgchartPath + "/api/";
+ grpSel.rootPath = orgchartPath + "/";
+
+ grpSel.setSelectHandler(function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).val(grpSel.selection);
+ $("#" + grpSel.prefixID + "input").val("group#" + grpSel.selection);
+ });
+ grpSel.setResultHandler(function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).val(grpSel.selection);
+ });
+ grpSel.initialize();
+ }
+ }
+
+ /**
+ * Render the query match condition's input type for dropdown and radio fields
+ * @param widgetID
+ * @param options html section matching the widgetID
+ * @memberOf LeafFormSearchMultisite
+ */
+ function renderSingleSelectInputType(widgetID, options) {
+ switch ($("#" + prefixID + "widgetCod_" + widgetID).val()) {
+ case "LIKE":
+ case "NOT LIKE":
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(
+ ' '
+ );
+ break;
+ default:
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(options);
+ chosenOptions();
+ break;
+ }
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function renderWidget(widgetID, callback) {
+ switch ($("#" + prefixID + "widgetTerm_" + widgetID).val()) {
+ case "title":
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ '\
+ CONTAINS \
+ DOES NOT CONTAIN \
+ = \
+ != \
+ '
+ );
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(
+ ' '
+ );
+ break;
+ case "serviceID":
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ '\
+ IS \
+ IS NOT \
+ '
+ );
+ $.ajax({
+ type: "GET",
+ url: "./api/system/services",
+ dataType: "json",
+ success: function (res) {
+ let services =
+ '';
+ for (let i in res) {
+ services +=
+ '' +
+ res[i].groupTitle +
+ " ";
+ }
+ services += " ";
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(services);
+ chosenOptions();
+ if (callback != undefined) {
+ callback();
+ }
+ },
+ });
+ break;
+ case "date":
+ case "dateInitiated":
+ case "dateSubmitted":
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ '\
+ ON \
+ ON AND AFTER \
+ ON AND BEFORE \
+ '
+ );
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(
+ ' '
+ );
+ if (!jQuery.ui) {
+ $.getScript("../libs/js/jquery/jquery-ui.custom.min.js", function () {
+ $("#" + prefixID + "widgetMat_" + widgetID).datepicker();
+ });
+ } else {
+ $("#" + prefixID + "widgetMat_" + widgetID).datepicker();
+ }
+ break;
+ case "categoryID":
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ '\
+ IS \
+ IS NOT \
+ '
+ );
+ $.ajax({
+ type: "GET",
+ url: "./api/workflow/categoriesUnabridged",
+ dataType: "json",
+ success: function (res) {
+ let categories =
+ '';
+ for (let i in res) {
+ categories +=
+ '' +
+ res[i].categoryName +
+ " ";
+ }
+ categories += " ";
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(categories);
+ chosenOptions();
+ if (callback != undefined) {
+ callback();
+ }
+ },
+ cache: false,
+ });
+ break;
+ case "userID":
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ ' IS'
+ );
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(
+ '
'
+ );
+ createEmployeeSelectorWidget(widgetID);
+ break;
+ case "dependencyID":
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ ' ='
+ );
+ $.ajax({
+ type: "GET",
+ url: "./api/workflow/dependencies",
+ dataType: "json",
+ success: function (res) {
+ let dependencies =
+ '';
+ for (let i in res) {
+ dependencies +=
+ '' +
+ res[i].description +
+ " ";
+ }
+ dependencies += " ";
+ $("#" + prefixID + "widgetTerm_" + widgetID).after(dependencies);
+
+ let options =
+ '';
+ options += 'Reviewed ';
+ options += 'Not Reviewed ';
+ options +=
+ 'Returned to a previous step ';
+ options += " ";
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(options);
+
+ chosenOptions();
+ $("#" + prefixID + "widgetTerm_" + widgetID + "_chosen").css(
+ "display",
+ "none"
+ );
+ if (callback != undefined) {
+ callback();
+ }
+ },
+ cache: false,
+ });
+ break;
+ case "stepID":
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ '\
+ IS \
+ IS NOT \
+ '
+ );
+ let categories =
+ '';
+ categories += 'Submitted ';
+ categories += 'Cancelled ';
+ categories += 'Resolved ';
+ categories +=
+ 'Actionable by me ';
+
+ categories += " ";
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(categories);
+ chosenOptions();
+ if (callback != undefined) {
+ callback();
+ }
+ break;
+ case "data":
+ let indicators =
+ '';
+ indicators +=
+ 'Any standard data field ';
+ indicators +=
+ 'Any Org. Chart employee field ';
+
+ indicators += " ";
+ $("#" + prefixID + "widgetTerm_" + widgetID).after(indicators);
+ chosenOptions();
+ $("#" + prefixID + "widgetIndicator_" + widgetID).css(
+ "float",
+ "right"
+ );
+ $("#" + prefixID + "widgetIndicator_" + widgetID).on(
+ "change chosen:updated",
+ function () {
+ iID = $("#" + prefixID + "widgetIndicator_" + widgetID).val();
+
+ // set default conditions for "any data field"
+ if (iID == ALL_DATA_FIELDS) {
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ '\
+ CONTAINS \
+ DOES NOT CONTAIN \
+ = \
+ != \
+ '
+ );
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(
+ ' '
+ );
+ chosenOptions();
+ } else if (iID == ALL_OC_EMPLOYEE_DATA_FIELDS) {
+ // set conditions for orgchart employee fields
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ ' IS'
+ );
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(
+ '
'
+ );
+ createEmployeeSelectorWidget(widgetID, "empUID");
+ }
+ }
+ );
+ $("#" + prefixID + "widgetTerm_" + widgetID + "_chosen").css(
+ "display",
+ "none"
+ );
+ if (callback != undefined) {
+ callback();
+ }
+ break;
+ default:
+ $("#" + prefixID + "widgetCondition_" + widgetID).html(
+ '\
+ = \
+ > \
+ >= \
+ < \
+ <= \
+ CONTAINS \
+ '
+ );
+ $("#" + prefixID + "widgetMatch_" + widgetID).html(
+ ' '
+ );
+ break;
+ }
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function newSearchWidget(gate) {
+ // @TODO IE Fix (No overloading)
+ if (gate === undefined) {
+ gate = "AND";
+ }
+ let widget =
+ '\
+ \
+ ' +
+ gate +
+ ' \
+ \
+ Title \
+ Date Submitted \
+ Initiator \
+ Current Status \
+ Data Field \
+ \
+ \
+ \
+ ';
+ $(widget).appendTo("#" + prefixID + "searchTerms");
+ renderWidget(widgetCounter);
+ firstChild();
+
+ $("#" + prefixID + "widgetTerm_" + widgetCounter).on(
+ "change",
+ "",
+ widgetCounter,
+ function (e) {
+ renderWidget(e.data);
+ chosenOptions();
+ }
+ );
+ $("#" + prefixID + "widgetRemove_" + widgetCounter).on(
+ "click",
+ "",
+ widgetCounter,
+ function (e) {
+ $("#" + prefixID + "widget_" + e.data).remove();
+ $("#" + prefixID + "widgetOp_" + e.data).remove();
+ firstChild();
+ }
+ );
+
+ widgetCounter++;
+ }
+
+ /**
+ * @memberOf LeafFormSearchMultisite
+ */
+ function generateSearchQuery() {
+ leafFormQuery.clearTerms();
+ for (let i = 0; i < widgetCounter; i++) {
+ if ($("#" + prefixID + "widgetTerm_" + i).val() != undefined) {
+ term = $("#" + prefixID + "widgetTerm_" + i).val();
+ if (term != "data" && term != "dependencyID") {
+ id = $("#" + prefixID + "widgetTerm_" + i).val();
+ cod = $("#" + prefixID + "widgetCod_" + i).val();
+ match = $("#" + prefixID + "widgetMat_" + i).val();
+ gate = document.getElementById(
+ prefixID + "widgetGate_" + i
+ ).innerHTML; // Assign Operator
+ if (cod == "LIKE") {
+ match = "*" + match + "*";
+ }
+ leafFormQuery.addTerm(id, cod, match, gate);
+ } else {
+ id = $("#" + prefixID + "widgetTerm_" + i).val();
+ indicatorID = $("#" + prefixID + "widgetIndicator_" + i).val();
+ cod = $("#" + prefixID + "widgetCod_" + i).val();
+ match = $("#" + prefixID + "widgetMat_" + i).val();
+ gate = document.getElementById(
+ prefixID + "widgetGate_" + i
+ ).innerHTML; // Assign Operator
+ if (cod == "LIKE") {
+ match = "*" + match + "*";
+ }
+ leafFormQuery.addDataTerm(id, indicatorID, cod, match, gate);
+ }
+ }
+ }
+ if (leafFormQuery.getQuery().terms.length > 0) {
+ $("#" + prefixID + "searchtxt").val(
+ JSON.stringify(leafFormQuery.getQuery().terms)
+ );
+ } else {
+ $("#" + prefixID + "searchtxt").val("*");
+ }
+ }
+
+ /**
+ * Purpose: Update Chosen Options for Fields
+ * @memberOf LeafFormSearchMultisite
+ */
+ function chosenOptions() {
+ $(".chosen").chosen({
+ disable_search_threshold: 6,
+ width: "100%",
+ }); // needs to be here due to chosen issue with display:none
+ }
+
+ /**
+ * Purpose: Refresh First Child in Search
+ * @memberOf LeafFormSearchMultisite
+ */
+ function firstChild() {
+ if (
+ document.getElementById(prefixID + "searchTerms").children[0] != undefined
+ ) {
+ document.getElementById(
+ prefixID + "searchTerms"
+ ).children[0].children[1].style.display = "none"; // Hide First Operator
+ document
+ .getElementById(prefixID + "searchTerms")
+ .children[0].children[2].setAttribute("colspan", "2"); // Resize col
+ document.getElementById(
+ prefixID + "searchTerms"
+ ).children[0].children[2].style.width = "175px";
+ document.getElementById(
+ prefixID + "searchTerms"
+ ).children[0].children[3].style.width = "130px";
+ }
+ }
+
+ return {
+ init: init,
+ renderUI: renderUI,
+ setOrgchartPath: setOrgchartPath,
+ focus: focus,
+ getPrefixID: function () {
+ return prefixID;
+ },
+ getSearchInput: function () {
+ return $("#" + prefixID + "searchtxt").val();
+ },
+ getResultContainerID: function () {
+ return prefixID + "_result";
+ },
+ getLastSearch: getLastSearch,
+ generateQuery: generateSearchQuery,
+ getLeafFormQuery: function () {
+ return leafFormQuery;
+ },
+ renderPreviousAdvancedSearch: renderPreviousAdvancedSearch,
+ setSearchFunc: setSearchFunc,
+ search: search,
+ showBusy: showBusy,
+ showNotBusy: showNotBusy,
+ setRootURL: function (url) {
+ rootURL = url;
+ },
+ };
+};
diff --git a/LEAF_Request_Portal/js/vue_conditions_editor/LEAF_conditions_editor.js b/LEAF_Request_Portal/js/vue_conditions_editor/LEAF_conditions_editor.js
index f1b302b83..8afccb929 100644
--- a/LEAF_Request_Portal/js/vue_conditions_editor/LEAF_conditions_editor.js
+++ b/LEAF_Request_Portal/js/vue_conditions_editor/LEAF_conditions_editor.js
@@ -707,9 +707,8 @@ const ConditionsEditor = Vue.createApp({
* @returns {Array} of condition objects
*/
savedConditions() {
- return this.childIndicator.conditions
- ? JSON.parse(this.childIndicator.conditions)
- : [];
+ return typeof this.childIndicator.conditions === 'string' && this.childIndicator.conditions[0] === '[' ?
+ JSON.parse(this.childIndicator.conditions) : [];
},
/**
* @returns {Object} with arrays of conditions by type
diff --git a/LEAF_Request_Portal/sources/Group.php b/LEAF_Request_Portal/sources/Group.php
index fbecc36f4..cf4a0b150 100644
--- a/LEAF_Request_Portal/sources/Group.php
+++ b/LEAF_Request_Portal/sources/Group.php
@@ -197,39 +197,49 @@ public function cleanDb(): void
*/
public function getMembers($groupID, bool $searchDeleted = false): array|string
{
- if (!is_numeric($groupID))
- {
- $return_value = "invalid group ID";
+ if (!is_numeric($groupID)) {
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'invalid group ID'
+ )
+ );
} else {
- $sql_vars = array(':groupID' => $groupID);
- $res = $this->db->prepared_query('SELECT * FROM users WHERE groupID=:groupID ORDER BY userID', $sql_vars);
+ $vars = array(':groupID' => $groupID);
+ $sql = 'SELECT `userID`, `groupID`, `backupID`, `primary_admin`,
+ `locallyManaged`, `active`
+ FROM `users`
+ WHERE `groupID` = :groupID
+ ORDER BY `userID`';
+
+ $res = $this->db->pdo_select_query($sql, $vars);
$members = array();
- if (count($res) > 0)
- {
+ if ($res['status']['code'] == 2) {
$dir = new VAMC_Directory();
- foreach ($res as $member)
- {
+
+ foreach ($res['data'] as $member) {
$dirRes = $dir->lookupLogin($member['userID'], false, true, $searchDeleted);
- if (isset($dirRes[0]))
- {
+ if (isset($dirRes[0])) {
$dirRes[0]['regionallyManaged'] = false;
- foreach ($dirRes[0]['groups'] as $group)
- {
- if ($groupID == $group['groupID']){
+
+ foreach ($dirRes[0]['groups'] as $group) {
+ if ($groupID == $group['groupID']) {
$dirRes[0]['regionallyManaged'] = true;
}
}
- if($groupID == 1)
- {
+
+ if ($groupID == 1) {
$dirRes[0]['primary_admin'] = $member['primary_admin'];
}
- if($member['locallyManaged'] == 1) {
+
+ if ($member['locallyManaged'] == 1) {
$dirRes[0]['backupID'] = null;
} else {
$dirRes[0]['backupID'] = $member['backupID'];
}
+
$dirRes[0]['locallyManaged'] = $member['locallyManaged'];
$dirRes[0]['active'] = $member['active'];
@@ -241,7 +251,13 @@ public function getMembers($groupID, bool $searchDeleted = false): array|string
$col = array_column( $members, "lastName" );
array_multisort( $col, SORT_ASC, $members );
- $return_value = $members;
+ $return_value = array (
+ 'status' => array (
+ 'code' => 2,
+ 'message' => ''
+ ),
+ 'data' => $members
+ );
}
return $return_value;
@@ -448,7 +464,7 @@ public function getGroupsAndMembers(bool $searchDeleted = false): array
{
if ($group['groupID'] > 0)
{
- $group['members'] = $this->getMembers($group['groupID'], $searchDeleted);
+ $group['members'] = $this->getMembers($group['groupID'], $searchDeleted)['data'];
$list[] = $group;
}
}
diff --git a/LEAF_Request_Portal/sources/Site.php b/LEAF_Request_Portal/sources/Site.php
index fcd6a026a..052c8854c 100644
--- a/LEAF_Request_Portal/sources/Site.php
+++ b/LEAF_Request_Portal/sources/Site.php
@@ -43,6 +43,75 @@ public function setSitemapJSON()
return 1;
}
+ public function setHomeDesignJSON(array $menuItems = [], string $direction = 'v'): array {
+ $status = array();
+ if (!$this->login->checkGroup(1)) {
+ $status['code'] = 0;
+ $status['message'] = "Admin access required";
+ return $status;
+ }
+ foreach ($menuItems as $i => $item) {
+ $menuItems[$i]['title'] = \Leaf\XSSHelpers::sanitizer($item['title']);
+ $menuItems[$i]['subtitle'] = \Leaf\XSSHelpers::sanitizer($item['subtitle']);
+ $menuItems[$i]['link'] = \Leaf\XSSHelpers::scrubNewLinesFromURL(\Leaf\XSSHelpers::xscrub($item['link']));
+ $menuItems[$i]['icon'] = \Leaf\XSSHelpers::scrubFilename($item['icon']);
+ }
+ $home_design_data = array();
+ $home_design_data['menuCards'] = $menuItems;
+ $home_design_data['direction'] = $direction === 'v' ? 'v' : 'h';
+ $homepage_design_json = json_encode($home_design_data);
+
+ $strSQL = 'INSERT INTO settings (setting, `data`)
+ VALUES ("homepage_design_json", :homepage_design_json)
+ ON DUPLICATE KEY UPDATE `data`=:homepage_design_json';
+ $vars = array(':homepage_design_json' => $homepage_design_json);
+
+ $this->db->prepared_query($strSQL, $vars);
+ $status['code'] = 1;
+ $status['message'] = "success";
+ return $status;
+ }
+ public function setSearchDesignJSON(array $chosenHeaders = []): array {
+ $status = array();
+ if (!$this->login->checkGroup(1)) {
+ $status['code'] = 0;
+ $status['message'] = "Admin access required";
+ return $status;
+ }
+ $search_design_data = array();
+ $search_design_data['chosenHeaders'] = \Leaf\XSSHelpers::scrubObjectOrArray($chosenHeaders);
+ $search_design_json = json_encode($search_design_data);
+
+ $strSQL = 'INSERT INTO settings (setting, `data`)
+ VALUES ("search_design_json", :search_design_json)
+ ON DUPLICATE KEY UPDATE `data`=:search_design_json';
+ $vars = array(':search_design_json' => $search_design_json);
+
+ $this->db->prepared_query($strSQL, $vars);
+
+ $status['code'] = 1;
+ $status['message'] = "";
+ return $status;
+ }
+ public function enableNoCodeHomepage(int $isEnabled = 0): array {
+ $status = array();
+ if (!$this->login->checkGroup(1)) {
+ $status['code'] = 0;
+ $status['message'] = "Admin access required";
+ return $status;
+ }
+ $homepage_enabled = $isEnabled === 1 ? '1' : '0';
+ $strSQL = 'INSERT INTO settings (setting, `data`)
+ VALUES ("homepage_enabled", :homepage_enabled)
+ ON DUPLICATE KEY UPDATE `data`=:homepage_enabled';
+ $vars = array(':homepage_enabled' => $homepage_enabled);
+
+ $this->db->prepared_query($strSQL, $vars);
+
+ $status['code'] = 1;
+ $status['message'] = "success";
+ return $status;
+ }
public function getSitemapJSON()
{
$settings = $this->db->prepared_query('SELECT data from settings WHERE setting="sitemap_json"', null);
diff --git a/LEAF_Request_Portal/sources/System.php b/LEAF_Request_Portal/sources/System.php
index e12e272b7..75cd8e26e 100644
--- a/LEAF_Request_Portal/sources/System.php
+++ b/LEAF_Request_Portal/sources/System.php
@@ -146,100 +146,405 @@ public function updateService($serviceID)
return "groupID: {$serviceID} updated";
}
- public function updateGroup($groupID)
+ /**
+ * @param int $groupID
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:24:51 PM (America/New_York)
+ */
+ public function updateGroup(int $groupID): array
{
- if (!is_numeric($groupID))
- {
- return 'Invalid Group';
+ if (!is_numeric($groupID)) {
+ $return_value = array(
+ 'status' => array(
+ 'code' => 4,
+ 'message' => 'Invalid Group Id.'
+ )
+ );
+ } elseif ($groupID == 1) {
+ $return_value = array(
+ 'status' => array(
+ 'code' => 4,
+ 'message' => 'You are not authorized to update admin groups.'
+ )
+ );
+ } else {
+ $oc_db = new \Leaf\Db(\DIRECTORY_HOST, \DIRECTORY_USER, \DIRECTORY_PASS, \ORGCHART_DB);
+ $group = new \Orgchart\Group($oc_db, $this->login);
+ $position = new \Orgchart\Position($oc_db, $this->login);
+ $employee = new \Orgchart\Employee($oc_db, $this->login);
+ $tag = new \Orgchart\Tag($oc_db, $this->login);
+
+ // clear out old data first
+ $delete_groups = $this->clearGroups($groupID);
+
+ if ($delete_groups['status']['code'] == 2) {
+ // find quadrad/ELT tag name
+ $upperLevelTag = $tag->getParent('service');
+ $isQuadrad = false;
+
+ if (array_search($upperLevelTag, $group->getAllTags($groupID)) !== false) {
+ $isQuadrad = true;
+ }
+
+ $resGroup = $group->getGroup($groupID)[0];
+
+ $insert_group = $this->insertGroup($groupID, $isQuadrad, $resGroup['groupTitle']);
+
+ if ($insert_group['status']['code'] == 2) {
+ $delete_user_backups = $this->deleteUserBackups($groupID);
+
+ if ($delete_user_backups['status']['code'] == 2) {
+ $resEmp = array();
+ $positions = $group->listGroupPositions($groupID);
+ $resEmp = $group->listGroupEmployees($groupID);
+
+ if (!empty($positions) && is_array($positions)){
+ foreach ($positions as $tposition) {
+ $resEmp = array_merge($resEmp, $position->getEmployees($tposition['positionID']));
+ }
+ }
+
+ if (!empty($resEmp) && is_array($resEmp)) {
+ foreach ($resEmp as $emp) {
+ $insert_user = $this->insertUser($groupID, $emp);
+
+ if ($insert_user['status']['code'] == 2) {
+ // nothing to be done, all is good
+ } else {
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'Action failed to add users.'
+ )
+ );
+ break;
+ }
+ }
+ }
+
+ $backups = $this->addBackups($groupID);
+
+ if ($backups['status']['code'] == 2) {
+ $privs = $this->updateCatPrivs($groupID);
+
+ if ($privs['status']['code'] == 2) {
+ // at this point everything updated as expected
+ $return_value = array (
+ 'status' => array (
+ 'code' => 2,
+ 'message' => 'Everything updated as expected.'
+ )
+ );
+ } else {
+ // something happened updating category privs
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'There was an error updating category privs.'
+ )
+ );
+ }
+ } else {
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'There was an arror adding backups.'
+ )
+ );
+ }
+ } else {
+ // something happened deleting user backups
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'There was an error deleting user backups.'
+ )
+ );
+ }
+ } else {
+ // something happened with the inserting of groups
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'There was an error inserting groups.'
+ )
+ );
+ }
+ } else {
+ // something happened with the delete groups
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'There was an error when deleting groups.'
+ )
+ );
+ }
}
- if ($groupID == 1)
- {
- return 'Cannot update admin group';
+
+ return $return_value;
+ }
+
+ /**
+ * @param int $groupID
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:25:07 PM (America/New_York)
+ */
+ private function updateCatPrivs(int $groupID): array
+ {
+ $cat_privs = $this->getCatPrivs($groupID);
+
+ if ($cat_privs['status']['code'] == 2) {
+ $return_value = $this->deleteCatPrivs($groupID);
+ } else {
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'Action failed to add backups.'
+ )
+ );
}
- // clear out old data first
+ return $return_value;
+ }
+
+ /**
+ * @param int $groupID
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:25:25 PM (America/New_York)
+ */
+ private function deleteCatPrivs(int $groupID): array
+ {
$vars = array(':groupID' => $groupID);
- //$this->db->prepared_query('DELETE FROM users WHERE groupID=:groupID AND backupID IS NULL', $vars);
- $this->db->prepared_query('DELETE FROM `groups` WHERE groupID=:groupID', $vars);
+ $sql = 'DELETE
+ FROM `category_privs`
+ WHERE `groupID` = :groupID';
- $oc_db = new \Leaf\Db(\DIRECTORY_HOST, \DIRECTORY_USER, \DIRECTORY_PASS, \ORGCHART_DB);
- $group = new \Orgchart\Group($oc_db, $this->login);
- $position = new \Orgchart\Position($oc_db, $this->login);
- $employee = new \Orgchart\Employee($oc_db, $this->login);
- $tag = new \Orgchart\Tag($oc_db, $this->login);
+ $return_value = $this->db->pdo_delete_query($sql, $vars);
- // find quadrad/ELT tag name
- $upperLevelTag = $tag->getParent('service');
- $isQuadrad = false;
- if (array_search($upperLevelTag, $group->getAllTags($groupID)) !== false)
- {
- $isQuadrad = true;
- }
+ return $return_value;
+ }
- $resGroup = $group->getGroup($groupID)[0];
- $vars = array(':groupID' => $groupID,
- ':parentGroupID' => ($isQuadrad == true ? -1 : null),
- ':name' => $resGroup['groupTitle'],
- ':groupDescription' => '', );
+ /**
+ * @param int $groupID
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:25:38 PM (America/New_York)
+ */
+ private function getCatPrivs(int $groupID): array
+ {
+ $vars = array(':groupID' => $groupID);
+ $sql = 'SELECT `categoryID`
+ FROM `category_privs`
+ LEFT JOIN `groups` USING (`groupID`)
+ WHERE `category_privs`.`groupID` = :groupID
+ AND `groups`.`groupID` IS NULL';
- $this->db->prepared_query('INSERT INTO `groups` (groupID, parentGroupID, name, groupDescription)
- VALUES (:groupID, :parentGroupID, :name, :groupDescription)', $vars);
+ $return_value = $this->db->pdo_select_query($sql, $vars);
- // build list of member employees
- $resEmp = array();
- $positions = $group->listGroupPositions($groupID);
- $resEmp = $group->listGroupEmployees($groupID);
- foreach ($positions as $tposition)
- {
- $resEmp = array_merge($resEmp, $position->getEmployees($tposition['positionID']));
- }
+ return $return_value;
+ }
- // clear backups in case of updates
- $vars = array(':groupID' => $groupID);
- $this->db->prepared_query('DELETE FROM users WHERE backupID IS NOT NULL AND groupID=:groupID', $vars);
- foreach ($resEmp as $emp)
- {
- if ($emp['userName'] != '')
- {
- $vars = array(':userID' => $emp['userName'],
- ':groupID' => $groupID, );
+ /**
+ * @param int $groupID
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:25:53 PM (America/New_York)
+ */
+ private function addBackups(int $groupID): array
+ {
+ $oc_db = new \Leaf\Db(\DIRECTORY_HOST, \DIRECTORY_USER, \DIRECTORY_PASS, \ORGCHART_DB);
+ $employee = new \Orgchart\Employee($oc_db, $this->login);
- $this->db->prepared_query('INSERT INTO users (userID, groupID, active)
- VALUES (:userID, :groupID, 0)
- ON DUPLICATE KEY UPDATE userID=:userID, groupID=:groupID', $vars);
+ // get all users for this group
+ $group_users = $this->getGroupUsers($groupID);
- // include the backups of employees
- $res = $this->db->prepared_query('SELECT * FROM users WHERE userID=:userID AND groupID=:groupID', $vars);
- if ($res[0]['active'] == 1) {
- $backups = $employee->getBackups($emp['empUID']);
- foreach ($backups as $backup) {
- $vars = array(':userID' => $backup['userName'],
- ':groupID' => $groupID,
- ':backupID' => $emp['userName'],);
+ // loop through group_users to add backups
+ if ($group_users['status']['code'] == 2){
+ $userNames = array();
- // Add backupID check for updates
- $this->db->prepared_query('INSERT INTO users (userID, groupID, backupID)
- VALUES (:userID, :groupID, :backupID)
- ON DUPLICATE KEY UPDATE userID=:userID, groupID=:groupID', $vars);
+ foreach ($group_users['data'] as $user) {
+ $userNames[] = $user['userID'];
+ }
+
+ $employee_list = $employee->getEmployeeByUserName($userNames, $oc_db);
+ foreach ($employee_list['data'] as $user) {
+ // if active user, then get backups and add them
+ if ($user['deleted'] == 0) {
+ $backups = $employee->getBackups($user['empUID']);
+
+ if (!empty($backups)) {
+ foreach ($backups as $backup) {
+ $backup_added = $this->addBackup($groupID, $backup['userName'], $user['userName']);
+
+ if ($backup_added['status']['code'] == 2) {
+ continue;
+ } else {
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'Action failed to add backups.'
+ )
+ );
+ break;
+ }
+ }
}
}
}
+ $return_value = array (
+ 'status' => array (
+ 'code' => 2,
+ 'message' => ''
+ )
+ );
+ } else {
+ $return_value = $group_users;
}
- //if the group is removed, also remove the category_privs
+ return $return_value;
+ }
+
+ /**
+ * @param int $groupID
+ * @param string $backup_user
+ * @param string $user
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:26:30 PM (America/New_York)
+ */
+ private function addBackup(int $groupID, string $backup_user, string $user): array
+ {
+ $vars = array(':userID' => $backup_user,
+ ':groupID' => $groupID,
+ ':backupID' => $user);
+ $sql = 'INSERT INTO `users` (`userID`, `groupID`, `backupID`)
+ VALUES (:userID, :groupID, :backupID)
+ ON DUPLICATE KEY UPDATE `userID` = :userID, `groupID` = :groupID';
+
+ $return_value = $this->db->pdo_insert_query($sql, $vars);
+
+ return $return_value;
+ }
+
+ /**
+ * @param int $groupID
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:26:53 PM (America/New_York)
+ */
+ private function getGroupUsers(int $groupID): array
+ {
$vars = array(':groupID' => $groupID);
- $res = $this->db->prepared_query('SELECT *
- FROM category_privs
- LEFT JOIN `groups` USING (groupID)
- WHERE category_privs.groupID = :groupID
- AND `groups`.groupID is null;', $vars);
- if(count($res) > 0)
- {
- $this->db->prepared_query('DELETE FROM category_privs WHERE groupID=:groupID', $vars);
+ $sql = 'SELECT `userID`
+ FROM `users`
+ WHERE `groupID` = :groupID';
+
+ $return_value = $this->db->pdo_select_query($sql, $vars);
+
+ return $return_value;
+ }
+
+ /**
+ * @param int $groupID
+ * @param array $emp
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:27:17 PM (America/New_York)
+ */
+ private function insertUser(int $groupID, array $emp): array
+ {
+ if (!empty($emp['userName'])) {
+ $vars = array(':userID' => $emp['userName'],
+ ':groupID' => $groupID, );
+ $sql = 'INSERT INTO `users` (`userID`, `groupID`, `active`)
+ VALUES (:userID, :groupID, 0)
+ ON DUPLICATE KEY UPDATE `userID` = :userID, `groupID` = :groupID';
+
+ $return_value = $this->db->pdo_insert_query($sql, $vars);
+ } else {
+ $return_value = array (
+ 'status' => array (
+ 'code' => 4,
+ 'message' => 'Improperly formatted data.'
+ )
+ );
}
+ return $return_value;
+ }
+
+ /**
+ * @param int $groupID
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:27:47 PM (America/New_York)
+ */
+ private function deleteUserBackups(int $groupID): array
+ {
+ $vars = array(':groupID' => $groupID);
+ $sql = 'DELETE
+ FROM `users`
+ WHERE `backupID` IS NOT NULL
+ AND `groupID` = :groupID';
+
+ $return_value = $this->db->pdo_delete_query($sql , $vars);
+
+ return $return_value;
+ }
+
+ /**
+ * @param int $groupID
+ * @param bool $isQuadrad
+ * @param string $title
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:28:03 PM (America/New_York)
+ */
+ private function insertGroup(int $groupID, bool $isQuadrad, string $title): array
+ {
+ $vars = array(':groupID' => $groupID,
+ ':parentGroupID' => ($isQuadrad == true ? -1 : null),
+ ':name' => $title,
+ ':groupDescription' => '', );
+ $sql = 'INSERT INTO `groups` (`groupID`, `parentGroupID`, `name`,
+ `groupDescription`)
+ VALUES (:groupID, :parentGroupID, :name, :groupDescription)';
+
+ $return_value = $this->db->pdo_insert_query($sql, $vars);
+
+ return $return_value;
+ }
+
+ /**
+ * @param int $groupID
+ *
+ * @return array
+ *
+ * Created at: 6/30/2023, 1:28:34 PM (America/New_York)
+ */
+ private function clearGroups(int $groupID): array
+ {
+ $vars = array(':groupID' => $groupID);
+ $sql = 'DELETE
+ FROM `groups`
+ WHERE `groupID` = :groupID';
+
+ $return_value = $this->db->pdo_delete_query($sql, $vars);
- return "groupID: {$groupID} updated";
+ return $return_value;
}
/**
diff --git a/LEAF_Request_Portal/templates/nocode_templates/view_homepage.tpl b/LEAF_Request_Portal/templates/nocode_templates/view_homepage.tpl
new file mode 100644
index 000000000..20ea1a5c4
--- /dev/null
+++ b/LEAF_Request_Portal/templates/nocode_templates/view_homepage.tpl
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LEAF_Request_Portal/templates/nocode_templates/view_search.tpl b/LEAF_Request_Portal/templates/nocode_templates/view_search.tpl
new file mode 100644
index 000000000..1166ab74c
--- /dev/null
+++ b/LEAF_Request_Portal/templates/nocode_templates/view_search.tpl
@@ -0,0 +1,301 @@
+
+
+
+
+
diff --git a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl
new file mode 100644
index 000000000..3064ec0df
--- /dev/null
+++ b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl
@@ -0,0 +1,1422 @@
+
+
+
+
+
+ Step 1: Develop search filter
+
+
+
+
+
+
+ Step 2: Select Data Columns
+
+
+
Loading...
+
+
Generate Multi-site Report
+
+
+
+
+
+Loading...
+
+
+
+
+
diff --git a/LEAF_Request_Portal/templates/view_reports.tpl b/LEAF_Request_Portal/templates/view_reports.tpl
index df8d1e12e..c570d2f93 100644
--- a/LEAF_Request_Portal/templates/view_reports.tpl
+++ b/LEAF_Request_Portal/templates/view_reports.tpl
@@ -290,7 +290,7 @@ function addHeader(column) {
callback: function(data, blob) {
let daysSinceAction;
let recordBlob = blob[data.recordID];
- if(recordBlob.action_history != undefined) {
+ if(recordBlob.action_history != undefined && recordBlob.action_history.length > 0) {
// Get Last Action no matter what (could change for non-comment)
let lastActionRecord = recordBlob.action_history.length - 1;
let lastAction = recordBlob.action_history[lastActionRecord];
diff --git a/LEAF_Request_Portal/templates/view_search.tpl b/LEAF_Request_Portal/templates/view_search.tpl
index f602fb56f..9b38a9d13 100644
--- a/LEAF_Request_Portal/templates/view_search.tpl
+++ b/LEAF_Request_Portal/templates/view_search.tpl
@@ -1,5 +1,7 @@
-
-Show more records
+