From 3d80e292b4896d4833a0314acb7ba736d9e10c5d Mon Sep 17 00:00:00 2001 From: shane Date: Fri, 22 Nov 2024 12:23:25 -0600 Subject: [PATCH 01/16] LEAF-4581 - work on getting emojis to post, also look at the full data set since we will want to also test the data going into the dbs and make sure they display properly as well --- LEAF-Automated-Tests | 2 +- LEAF_Request_Portal/sources/Form.php | 1 + LEAF_Request_Portal/sources/FormWorkflow.php | 2 +- LEAF_Request_Portal/testofcharacter.php | 31 ++++++++++++++++++++ app/Leaf/Db.php | 2 +- 5 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 LEAF_Request_Portal/testofcharacter.php diff --git a/LEAF-Automated-Tests b/LEAF-Automated-Tests index a7f6435a6..f7c9b1ac8 160000 --- a/LEAF-Automated-Tests +++ b/LEAF-Automated-Tests @@ -1 +1 @@ -Subproject commit a7f6435a65ae82b646ebfd70cd3ea92015b96a38 +Subproject commit f7c9b1ac8d1311b60727cb96aa206957674483e9 diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 4945a1f5d..589d4195f 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -1095,6 +1095,7 @@ public function isCategory($categoryID) */ private function writeDataField($recordID, $key, $series) { + if (is_array($_POST[$key])) //multiselect, checkbox, grid items { $_POST[$key] = XSSHelpers::scrubObjectOrArray($_POST[$key]); diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index 48603d0a0..507aa84f0 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -1672,7 +1672,7 @@ private function getFields(): array default: break; } - $data = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $data); + //$data = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $data); $formattedFields["content"][$field['indicatorID']] = $data !== "" ? $data : $field["default"]; $formattedFields["to_cc_content"][$field['indicatorID']] = $emailValue; } diff --git a/LEAF_Request_Portal/testofcharacter.php b/LEAF_Request_Portal/testofcharacter.php new file mode 100644 index 000000000..1d58fd61f --- /dev/null +++ b/LEAF_Request_Portal/testofcharacter.php @@ -0,0 +1,31 @@ + + + + + + Characters + + + + + + + + +
+ '; +} + for ($codePoint = $startCode; $codePoint <= $endCode; $codePoint++) { + $unicodeChar = mb_chr($codePoint); + echo "U+".dechex($codePoint).": $unicodeChar\n"; + } + ?> +
+ + + diff --git a/app/Leaf/Db.php b/app/Leaf/Db.php index 0d6e4bbbf..a31c050b5 100644 --- a/app/Leaf/Db.php +++ b/app/Leaf/Db.php @@ -77,7 +77,7 @@ public function __construct($host, $user, $pass, $database, $abortOnError = fals $this->isConnected = false; } - + $this->db->exec("SET NAMES 'utf8mb4'"); unset($pass); } From e710967a96855485de759165a90876528378dfb0 Mon Sep 17 00:00:00 2001 From: shane Date: Tue, 26 Nov 2024 13:30:09 -0600 Subject: [PATCH 02/16] LEAF-4581 - get the db changes that we will need in place and get the testing thing I was trying out. Need to figureo ut how to write tests for this one --- LEAF-Automated-Tests | 2 +- LEAF_Request_Portal/testofcharacter.php | 31 ------------ .../Update_RMC_DB_2024101500-2024112500.sql | 47 +++++++++++++++++++ 3 files changed, 48 insertions(+), 32 deletions(-) delete mode 100644 LEAF_Request_Portal/testofcharacter.php create mode 100644 docker/mysql/db/db_upgrade/portal/Update_RMC_DB_2024101500-2024112500.sql diff --git a/LEAF-Automated-Tests b/LEAF-Automated-Tests index f7c9b1ac8..8d87883ef 160000 --- a/LEAF-Automated-Tests +++ b/LEAF-Automated-Tests @@ -1 +1 @@ -Subproject commit f7c9b1ac8d1311b60727cb96aa206957674483e9 +Subproject commit 8d87883efbef6bf4e028868c2db41ec42c2d0a35 diff --git a/LEAF_Request_Portal/testofcharacter.php b/LEAF_Request_Portal/testofcharacter.php deleted file mode 100644 index 1d58fd61f..000000000 --- a/LEAF_Request_Portal/testofcharacter.php +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - Characters - - - - - - - - -
- '; -} - for ($codePoint = $startCode; $codePoint <= $endCode; $codePoint++) { - $unicodeChar = mb_chr($codePoint); - echo "U+".dechex($codePoint).": $unicodeChar\n"; - } - ?> -
- - - diff --git a/docker/mysql/db/db_upgrade/portal/Update_RMC_DB_2024101500-2024112500.sql b/docker/mysql/db/db_upgrade/portal/Update_RMC_DB_2024101500-2024112500.sql new file mode 100644 index 000000000..04ad32593 --- /dev/null +++ b/docker/mysql/db/db_upgrade/portal/Update_RMC_DB_2024101500-2024112500.sql @@ -0,0 +1,47 @@ +START TRANSACTION; + +ALTER TABLE `data` +CHANGE `data` `data` text COLLATE 'utf8mb4_general_ci' NOT NULL AFTER `series`, +CHANGE `userID` `userID` varchar(50) COLLATE 'utf8mb4_general_ci' NOT NULL AFTER `timestamp`, +COLLATE 'utf8mb4_general_ci'; + +ALTER TABLE `data_history` +CHANGE `data` `data` text COLLATE 'utf8mb4_general_ci' NOT NULL AFTER `series`, +CHANGE `userID` `userID` varchar(50) COLLATE 'utf8mb4_general_ci' NOT NULL AFTER `timestamp`, +CHANGE `userDisplay` `userDisplay` varchar(90) COLLATE 'utf8mb4_general_ci' NULL AFTER `userID`, +COLLATE 'utf8mb4_general_ci'; + +ALTER TABLE `records` +CHANGE `userID` `userID` varchar(50) COLLATE 'utf8mb4_general_ci' NOT NULL AFTER `serviceID`, +CHANGE `title` `title` text COLLATE 'utf8mb4_general_ci' NULL AFTER `userID`, +CHANGE `lastStatus` `lastStatus` text COLLATE 'utf8mb4_general_ci' NULL AFTER `priority`, +COLLATE 'utf8mb4_general_ci'; + + +UPDATE `settings` SET `data` = '2024112500' WHERE `settings`.`setting` = 'dbversion'; + +COMMIT; + +/**** Revert DB ***** NOTE: Data could have issues going back if it contains data that is in the mb4 set +START TRANSACTION; + +ALTER TABLE `data` +CHANGE `data` `data` text COLLATE 'utf8mb3_general_ci' NOT NULL AFTER `series`, +CHANGE `userID` `userID` varchar(50) COLLATE 'utf8mb3_general_ci' NOT NULL AFTER `timestamp`, +COLLATE 'utf8mb3_general_ci'; + +ALTER TABLE `data_history` +CHANGE `data` `data` text COLLATE 'utf8mb3_general_ci' NOT NULL AFTER `series`, +CHANGE `userID` `userID` varchar(50) COLLATE 'utf8mb3_general_ci' NOT NULL AFTER `timestamp`, +CHANGE `userDisplay` `userDisplay` varchar(90) COLLATE 'utf8mb3_general_ci' NULL AFTER `userID`, +COLLATE 'utf8mb3_general_ci'; + +ALTER TABLE `records` +CHANGE `userID` `userID` varchar(50) COLLATE 'utf8mb3_general_ci' NOT NULL AFTER `serviceID`, +CHANGE `title` `title` text COLLATE 'utf8mb3_general_ci' NULL AFTER `userID`, +COLLATE 'utf8mb3_general_ci'; + +UPDATE `settings` SET `data` = '2024101500' WHERE `settings`.`setting` = 'dbversion'; + +COMMIT; +*/ From 950a2280c98595efe6262ea868a739b5c6eaf145 Mon Sep 17 00:00:00 2001 From: Jamie P Holcomb Date: Tue, 10 Dec 2024 14:21:10 -0500 Subject: [PATCH 03/16] Leaf 4376 - update userName --- app/Leaf/VAMCActiveDirectory.php | 489 +++++++++++++++++++++++++++++ scripts/updateNationalOrgchart.php | 23 ++ 2 files changed, 512 insertions(+) create mode 100644 app/Leaf/VAMCActiveDirectory.php create mode 100644 scripts/updateNationalOrgchart.php diff --git a/app/Leaf/VAMCActiveDirectory.php b/app/Leaf/VAMCActiveDirectory.php new file mode 100644 index 000000000..1c070a802 --- /dev/null +++ b/app/Leaf/VAMCActiveDirectory.php @@ -0,0 +1,489 @@ + 'lname', + 'givenName' => 'fname', + 'initials' => 'midIni', + 'mail' => 'email', + 'telephoneNumber' => 'phone', + 94 => 'pager', + 'physicalDeliveryOfficeName' => 'roomNum', + 'title' => 'title', + 'description' => 'service', + 98 => 'mailcode', + 'sAMAccountName' => 'loginName', + 'mobile' => 'mobile', + 'DN' => 'domain', + 'objectGUID' => 'guid'); + + // Connect to the database + public function __construct($national_db) + { + $this->db = $national_db; + } + + // Imports data from \t and \n delimited file of format: + // Name Business Phone Description Modified E-Mail Address User Logon Name + public function importADData($file) + { + $data = $this->getData($file); + $rawdata = explode("\r\n", $data[0]['data']); + $rawheaders = trim(array_shift($rawdata)); + $rawheaders = explode(',', $rawheaders); + + foreach ($rawdata as $key => $line) { + $t = $this->splitWithEscape($line); + array_walk($t, array($this, 'trimField2')); + + if (!is_array($t)) { + return 'invalid service'; + } + + foreach ($t as $t_key => $val) { + $head_check = $rawheaders[$t_key]; + + if (!isset($this->headers[$head_check])) { + return 'invalid header'; + } + + $write_data[$key][$this->headers[$head_check]] = $val; + } + } + + $count = 0; + + foreach ($write_data as $employee) { + if ( + isset($employee['lname']) + && $employee['lname'] != '' + && isset($employee['loginName']) + && $employee['loginName'] != '' + && !is_numeric($employee['loginName']) + && !str_contains($employee['loginName'], '.') + ) { + $id = md5(strtoupper($employee['lname']) . strtoupper($employee['fname']) . strtoupper($employee['midIni'])); + + $this->users[$id]['lname'] = $employee['lname']; + $this->users[$id]['fname'] = $employee['fname']; + $this->users[$id]['midIni'] = $employee['midIni']; + $this->users[$id]['email'] = isset($employee['email']) ? $employee['email'] : null; + $this->users[$id]['phone'] = $employee['phone']; + $this->users[$id]['pager'] = isset($employee['pager']) ? $employee['pager'] : null; + $this->users[$id]['roomNum'] = $employee['roomNum']; + $this->users[$id]['title'] = $employee['title']; + $this->users[$id]['service'] = $employee['service']; + $this->users[$id]['mailcode'] = isset($employee['mailcode']) ? $employee['mailcode'] : null; + $this->users[$id]['loginName'] = $employee['loginName']; + $this->users[$id]['objectGUID'] = null; + $this->users[$id]['mobile'] = $employee['mobile']; + $this->users[$id]['domain'] = $employee['domain']; + $this->users[$id]['source'] = 'ad'; + //echo "Grabbing data for $employee['lname'], $employee['fname']\n"; + $count++; + } else { + $ln = isset($employee['loginName']) ? $employee['loginName'] : 'no login name'; + $lan = isset($employee['lname']) ? $employee['lname'] : 'no last name'; + $message = "{$ln} - {$lan} probably not a user, skipping.\n"; + error_log($message, 3, '/var/www/php-logs/ad_processing.log'); + } + + if ($count > 100) { + $this->importData(); + $count = 0; + } + } + + // import any remaining entries + $this->importData(); + + // get all userNames that should be disabled + $disableUsersList = $this->getUserNamesToBeDisabled(); + error_log(print_r($disableUsersList, true), 3, '/var/www/php-logs/errors.log'); + + + // Disable users not in this array + //$this->preventRecycledUserName($disableUsersList); + + + } + + // Imports data from \t and \n delimited file of format: + // Lname\t Fname Mid_Initial\t Email\t Phone\t Pager\t Room#\t Title\t Service\t MailCode\n + public function importData() + { + $time = time(); + $sql1 = 'INSERT INTO employee (userName, lastName, firstName, middleName, phoneticFirstName, phoneticLastName, domain, lastUpdated, new_empUUID) + VALUES (:loginName, :lname, :fname, :midIni, :phoneticFname, :phoneticLname, :domain, :lastUpdated, uuid())'; + + $count = 0; + + $userKeys = array_keys($this->users); + + foreach ($userKeys as $key) { + $phoneticFname = metaphone($this->users[$key]['fname']); + $phoneticLname = metaphone($this->users[$key]['lname']); + + $vars = array(':loginName' => $this->users[$key]['loginName']); + $sql = 'SELECT SQL_NO_CACHE * + FROM employee + WHERE username = :loginName'; + + $res = $this->db->prepared_query($sql, $vars); + + if (count($res) > 0) { + //echo "Updating data for {$this->users[$key]['lname']}, {$this->users[$key]['fname']} \n"; + + $vars = array(':empUID' => $res[0]['empUID'], + ':indicatorID' => 6, + ':data' => $this->users[$key]['email']); + $sql = "INSERT INTO `employee_data` (`empUID`, `indicatorID`, `data`, `author`) + VALUES (:empUID, :indicatorID, :data, 'system') + ON DUPLICATE KEY UPDATE `data` = :data"; + + $this->db->prepared_query($sql, $vars); + + $vars = array(':empUID' => $res[0]['empUID'], + ':indicatorID' => 5, + ':data' => $this->fixIfHex($this->users[$key]['phone'])); + + $this->db->prepared_query($sql, $vars); + + $vars = array(':empUID' => $res[0]['empUID'], + ':indicatorID' => 8, + ':data' => $this->fixIfHex($this->users[$key]['roomNum'])); + + $this->db->prepared_query($sql, $vars); + + $vars = array(':empUID' => $res[0]['empUID'], + ':indicatorID' => 23, + ':data' => $this->fixIfHex($this->users[$key]['title'])); + + $this->db->prepared_query($sql, $vars); + + // don't store mobile # if it's the same as the primary phone # + if ($this->users[$key]['phone'] != $this->users[$key]['mobile']) { + $vars = array(':empUID' => $res[0]['empUID'], + ':indicatorID' => 16, + ':data' => $this->fixIfHex($this->users[$key]['mobile'])); + + $this->db->prepared_query($sql, $vars); + } + + $vars = array(':lname' => $this->users[$key]['lname'], + ':fname' => $this->users[$key]['fname'], + ':midIni' => $this->users[$key]['midIni'], + ':phoneticFname' => $phoneticFname, + ':phoneticLname' => $phoneticLname, + ':domain' => $this->users[$key]['domain'], + ':lastUpdated' => $time, + ':userName' => $this->users[$key]['loginName']); + $sql = 'UPDATE employee + SET lastName = :lname, + firstName = :fname, + middleName = :midIni, + phoneticFirstName = :phoneticFname, + phoneticLastName = :phoneticLname, + domain = :domain, + lastUpdated = :lastUpdated, + deleted = 0 + WHERE username = :userName'; + + $this->db->prepared_query($sql, $vars); + } else { + $vars = array(':loginName', $this->users[$key]['loginName'], + ':lname', $this->users[$key]['lname'], + ':fname', $this->users[$key]['fname'], + ':midIni', $this->users[$key]['midIni'], + ':phoneticFname', $phoneticFname, + ':phoneticLname', $phoneticLname, + ':domain', $this->users[$key]['domain'], + ':lastUpdated', $time); + + $this->db->prepared_query($sql1, $vars); + + //echo "Inserting data for {$this->users[$key]['lname']}, {$this->users[$key]['fname']} : " . $pq->errorCode() . "\n"; + + $lastEmpUID = $this->db->getLastInsertId(); + + // prioritize adding email to DB + $sql = "INSERT INTO employee_data (empUID, indicatorID, data, author) + VALUES (:empUID, :indicatorID, :data, 'system') + ON DUPLICATE KEY UPDATE data=:data"; + + $vars = array(':empUID', $lastEmpUID, + ':indicatorID', 6, + ':data', $this->users[$key]['email']); + $this->db->prepared_query($sql, $vars); + $count++; + } + + unset($this->users[$key]); + } + + echo 'Cleanup... '; + // TODO: do some clean up + echo "... Done.\n"; + + echo "Total: $count"; + } + + private function getUserNamesToBeDisabled(): array + { + $sql = 'SELECT `userName` + FROM `employee` + WHERE `deleted` = 0 + AND `lastUpdated` < (UNIX_TIMESTAMP(NOW() - 108000) '; + + $return_value = $this->db->prepared_query($sql, array()); + + return $return_value; + } + + private function getNewlyDeletedUsers($time): array + { + $sql = 'SELECT `userName` + FROM `employee` + WHERE `userName` LIKE "disabled_{$time}_%"'; + + $return_value = $this->db->prepared_query($sql, array()); + + return $return_value; + } + + private function preventRecycledUserName(array $userNames): void + { + $commaUserNames = implode(',', $userNames); + $deleteTime = time(); + + $vars = array(':deleteTime' => $deleteTime); + + $sql = 'UPDATE `employee` + SET `deleted` = :deleteTime, + `userName` = concat("disabled_", `deleted`, "_", `userName`) + WHERE `userName` IN ("' . implode('","', array_values($userNames)) . '")'; + + $this->db->prepared_query($sql, $vars); + + foreach ($userNames as $name) { + $vars[':userName'] = $name; + $sql = 'UPDATE `employee_data` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName'; + + $this->db->prepared_query($sql, $vars); + + $sql = 'UPDATE `employee_data_history` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName'; + + $this->db->prepared_query($sql, $vars); + + $sql = 'UPDATE `group_data` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName'; + + $this->db->prepared_query($sql, $vars); + + $sql = 'UPDATE `group_data_history` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName'; + + $this->db->prepared_query($sql, $vars); + + $sql = 'UPDATE `position_data` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName'; + + $this->db->prepared_query($sql, $vars); + + $sql = 'UPDATE `position_data_history` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName'; + + $this->db->prepared_query($sql, $vars); + + $sql = 'UPDATE `relation_employee_backup` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `approverUserName` = :userName'; + + $this->db->prepared_query($sql, $vars); + } + } + + private function getData(string $file): array + { + $vars = array(':file' => $file); + $sql = 'SELECT `data` + FROM `cache` + WHERE `cacheID` = :file'; + + $data = $this->db->prepared_query($sql, $vars); + + $this->removeData($file); + + return $data; + } + + private function removeData(string $file): void + { + $vars = array(':file' => $file); + $sql = 'DELETE + FROM `cache` + WHERE `cacheID` = :file'; + + $this->db->prepared_query($sql, $vars); + } + + private function trimField2(string &$value, string $key): void + { + $value = trim($value); + $value = trim($value, '.'); + } + + // workaround for excel + // author: tajhlande at gmail dot com + private function splitWithEscape($str, $delimiterChar = ',', $escapeChar = '"') + { + $len = strlen($str); + $tokens = array(); + $i = 0; + $inEscapeSeq = false; + $currToken = ''; + + while ($i < $len) { + $c = substr($str, $i, 1); + + if ($inEscapeSeq) { + if ($c == $escapeChar) { + // lookahead to see if next character is also an escape char + if ($i == ($len - 1)) { + // c is last char, so must be end of escape sequence + $inEscapeSeq = false; + } elseif (substr($str, $i + 1, 1) == $escapeChar) { + // append literal escape char + $currToken .= $escapeChar; + $i++; + } else { + // end of escape sequence + $inEscapeSeq = false; + } + } else { + $currToken .= $c; + } + } else { + if ($c == $delimiterChar) { + // end of token, flush it + array_push($tokens, $currToken); + $currToken = ''; + } elseif ($c == $escapeChar) { + // begin escape sequence + $inEscapeSeq = true; + } else { + $currToken .= $c; + } + } + + $i++; + } + + // flush the last token + array_push($tokens, $currToken); + + return $tokens; + } + + private function parseVAdomain($adPath) + { + $dc = ''; + $dcSrc = explode(',', $adPath); + + foreach ($dcSrc as $adElement) { + if (strpos($adElement, 'DC=') !== false) { + $dc .= substr($adElement, 3) . '.'; + } + } + + $dc = trim($dc, '.'); + + switch ($dc) { + case 'v01.med.va.gov': + return 'VHA01'; + case 'v02.med.va.gov': + return 'VHA02'; + case 'v03.med.va.gov': + return 'VHA03'; + case 'v04.med.va.gov': + return 'VHA04'; + case 'v05.med.va.gov': + return 'VHA05'; + case 'v06.med.va.gov': + return 'VHA06'; + case 'v07.med.va.gov': + return 'VHA07'; + case 'v08.med.va.gov': + return 'VHA08'; + case 'v09.med.va.gov': + return 'VHA09'; + case 'v10.med.va.gov': + return 'VHA10'; + case 'v11.med.va.gov': + return 'VHA11'; + case 'v12.med.va.gov': + return 'VHA12'; + case 'v13.med.va.gov': + return 'VHA13'; + case 'v14.med.va.gov': + return 'VHA14'; + case 'v15.med.va.gov': + return 'VHA15'; + case 'v16.med.va.gov': + return 'VHA16'; + case 'v17.med.va.gov': + return 'VHA17'; + case 'v18.med.va.gov': + return 'VHA18'; + case 'v19.med.va.gov': + return 'VHA19'; + case 'v20.med.va.gov': + return 'VHA20'; + case 'v21.med.va.gov': + return 'VHA21'; + case 'v22.med.va.gov': + return 'VHA22'; + case 'v23.med.va.gov': + return 'VHA23'; + default: + return $dc; + } + } + + //tests stringToFix for format X'...', if it matches, it's a hex value, is decoded and returned + private function fixIfHex($stringToFix) + { + if (substr( $stringToFix, 0, 2 ) === "X'") { + $stringToFix = ltrim($stringToFix, "X'"); + $stringToFix = rtrim($stringToFix, "'"); + $stringToFix = hex2bin($stringToFix); + } + + return $stringToFix; + } +} diff --git a/scripts/updateNationalOrgchart.php b/scripts/updateNationalOrgchart.php new file mode 100644 index 000000000..1431ff15d --- /dev/null +++ b/scripts/updateNationalOrgchart.php @@ -0,0 +1,23 @@ +importADData($file); + +$endTime = microtime(true); +$totalTime = round(($endTime - $startTime)/60, 2); + +error_log(print_r($file . " took " . $totalTime . " minutes to complete.", true), 3 , '/var/www/php-logs/ad_processing.log'); \ No newline at end of file From a6f408303f1972ded6938548d057fb859c46f47e Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Wed, 11 Dec 2024 13:34:06 -0500 Subject: [PATCH 04/16] LEAF 4597 move info element, move styles to css, control display with class names --- LEAF_Nexus/css/editor.css | 28 +++++++++++++++++++++++ LEAF_Nexus/templates/editor.tpl | 40 ++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/LEAF_Nexus/css/editor.css b/LEAF_Nexus/css/editor.css index 9b02159cc..369609f77 100644 --- a/LEAF_Nexus/css/editor.css +++ b/LEAF_Nexus/css/editor.css @@ -91,4 +91,32 @@ #editor_tools>span:hover { background-color: #2372b0; color: white; +} + +#visual_alert_box_container { + max-width: 354px; + box-sizing: border-box; + margin-left: auto; +} +#visual_alert_box { + text-align: left; + position: relative; + padding: 0.25em; + background-color:#fff; +} +#visual_alert_box_container label { + display: flex; + justify-content:flex-end; + padding-top: 0.25rem; +} +#visual_alert_box.hide, #visual_alert_box_container label.hide { + display: none; +} + +#visual_alert_box_container label input { + margin: 0 0 0 0.25rem; +} + +#visual_alert_box_title { + font-weight: bolder; } \ No newline at end of file diff --git a/LEAF_Nexus/templates/editor.tpl b/LEAF_Nexus/templates/editor.tpl index 3b7c4c3db..abcd4a723 100644 --- a/LEAF_Nexus/templates/editor.tpl +++ b/LEAF_Nexus/templates/editor.tpl @@ -19,9 +19,19 @@ placeholder
+
+
+ You are moving the card
+ Esc - return to original location
+ Enter - save current location +
+ +
-
+
Loading...
@@ -120,6 +130,17 @@ function applyZoomLevel() { } } +function toggleHideClass( elementID = '') { + let el = document.getElementById(elementID); + if(el !== null) { + if(el.classList.contains('hide')) { + el.classList.remove('hide'); + } else { + el.classList.add('hide'); + } + } +} + function viewSupervisor() { $.ajax({ url: './api/position//supervisor', @@ -263,7 +284,7 @@ function moveCoordinates(prefix, position) { if (e.key === "Tab") { saveLayout(position); $('#' + prefix + position).css('box-shadow', 'none'); - $('#visual_alert_box').css('opacity', '0'); + $('#visual_alert_box').addClass('hide'); document.removeEventListener('keydown', moveCard); return; } else if (controlKeys.includes(e.key)) { @@ -300,7 +321,7 @@ function moveCoordinates(prefix, position) { if (abort) { $('#' + prefix + position).css('box-shadow', 'none'); - $('#visual_alert_box').css('opacity', '0'); + $('#visual_alert_box').addClass('hide'); document.removeEventListener('keydown', moveCard); return; } @@ -308,11 +329,18 @@ function moveCoordinates(prefix, position) { }; $('div.positionSmall').css('box-shadow', 'none'); $('#' + prefix + position).css('box-shadow', ' 0 0 6px #c00'); - let alert_box = document.getElementById('visual_alert_box'); + let alert_box_card_title = document.getElementById('visual_alert_box_title'); let title = document.getElementById(prefix + position + '_title'); let titleText = title.innerHTML; - alert_box.innerHTML = "You are moving the " + titleText + " card
Esc - return to original location
Enter - save current location
Tab - Save and move to next card"; - $('#visual_alert_box').css('opacity', '100'); + alert_box_card_title.textContent = titleText; + if( $('#visual_alert_box_container label').hasClass('hide')) { + $('#visual_alert_box_container label').removeClass('hide'); + $('#visual_alert_box').removeClass('hide'); + } else { + if(document.getElementById('MovementInfoToggle').checked !== true) { + $('#visual_alert_box').removeClass('hide'); + } + } let card = document.getElementById(prefix + position); let cardStyle = window.getComputedStyle(card); From a61bc059a1fd1a49bf5f3a84896a9373fbd12c87 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Thu, 12 Dec 2024 09:25:43 -0500 Subject: [PATCH 05/16] LEAF 4597 only show card keyboard info when using keyboard to move --- LEAF_Nexus/templates/editor.tpl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/LEAF_Nexus/templates/editor.tpl b/LEAF_Nexus/templates/editor.tpl index abcd4a723..edf443fba 100644 --- a/LEAF_Nexus/templates/editor.tpl +++ b/LEAF_Nexus/templates/editor.tpl @@ -289,6 +289,17 @@ function moveCoordinates(prefix, position) { return; } else if (controlKeys.includes(e.key)) { e.preventDefault(); + //only show extra info if keyboard is being used to move the card + if(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) { + if( $('#visual_alert_box_container label').hasClass('hide')) { + $('#visual_alert_box_container label').removeClass('hide'); + $('#visual_alert_box').removeClass('hide'); + } else { + if(document.getElementById('MovementInfoToggle').checked !== true) { + $('#visual_alert_box').removeClass('hide'); + } + } + } switch (e.key) { case "ArrowLeft": leftValue = (Number(leftValue) - 10); @@ -333,14 +344,6 @@ function moveCoordinates(prefix, position) { let title = document.getElementById(prefix + position + '_title'); let titleText = title.innerHTML; alert_box_card_title.textContent = titleText; - if( $('#visual_alert_box_container label').hasClass('hide')) { - $('#visual_alert_box_container label').removeClass('hide'); - $('#visual_alert_box').removeClass('hide'); - } else { - if(document.getElementById('MovementInfoToggle').checked !== true) { - $('#visual_alert_box').removeClass('hide'); - } - } let card = document.getElementById(prefix + position); let cardStyle = window.getComputedStyle(card); From a189823cba61eb736fa257b3302e7c3f75d02370 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Thu, 12 Dec 2024 13:12:48 -0500 Subject: [PATCH 06/16] LEAF 4597 updates to coord tracking and after move paint --- LEAF_Nexus/js/ui/position.js | 3 +- LEAF_Nexus/templates/editor.tpl | 61 ++++++++++++++++----------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/LEAF_Nexus/js/ui/position.js b/LEAF_Nexus/js/ui/position.js index a4a956f5b..3fb289027 100644 --- a/LEAF_Nexus/js/ui/position.js +++ b/LEAF_Nexus/js/ui/position.js @@ -47,7 +47,8 @@ position.prototype.initialize = function (parentContainerID) { $("#" + prefixedPID + "_title").on("click keydown mouseenter", function(ev) { //if they are newly focusing an open card just update the tab focus const isNewFocus = document.activeElement !== ev.currentTarget; - if (ev.type === "click" && isNewFocus) { + const cardDataAttr = ev.currentTarget.parentNode.getAttribute('data-moving'); + if (ev.type === "click" && isNewFocus || cardDataAttr === "true") { ev.currentTarget.focus(); return; } diff --git a/LEAF_Nexus/templates/editor.tpl b/LEAF_Nexus/templates/editor.tpl index edf443fba..028c54b3c 100644 --- a/LEAF_Nexus/templates/editor.tpl +++ b/LEAF_Nexus/templates/editor.tpl @@ -155,7 +155,7 @@ function viewSupervisor() { }); } -function saveLayout(positionID) { +function saveLayout(positionID, repaint = false) { const position = $('#' + positions[positionID].getDomID()).offset(); let newPosition = new Object(); newPosition.x = parseInt(position.left); @@ -174,6 +174,9 @@ function saveLayout(positionID) { if (+res === 1) { positions[positionID].x = newPosition.x; positions[positionID].y = newPosition.y; + if(repaint === true) { + jsPlumb.repaintEverything(); + } } $('#busyIndicator').css('visibility', 'hidden'); }, @@ -280,17 +283,26 @@ function addSupervisor(positionID) { } function moveCoordinates(prefix, position) { + let card = document.getElementById(prefix + position); + const cardStyle = window.getComputedStyle(card); + const originalTopOrg = cardStyle.getPropertyValue('top'); + const originalLeftOrg = cardStyle.getPropertyValue('left'); + const moveCard = (e) => { if (e.key === "Tab") { - saveLayout(position); + saveLayout(position, true); $('#' + prefix + position).css('box-shadow', 'none'); $('#visual_alert_box').addClass('hide'); document.removeEventListener('keydown', moveCard); return; } else if (controlKeys.includes(e.key)) { e.preventDefault(); + const cardStyle = window.getComputedStyle(card); + const topValue = Number(cardStyle.getPropertyValue('top').replace("px", "")); + const leftValue = Number(cardStyle.getPropertyValue('left').replace("px", "")); //only show extra info if keyboard is being used to move the card if(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) { + card.setAttribute("data-moving", "true"); if( $('#visual_alert_box_container label').hasClass('hide')) { $('#visual_alert_box_container label').removeClass('hide'); $('#visual_alert_box').removeClass('hide'); @@ -299,43 +311,35 @@ function moveCoordinates(prefix, position) { $('#visual_alert_box').removeClass('hide'); } } + } else { + card.removeAttribute("data-moving"); } switch (e.key) { case "ArrowLeft": - leftValue = (Number(leftValue) - 10); - card.style.left = leftValue + "px"; + card.style.left = leftValue - 10 + "px"; break; case "ArrowRight": - leftValue = (Number(leftValue) + 10); - card.style.left = leftValue + "px"; + card.style.left = leftValue + 10 + "px"; break; case "ArrowUp": - topValue = (Number(topValue) - 10); - card.style.top = topValue + "px"; + card.style.top = topValue - 10 + "px"; break; case "ArrowDown": - topValue = (Number(topValue) + 10); - card.style.top = topValue + "px"; + card.style.top = topValue + 10 + "px"; break; case "Enter": // save the coordinates as they are now - saveLayout(position); - abort = true; + saveLayout(position, true); break; case "Escape": // revert coordinates back to original - card.style.top = topOrg; - card.style.left = leftOrg; - abort = true; + card.style.top = originalTopOrg; + card.style.left = originalLeftOrg + $('#' + prefix + position).css('box-shadow', 'none'); + $('#visual_alert_box').addClass('hide'); + document.removeEventListener('keydown', moveCard); break; } - - if (abort) { - $('#' + prefix + position).css('box-shadow', 'none'); - $('#visual_alert_box').addClass('hide'); - document.removeEventListener('keydown', moveCard); - return; - } } }; $('div.positionSmall').css('box-shadow', 'none'); @@ -345,17 +349,12 @@ function moveCoordinates(prefix, position) { let titleText = title.innerHTML; alert_box_card_title.textContent = titleText; - let card = document.getElementById(prefix + position); - let cardStyle = window.getComputedStyle(card); - let topOrg = cardStyle.getPropertyValue('top'); - let leftOrg = cardStyle.getPropertyValue('left'); - let topValue = cardStyle.getPropertyValue('top').replace("px", ""); - let leftValue = cardStyle.getPropertyValue('left').replace("px", ""); - let key; - let abort = false; const controlKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Enter', 'Escape']; document.addEventListener('keydown', moveCard); - title.addEventListener('blur', () => document.removeEventListener('keydown', moveCard)); + title.addEventListener('blur', () => { + card.removeAttribute("data-moving"); + document.removeEventListener('keydown', moveCard) + }); } function addSubordinate(parentID) { From 85de6c6645dcfaec63626a5145744f2bb7ae8234 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Thu, 12 Dec 2024 17:09:39 -0500 Subject: [PATCH 07/16] Revert "Revert "Merge pull request #2615 from department-of-veterans-affairs/enhance/LEAF-4455/metadata_read_all"" This reverts commit 53146f424a1fa8bcad3f563eace6e396ff72940c. --- LEAF_Request_Portal/sources/Form.php | 121 +++++++++--------- LEAF_Request_Portal/sources/FormWorkflow.php | 20 +-- LEAF_Request_Portal/sources/View.php | 14 +- .../templates/reports/LEAF_Sitemap_Search.tpl | 1 + .../templates/view_reports.tpl | 1 + LEAF_Request_Portal/templates/view_status.tpl | 7 +- 6 files changed, 89 insertions(+), 75 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index d92116efd..cea57e765 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -573,15 +573,16 @@ public function getIndicator($indicatorID, $series, $recordID = null, $parseTemp $form[$idx]['value'] = $this->fileToArray($data[0]['data']); $form[$idx]['raw'] = $data[0]['data']; } - // special handling for org chart data types + // special handling for org chart data types (request header questions, edited report builder cells) else if ($data[0]['format'] == 'orgchart_employee' && !empty($data[0]['data'])) { - $empRes = $this->employee->lookupEmpUID($data[0]['data']); - if (!empty($empRes)) { - $form[$idx]['displayedValue'] = "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; - } else { - $form[$idx]['displayedValue'] = ''; + $form[$idx]['displayedValue'] = ''; + if (isset($data[0]['metadata'])) { + $orgchartInfo = json_decode($data[0]['metadata'], true); + if(!empty(trim($orgchartInfo['lastName']))) { + $form[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; + } } } else if ($data[0]['format'] == 'orgchart_position' @@ -1008,9 +1009,9 @@ public function getRecordInfo($recordID) ); } - $dir = new VAMC_Directory; - $user = $dir->lookupLogin($res[0]['userID']); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[0]['userID']; + $userMetadata = json_decode($res[0]['userMetadata'], true); + $name = isset($userMetadata) && !empty(trim($userMetadata['lastName'])) ? + "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $res[0]['userID']; $data = array('name' => $name, 'service' => $res[0]['service'], @@ -2658,16 +2659,14 @@ public function getCustomData(array $recordID_list, string|null $indicatorID_lis } } break; - case 'orgchart_employee': - $empRes = $this->employee->lookupEmpUID($item['data']); - if (isset($empRes[0])) - { - $item['data'] = "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; - $item['dataOrgchart'] = $empRes[0]; - } - else - { - $item['data'] = ''; + case 'orgchart_employee': //report builder cells + $item['data'] = ''; + if (isset($item['metadata'])) { + $orgchartInfo = json_decode($item['metadata'], true); + if(!empty(trim($orgchartInfo['lastName']))) { + $item['data'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; + $item['dataOrgchart'] = $orgchartInfo; + } } break; case 'orgchart_position': @@ -2785,14 +2784,14 @@ public function getActionComments(int $recordID): array } else { $vars = array(':recordID' => $recordID); - $sql = 'SELECT actionTextPasttense, comment, time, userID + $sql = 'SELECT actionTextPasttense, comment, time, userID, userMetadata FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN actions USING (actionType) WHERE recordID = :recordID AND comment != "" UNION - SELECT "Note Added", note, timestamp, userID + SELECT "Note Added", note, timestamp, userID, userMetadata FROM notes WHERE recordID = :recordID AND deleted IS NULL @@ -2800,13 +2799,12 @@ public function getActionComments(int $recordID): array $res = $this->db->prepared_query($sql, $vars); - $dir = new VAMC_Directory; - $total = count($res); - for ($i = 0; $i < $total; $i++) { - $user = $dir->lookupLogin($res[$i]['userID']); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[$i]['userID']; + $userMetadata = json_decode($res[$i]['userMetadata'], true); + $name = isset($userMetadata) && !empty(trim($userMetadata['lastName'])) ? + "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $res[$i]['userID']; + $res[$i]['name'] = $name; } @@ -2958,11 +2956,9 @@ public function setInitiator($recordID, $userID) userID=:userID, userMetadata=:userMetadata WHERE recordID=:recordID', $vars); - // write log entry - $dir = new VAMC_Directory; - $user = $dir->lookupLogin($userID); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $userID; + $newInitiatorInfo = json_decode($newInitiatorMetadata, true); + $name = "{$newInitiatorInfo['firstName']} {$newInitiatorInfo['lastName']}"; $actionUserID = $this->login->getUserID(); $actionUserMetadata = $this->employee->getInfoForUserMetadata($actionUserID, false); @@ -3765,14 +3761,27 @@ public function query(string $inQuery): mixed WHERE format = 'orgchart_employee') rj_OCEmployeeData ON (lj_data.indicatorID = rj_OCEmployeeData.indicatorID) "; } - if ($joinInitiatorNames) - { - $joins .= "LEFT JOIN (SELECT userName, lastName, firstName FROM {$this->oc_dbName}.employee) lj_OCinitiatorNames ON records.userID = lj_OCinitiatorNames.userName "; + + //joinInitiatorNames backwards compat - additional SQL for records.userMetadata replaces previous join with orgchart.employee. + //userMetadata properties are empty for accounts that were inactive when prior metadata values were updated. + //Alternatives here display 'userID (inactive account)' instead of 'null, null' if metadata is empty. + $initiatorNamesSQL = ''; + if ($joinInitiatorNames) { + $initiatorNamesSQL = ', + IF( + JSON_EXTRACT(`userMetadata`, "$.userName") != "", + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")), "(inactive account)" + ) AS `firstName`, + IF( + JSON_EXTRACT(`userMetadata`, "$.userName") != "", + TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")), `userID` + ) AS `lastName`'; } + $resSQL = 'SELECT * ' . $initiatorNamesSQL . ' FROM `records` ' . $joins . ' WHERE ' . $conditions . $sort . $limit; if(isset($_GET['debugQuery'])) { if($this->login->checkGroup(1)) { - $debugQuery = str_replace(["\r", "\n","\t", "%0d","%0a","%09","%20", ";"], ' ', 'SELECT * FROM records ' . $joins . 'WHERE ' . $conditions . $sort . $limit); + $debugQuery = str_replace(["\r", "\n","\t", "%0d","%0a","%09","%20", ";"], ' ', $resSQL); $debugVars = []; foreach($vars as $key => $value) { if(strpos($key, ':data') !== false @@ -3786,17 +3795,14 @@ public function query(string $inQuery): mixed header('X-LEAF-Query: '. str_replace(array_keys($debugVars), $debugVars, $debugQuery)); - return $res = $this->db->prepared_query('EXPLAIN SELECT * FROM records - ' . $joins . ' - WHERE ' . $conditions . $sort . $limit, $vars); + return $res = $this->db->prepared_query('EXPLAIN ' . $resSQL, $vars); } else { return XSSHelpers::scrubObjectOrArray(json_decode(html_entity_decode(html_entity_decode($_GET['q'])), true)); } } - $res = $this->db->prepared_query('SELECT * FROM records - ' . $joins . ' - WHERE ' . $conditions . $sort . $limit, $vars); + + $res = $this->db->prepared_query($resSQL, $vars); $data = array(); $recordIDs = ''; @@ -3872,17 +3878,15 @@ public function query(string $inQuery): mixed if ($joinActionHistory) { - $dir = new VAMC_Directory; - $actionHistorySQL = - 'SELECT recordID, stepID, userID, time, description, + 'SELECT recordID, stepID, userID, userMetadata, time, description, actionTextPasttense, actionType, comment FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN actions USING (actionType) WHERE recordID IN (' . $recordIDs . ') UNION - SELECT recordID, "-5", userID, timestamp, "Note Added", + SELECT recordID, "-5", userID, userMetadata, timestamp, "Note Added", "Note Added", "LEAF_note", note FROM notes WHERE recordID IN (' . $recordIDs . ') @@ -3892,8 +3896,10 @@ public function query(string $inQuery): mixed $res2 = $this->db->prepared_query($actionHistorySQL, array()); foreach ($res2 as $item) { - $user = $dir->lookupLogin($item['userID'], true); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $res[0]['userID']; + $userMetadata = json_decode($item['userMetadata'], true); + $name = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? + "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $item['userID']; + $item['approverName'] = $name; $data[$item['recordID']]['action_history'][] = $item; @@ -3931,9 +3937,7 @@ public function query(string $inQuery): mixed } if ($joinRecordResolutionBy === true) { - $dir = new VAMC_Directory; - - $recordResolutionBySQL = "SELECT recordID, action_history.userID as resolvedBy, action_history.stepID, action_history.actionType + $recordResolutionBySQL = "SELECT recordID, action_history.userID as resolvedBy, action_history.userMetadata, action_history.stepID, action_history.actionType FROM action_history LEFT JOIN records USING (recordID) INNER JOIN workflow_routes USING (stepID) @@ -3948,8 +3952,9 @@ public function query(string $inQuery): mixed $res2 = $this->db->prepared_query($recordResolutionBySQL, array()); foreach ($res2 as $item) { - $user = $dir->lookupLogin($item['resolvedBy'], true); - $nameResolved = isset($user[0]) ? "{$user[0]['Lname']}, {$user[0]['Fname']} " : $item['resolvedBy']; + $userMetadata = json_decode($item['userMetadata'], true); + $nameResolved = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? + "{$userMetadata['firstName']} {$userMetadata['lastName']} " : $item['resolvedBy']; $data[$item['recordID']]['recordResolutionBy']['resolvedBy'] = $nameResolved; } } @@ -4361,7 +4366,7 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp { $var = array(':series' => (int)$series, ':recordID' => (int)$recordID, ); - $res2 = $this->db->prepared_query('SELECT data, timestamp, indicatorID, groupID, userID FROM data + $res2 = $this->db->prepared_query('SELECT data, metadata, timestamp, indicatorID, groupID, userID FROM data LEFT JOIN indicator_mask USING (indicatorID) WHERE indicatorID IN (' . $indicatorList . ') AND series=:series AND recordID=:recordID', $var); @@ -4369,6 +4374,7 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp { $idx = $resIn['indicatorID']; $data[$idx]['data'] = isset($resIn['data']) ? $resIn['data'] : ''; + $data[$idx]['metadata'] = isset($resIn['metadata']) ? $resIn['metadata'] : null; $data[$idx]['timestamp'] = isset($resIn['timestamp']) ? $resIn['timestamp'] : 0; $data[$idx]['groupID'] = isset($resIn['groupID']) ? $resIn['groupID'] : null; $data[$idx]['userID'] = isset($resIn['userID']) ? $resIn['userID'] : ''; @@ -4435,14 +4441,15 @@ private function buildFormTree($id, $series = null, $recordID = null, $parseTemp $child[$idx]['value'] = $this->fileToArray($data[$idx]['data']); } - // special handling for org chart data types + // special handling for org chart data types (request subquestions / child) if ($field['format'] == 'orgchart_employee') { - $empRes = $this->employee->lookupEmpUID($data[$idx]['data']); $child[$idx]['displayedValue'] = ''; - if (isset($empRes[0])) - { - $child[$idx]['displayedValue'] = ($child[$idx]['isMasked']) ? '[protected data]' : "{$empRes[0]['firstName']} {$empRes[0]['lastName']}"; + if (isset($data[$idx]['metadata'])) { + $orgchartInfo = json_decode($data[$idx]['metadata'], true); + if(!empty(trim($orgchartInfo['lastName']))) { + $child[$idx]['displayedValue'] = "{$orgchartInfo['firstName']} {$orgchartInfo['lastName']}"; + } } } if ($field['format'] == 'orgchart_position') diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index e5960b8e6..0c39dbc18 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -447,7 +447,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $strSQL = ""; if(!$selectUnfilled) { - $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, requiresDigitalSignature FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepID, stepTitle, blockingStepID, workflowID, serviceID, filled, stepBgColor, stepFontColor, stepBorder, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, jsSrc, userID, userMetadata, requiresDigitalSignature FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -456,7 +456,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel WHERE recordID IN ({$recordIDs})"; } else { - $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID FROM records_workflow_state + $strSQL = "SELECT dependencyID, recordID, stepTitle, serviceID, `description`, indicatorID_for_assigned_empUID, indicatorID_for_assigned_groupID, userID, userMetadata FROM records_workflow_state LEFT JOIN records USING (recordID) LEFT JOIN workflow_steps USING (stepID) LEFT JOIN step_dependencies USING (stepID) @@ -494,8 +494,8 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; - $res[$i]['approverName'] = '(Requestor followup)'; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Inactive User)'; + $res[$i]['approverName'] = '(Inactive User)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { @@ -543,8 +543,8 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $dir = $this->getDirectory(); $approver = $dir->lookupLogin($res[$i]['userID']); if (empty($approver[0]['Fname']) && empty($approver[0]['Lname'])) { - $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Requestor followup)'; - $res[$i]['approverName'] = '(Requestor followup)'; + $res[$i]['description'] = $res[$i]['stepTitle'] . ' (Inactive User)'; + $res[$i]['approverName'] = '(Inactive User)'; $res[$i]['approverUID'] = $res[$i]['userID']; } else { @@ -716,11 +716,11 @@ public function getLastAction(): array|null|int if (isset($res[0]) && $res[0]['dependencyID'] == -1) { - $dir = $this->getDirectory(); - - $approver = $dir->lookupLogin($res[0]['userID']); + $approverMetadata = json_decode($res[0]['userMetadata'], true); + $display = isset($approverMetadata) && trim($approverMetadata['firstName'] . " " . $approverMetadata['lastName'] ) !== '' ? + $approverMetadata['firstName'] . " " . $approverMetadata['lastName'] : $res[0]['userID']; - $res[0]['description'] = "{$approver[0]['firstName']} {$approver[0]['lastName']}"; + $res[0]['description'] = $display; } // dependencyID -3 is for a group designated by the requestor if (isset($res[0]) diff --git a/LEAF_Request_Portal/sources/View.php b/LEAF_Request_Portal/sources/View.php index a31dc25f2..2a4ec937e 100644 --- a/LEAF_Request_Portal/sources/View.php +++ b/LEAF_Request_Portal/sources/View.php @@ -61,7 +61,7 @@ public function buildViewStatus(int $recordID): array $vars = array(':recordID' => $recordID); $sql1 = 'SELECT time, description, actionText, stepTitle, - dependencyID, comment, userID + dependencyID, comment, userID, userMetadata FROM action_history LEFT JOIN dependencies USING (dependencyID) LEFT JOIN workflow_steps USING (stepID) @@ -69,13 +69,13 @@ public function buildViewStatus(int $recordID): array WHERE recordID=:recordID UNION SELECT timestamp, "Note Added", "N/A", "N/A", - "N/A", note, userID + "N/A", note, userID, userMetadata FROM notes WHERE recordID = :recordID AND deleted IS NULL UNION SELECT `timestamp`, "Email Sent", "N/A", "N/A", - "N/A", concat(`recipients`, "
", `subject`), "" + "N/A", concat(`recipients`, "
", `subject`), "", "" FROM `email_tracker` WHERE recordID = :recordID ORDER BY time ASC'; @@ -102,8 +102,12 @@ public function buildViewStatus(int $recordID): array $packet['comment'] = $tmp['comment']; if (!empty($tmp['userID'])) { - $user = $dir->lookupLogin($tmp['userID']); - $name = isset($user[0]) ? "{$user[0]['Fname']} {$user[0]['Lname']}" : $tmp['userID']; + $name = $tmp['userID']; + if(isset($tmp['userMetadata'])) { + $umd = json_decode($tmp['userMetadata'], true); + $display = trim($umd['firstName'] . " " . $umd['lastName']); + $name = !empty($display) ? $display : $name; + } $packet['userName'] = $name; } diff --git a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl index f48ed746f..445aff1df 100644 --- a/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl +++ b/LEAF_Request_Portal/templates/reports/LEAF_Sitemap_Search.tpl @@ -198,6 +198,7 @@ function addHeader(column) { case 'dateCancelled': filterData['deleted'] = 1; filterData['action_history.approverName'] = 1; + filterData['action_history.actionType'] = 1; leafSearch.getLeafFormQuery().join('action_history'); headers.push({ name: 'Date Cancelled', indicatorID: 'dateCancelled', editable: false, callback: function(data, blob) { diff --git a/LEAF_Request_Portal/templates/view_reports.tpl b/LEAF_Request_Portal/templates/view_reports.tpl index 61b91ef80..6ac37fac9 100644 --- a/LEAF_Request_Portal/templates/view_reports.tpl +++ b/LEAF_Request_Portal/templates/view_reports.tpl @@ -140,6 +140,7 @@ function addHeader(column) { case 'dateCancelled': filterData['deleted'] = 1; filterData['action_history.approverName'] = 1; + filterData['action_history.actionType'] = 1; leafSearch.getLeafFormQuery().join('action_history'); headers.push({ name: 'Date Cancelled', indicatorID: 'dateCancelled', editable: false, callback: function(data, blob) { diff --git a/LEAF_Request_Portal/templates/view_status.tpl b/LEAF_Request_Portal/templates/view_status.tpl index bf2455c3b..1ea210cd7 100644 --- a/LEAF_Request_Portal/templates/view_status.tpl +++ b/LEAF_Request_Portal/templates/view_status.tpl @@ -26,12 +26,13 @@ Title of request: - by + + by -
Comment:
+
Comment: -
+
From 45bf0884968aa4b535f09072eee636af279fc89a Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Fri, 13 Dec 2024 10:18:32 -0500 Subject: [PATCH 08/16] LEAF 4455 simplify extract, add decode to query context --- LEAF_Request_Portal/sources/Form.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index cea57e765..c570e93a8 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3769,12 +3769,12 @@ public function query(string $inQuery): mixed if ($joinInitiatorNames) { $initiatorNamesSQL = ', IF( - JSON_EXTRACT(`userMetadata`, "$.userName") != "", - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.firstName")), "(inactive account)" + TRIM(JSON_VALUE(`userMetadata`, "$.userName")) != "", + JSON_VALUE(`userMetadata`, "$.firstName"), "(inactive account)" ) AS `firstName`, IF( - JSON_EXTRACT(`userMetadata`, "$.userName") != "", - TRIM(BOTH \'\"\' FROM JSON_EXTRACT(`userMetadata`, "$.lastName")), `userID` + TRIM(JSON_VALUE(`userMetadata`, "$.userName")) != "", + JSON_VALUE(`userMetadata`, "$.lastName"), `userID` ) AS `lastName`'; } $resSQL = 'SELECT * ' . $initiatorNamesSQL . ' FROM `records` ' . $joins . ' WHERE ' . $conditions . $sort . $limit; @@ -3808,6 +3808,7 @@ public function query(string $inQuery): mixed $recordIDs = ''; foreach ($res as $item) { + $item['userMetadata'] = json_decode($item['userMetadata'], true); if(!isset($data[$item['recordID']])) { $recordIDs .= $item['recordID'] . ','; } From cc32c66cd385ef882d70a1b23097f14596b1c0da Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Fri, 13 Dec 2024 15:11:03 -0500 Subject: [PATCH 09/16] LEAF 4455 decode action_history userMetadata --- LEAF_Request_Portal/sources/Form.php | 3 ++- LEAF_Request_Portal/sources/FormWorkflow.php | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index c570e93a8..82d87dcfd 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3897,7 +3897,8 @@ public function query(string $inQuery): mixed $res2 = $this->db->prepared_query($actionHistorySQL, array()); foreach ($res2 as $item) { - $userMetadata = json_decode($item['userMetadata'], true); + $item['userMetadata'] = json_decode($item['userMetadata'], true); + $userMetadata = $item['userMetadata']; $name = isset($userMetadata) && trim("{$userMetadata['firstName']} {$userMetadata['lastName']}") !== "" ? "{$userMetadata['firstName']} {$userMetadata['lastName']}" : $item['userID']; diff --git a/LEAF_Request_Portal/sources/FormWorkflow.php b/LEAF_Request_Portal/sources/FormWorkflow.php index 0c39dbc18..84b4b2ced 100644 --- a/LEAF_Request_Portal/sources/FormWorkflow.php +++ b/LEAF_Request_Portal/sources/FormWorkflow.php @@ -476,6 +476,7 @@ public function getRecordsDependencyData(object $form, array $records, bool $sel $groupDesignatedRecords = []; // map of records using "group designated" $groupDesignatedIndicators = []; // map of indicators using "group designated" foreach ($res as $i => $record) { + $res[$i]['userMetadata'] = json_decode($res[$i]['userMetadata'], true); // override access if user is in the admin group $res[$i]['isActionable'] = $this->login->checkGroup(1); // initialize isActionable @@ -711,12 +712,15 @@ public function getLastAction(): array|null|int LIMIT 1'; $res = $this->db->prepared_query($strSQL, $vars); } + if (isset($res[0])) { + $res[0]['userMetadata'] = json_decode($res[0]['userMetadata'], true); + } // dependencyID -1 is for a person designated by the requestor if (isset($res[0]) && $res[0]['dependencyID'] == -1) { - $approverMetadata = json_decode($res[0]['userMetadata'], true); + $approverMetadata = $res[0]['userMetadata']; $display = isset($approverMetadata) && trim($approverMetadata['firstName'] . " " . $approverMetadata['lastName'] ) !== '' ? $approverMetadata['firstName'] . " " . $approverMetadata['lastName'] : $res[0]['userID']; From 4c295395bdde0e2dbc8e508a71b851f76f1f1065 Mon Sep 17 00:00:00 2001 From: Jamie P Holcomb Date: Mon, 16 Dec 2024 08:23:08 -0500 Subject: [PATCH 10/16] Leaf 4376 - updates to disable users --- app/Leaf/VAMCActiveDirectory.php | 39 ++++++++++--------- scripts/disableNationalOrgchartEmpolyees.php | 17 ++++++++ .../updateNationalOrgchartEmployees.php | 24 ++++++++++++ 3 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 scripts/disableNationalOrgchartEmpolyees.php create mode 100644 scripts/scheduled-task-commands/updateNationalOrgchartEmployees.php diff --git a/app/Leaf/VAMCActiveDirectory.php b/app/Leaf/VAMCActiveDirectory.php index 1c070a802..b119bbd63 100644 --- a/app/Leaf/VAMCActiveDirectory.php +++ b/app/Leaf/VAMCActiveDirectory.php @@ -113,16 +113,15 @@ public function importADData($file) // import any remaining entries $this->importData(); + } + public function disableNationalOrgchartEmployees(): void + { // get all userNames that should be disabled $disableUsersList = $this->getUserNamesToBeDisabled(); - error_log(print_r($disableUsersList, true), 3, '/var/www/php-logs/errors.log'); - // Disable users not in this array - //$this->preventRecycledUserName($disableUsersList); - - + $this->preventRecycledUserName($disableUsersList); } // Imports data from \t and \n delimited file of format: @@ -250,35 +249,39 @@ private function getUserNamesToBeDisabled(): array $sql = 'SELECT `userName` FROM `employee` WHERE `deleted` = 0 - AND `lastUpdated` < (UNIX_TIMESTAMP(NOW() - 108000) '; + AND `lastUpdated` < (UNIX_TIMESTAMP(NOW() - 108000))'; $return_value = $this->db->prepared_query($sql, array()); return $return_value; } - private function getNewlyDeletedUsers($time): array + private function preventRecycledUserName(array $userNames): void { - $sql = 'SELECT `userName` - FROM `employee` - WHERE `userName` LIKE "disabled_{$time}_%"'; + /*$commaUserNames = implode(',', $userNames); + $deleteTime = time(); - $return_value = $this->db->prepared_query($sql, array()); + $vars = array(':deleteTime' => $deleteTime);*/ + $commaUserNames = ''; - return $return_value; - } + foreach ($userNames as $user) { + $commaUserNames .= '"' . $user['userName'] . '",'; + } - private function preventRecycledUserName(array $userNames): void - { - $commaUserNames = implode(',', $userNames); $deleteTime = time(); - $vars = array(':deleteTime' => $deleteTime); + $vars = array(':deleteTime' => $deleteTime, + ':userNames' => $commaUserNames); + error_log(print_r($vars, true), 3, '/var/www/php-logs/testing.log'); + /*$sql = 'UPDATE `employee` + SET `deleted` = :deleteTime, + `userName` = concat("disabled_", `deleted`, "_", `userName`) + WHERE `userName` IN ("' . implode('","', array_values($userNames)) . '")';*/ $sql = 'UPDATE `employee` SET `deleted` = :deleteTime, `userName` = concat("disabled_", `deleted`, "_", `userName`) - WHERE `userName` IN ("' . implode('","', array_values($userNames)) . '")'; + WHERE `userName` IN (:userNames)'; $this->db->prepared_query($sql, $vars); diff --git a/scripts/disableNationalOrgchartEmpolyees.php b/scripts/disableNationalOrgchartEmpolyees.php new file mode 100644 index 000000000..7d4117175 --- /dev/null +++ b/scripts/disableNationalOrgchartEmpolyees.php @@ -0,0 +1,17 @@ +disableNationalOrgchartEmployees(); + +$endTime = microtime(true); +$totalTime = round(($endTime - $startTime)/60, 2); + +error_log(print_r($file . " took " . $totalTime . " minutes to complete.", true), 3 , '/var/www/php-logs/ad_processing.log'); \ No newline at end of file diff --git a/scripts/scheduled-task-commands/updateNationalOrgchartEmployees.php b/scripts/scheduled-task-commands/updateNationalOrgchartEmployees.php new file mode 100644 index 000000000..39c3f867b --- /dev/null +++ b/scripts/scheduled-task-commands/updateNationalOrgchartEmployees.php @@ -0,0 +1,24 @@ +query($sql); + +function updateEmps($VISNS) { + foreach ($VISNS as $visn) { + if (str_starts_with($visn['data'], 'DN,')) { + exec("php /var/www/scripts/updateNationalOrgchart.php {$visn['cacheID']} > /dev/null 2>/dev/null &"); + echo "Deploying to: {$visn['cacheID']}\r\n"; + } + } + + exec ("php disableNationalOrgchartEmployees.php > /dev/null 2>/dev/null &"); +} + +updateEmps($VISNS); \ No newline at end of file From f8e9b426ca09ca026ab50dfcb0bbc79720d49f0d Mon Sep 17 00:00:00 2001 From: Jamie P Holcomb Date: Mon, 16 Dec 2024 09:56:16 -0500 Subject: [PATCH 11/16] Leaf 4376 - move a file --- .../disableNationalOrgchartEmployees.php} | 0 .../scheduled-task-commands/updateNationalOrgchartEmployees.php | 2 -- 2 files changed, 2 deletions(-) rename scripts/{disableNationalOrgchartEmpolyees.php => scheduled-task-commands/disableNationalOrgchartEmployees.php} (100%) diff --git a/scripts/disableNationalOrgchartEmpolyees.php b/scripts/scheduled-task-commands/disableNationalOrgchartEmployees.php similarity index 100% rename from scripts/disableNationalOrgchartEmpolyees.php rename to scripts/scheduled-task-commands/disableNationalOrgchartEmployees.php diff --git a/scripts/scheduled-task-commands/updateNationalOrgchartEmployees.php b/scripts/scheduled-task-commands/updateNationalOrgchartEmployees.php index 39c3f867b..87bbb96ed 100644 --- a/scripts/scheduled-task-commands/updateNationalOrgchartEmployees.php +++ b/scripts/scheduled-task-commands/updateNationalOrgchartEmployees.php @@ -17,8 +17,6 @@ function updateEmps($VISNS) { echo "Deploying to: {$visn['cacheID']}\r\n"; } } - - exec ("php disableNationalOrgchartEmployees.php > /dev/null 2>/dev/null &"); } updateEmps($VISNS); \ No newline at end of file From 2789a1a9cfcfb6cafd65c0e6cdf20702258b0702 Mon Sep 17 00:00:00 2001 From: Jamie P Holcomb Date: Mon, 16 Dec 2024 10:35:24 -0500 Subject: [PATCH 12/16] Leaf 4376 - rearrange update queries --- app/Leaf/VAMCActiveDirectory.php | 80 ++++++++++---------------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/app/Leaf/VAMCActiveDirectory.php b/app/Leaf/VAMCActiveDirectory.php index b119bbd63..8d3d6f9fd 100644 --- a/app/Leaf/VAMCActiveDirectory.php +++ b/app/Leaf/VAMCActiveDirectory.php @@ -258,74 +258,44 @@ private function getUserNamesToBeDisabled(): array private function preventRecycledUserName(array $userNames): void { - /*$commaUserNames = implode(',', $userNames); $deleteTime = time(); - $vars = array(':deleteTime' => $deleteTime);*/ - $commaUserNames = ''; - - foreach ($userNames as $user) { - $commaUserNames .= '"' . $user['userName'] . '",'; - } - - $deleteTime = time(); - - $vars = array(':deleteTime' => $deleteTime, - ':userNames' => $commaUserNames); - - error_log(print_r($vars, true), 3, '/var/www/php-logs/testing.log'); - /*$sql = 'UPDATE `employee` - SET `deleted` = :deleteTime, - `userName` = concat("disabled_", `deleted`, "_", `userName`) - WHERE `userName` IN ("' . implode('","', array_values($userNames)) . '")';*/ + $vars = array(':deleteTime' => $deleteTime); $sql = 'UPDATE `employee` SET `deleted` = :deleteTime, `userName` = concat("disabled_", `deleted`, "_", `userName`) - WHERE `userName` IN (:userNames)'; + WHERE `userName` = :userNames; - $this->db->prepared_query($sql, $vars); + UPDATE `employee_data` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName; - foreach ($userNames as $name) { - $vars[':userName'] = $name; - $sql = 'UPDATE `employee_data` - SET `author` = concat("disabled_", :deleteTime, "_", :userName) - WHERE `author` = :userName'; + UPDATE `employee_data_history` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName; - $this->db->prepared_query($sql, $vars); + UPDATE `group_data` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName; - $sql = 'UPDATE `employee_data_history` - SET `author` = concat("disabled_", :deleteTime, "_", :userName) - WHERE `author` = :userName'; + UPDATE `group_data_history` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName; - $this->db->prepared_query($sql, $vars); + UPDATE `position_data` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName; - $sql = 'UPDATE `group_data` - SET `author` = concat("disabled_", :deleteTime, "_", :userName) - WHERE `author` = :userName'; + UPDATE `position_data_history` + SET `author` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `author` = :userName; - $this->db->prepared_query($sql, $vars); - - $sql = 'UPDATE `group_data_history` - SET `author` = concat("disabled_", :deleteTime, "_", :userName) - WHERE `author` = :userName'; - - $this->db->prepared_query($sql, $vars); - - $sql = 'UPDATE `position_data` - SET `author` = concat("disabled_", :deleteTime, "_", :userName) - WHERE `author` = :userName'; + UPDATE `relation_employee_backup` + SET `approverUserName` = concat("disabled_", :deleteTime, "_", :userName) + WHERE `approverUserName` = :userName;'; - $this->db->prepared_query($sql, $vars); - - $sql = 'UPDATE `position_data_history` - SET `author` = concat("disabled_", :deleteTime, "_", :userName) - WHERE `author` = :userName'; - - $this->db->prepared_query($sql, $vars); - - $sql = 'UPDATE `relation_employee_backup` - SET `author` = concat("disabled_", :deleteTime, "_", :userName) - WHERE `approverUserName` = :userName'; + foreach ($userNames as $user) { + $vars[':userName'] = $user['userName']; $this->db->prepared_query($sql, $vars); } From 0f19510cb46c3840705a7751167b0f64fbbaabc9 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Mon, 16 Dec 2024 13:40:50 -0500 Subject: [PATCH 13/16] LEAF 4455 inactive user verbiage --- LEAF_Request_Portal/sources/Form.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index 82d87dcfd..b18f18db1 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3764,13 +3764,13 @@ public function query(string $inQuery): mixed //joinInitiatorNames backwards compat - additional SQL for records.userMetadata replaces previous join with orgchart.employee. //userMetadata properties are empty for accounts that were inactive when prior metadata values were updated. - //Alternatives here display 'userID (inactive account)' instead of 'null, null' if metadata is empty. + //Alternatives here display 'userID (inactive user)' instead of 'null, null' if metadata is empty. $initiatorNamesSQL = ''; if ($joinInitiatorNames) { $initiatorNamesSQL = ', IF( TRIM(JSON_VALUE(`userMetadata`, "$.userName")) != "", - JSON_VALUE(`userMetadata`, "$.firstName"), "(inactive account)" + JSON_VALUE(`userMetadata`, "$.firstName"), "(inactive user)" ) AS `firstName`, IF( TRIM(JSON_VALUE(`userMetadata`, "$.userName")) != "", From 6252a54911db11dc4357e8a1875dc4bf69104343 Mon Sep 17 00:00:00 2001 From: Carrie Hanscom Date: Mon, 16 Dec 2024 15:39:27 -0500 Subject: [PATCH 14/16] LEAF 4455 test initiator empties again lastName since userName might be removed from metadata fields in the future --- LEAF_Request_Portal/sources/Form.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/LEAF_Request_Portal/sources/Form.php b/LEAF_Request_Portal/sources/Form.php index b18f18db1..16a9211e0 100644 --- a/LEAF_Request_Portal/sources/Form.php +++ b/LEAF_Request_Portal/sources/Form.php @@ -3762,18 +3762,18 @@ public function query(string $inQuery): mixed } - //joinInitiatorNames backwards compat - additional SQL for records.userMetadata replaces previous join with orgchart.employee. - //userMetadata properties are empty for accounts that were inactive when prior metadata values were updated. - //Alternatives here display 'userID (inactive user)' instead of 'null, null' if metadata is empty. + //joinInitiatorNames backwards compat - additional SQL for records.userMetadata replaces the previous join with orgchart.employee. + //userMetadata properties are empty for accounts that were inactive when prior metadata values were updated. Use lastName to check if empty + //because userName might be removed in the future. Display 'userID (inactive user)' instead of 'null, null' if metadata is empty. $initiatorNamesSQL = ''; if ($joinInitiatorNames) { $initiatorNamesSQL = ', IF( - TRIM(JSON_VALUE(`userMetadata`, "$.userName")) != "", + TRIM(JSON_VALUE(`userMetadata`, "$.lastName")) != "", JSON_VALUE(`userMetadata`, "$.firstName"), "(inactive user)" ) AS `firstName`, IF( - TRIM(JSON_VALUE(`userMetadata`, "$.userName")) != "", + TRIM(JSON_VALUE(`userMetadata`, "$.lastName")) != "", JSON_VALUE(`userMetadata`, "$.lastName"), `userID` ) AS `lastName`'; } From 9c6e9beaee5ba791c9fe3f105e01fdd9f43f7c0f Mon Sep 17 00:00:00 2001 From: Jamie P Holcomb Date: Tue, 17 Dec 2024 11:47:23 -0500 Subject: [PATCH 15/16] Leaf 4376 - update queries --- app/Leaf/VAMCActiveDirectory.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Leaf/VAMCActiveDirectory.php b/app/Leaf/VAMCActiveDirectory.php index 8d3d6f9fd..4755f90f3 100644 --- a/app/Leaf/VAMCActiveDirectory.php +++ b/app/Leaf/VAMCActiveDirectory.php @@ -249,7 +249,7 @@ private function getUserNamesToBeDisabled(): array $sql = 'SELECT `userName` FROM `employee` WHERE `deleted` = 0 - AND `lastUpdated` < (UNIX_TIMESTAMP(NOW() - 108000))'; + AND `lastUpdated` < (UNIX_TIMESTAMP(NOW()) - 108000)'; $return_value = $this->db->prepared_query($sql, array()); @@ -264,7 +264,7 @@ private function preventRecycledUserName(array $userNames): void $sql = 'UPDATE `employee` SET `deleted` = :deleteTime, `userName` = concat("disabled_", `deleted`, "_", `userName`) - WHERE `userName` = :userNames; + WHERE `userName` = :userName; UPDATE `employee_data` SET `author` = concat("disabled_", :deleteTime, "_", :userName) From 99f4bc8bcbabac3b1f8372cd9af7e8d54dc916d5 Mon Sep 17 00:00:00 2001 From: Jamie P Holcomb Date: Tue, 17 Dec 2024 13:35:22 -0500 Subject: [PATCH 16/16] Leaf 4376 - adding type hints --- app/Leaf/VAMCActiveDirectory.php | 73 ++------------------------------ 1 file changed, 4 insertions(+), 69 deletions(-) diff --git a/app/Leaf/VAMCActiveDirectory.php b/app/Leaf/VAMCActiveDirectory.php index 4755f90f3..56a89ec8d 100644 --- a/app/Leaf/VAMCActiveDirectory.php +++ b/app/Leaf/VAMCActiveDirectory.php @@ -42,7 +42,7 @@ public function __construct($national_db) // Imports data from \t and \n delimited file of format: // Name Business Phone Description Modified E-Mail Address User Logon Name - public function importADData($file) + public function importADData(string $file): string { $data = $this->getData($file); $rawdata = explode("\r\n", $data[0]['data']); @@ -126,7 +126,7 @@ public function disableNationalOrgchartEmployees(): void // Imports data from \t and \n delimited file of format: // Lname\t Fname Mid_Initial\t Email\t Phone\t Pager\t Room#\t Title\t Service\t MailCode\n - public function importData() + public function importData(): void { $time = time(); $sql1 = 'INSERT INTO employee (userName, lastName, firstName, middleName, phoneticFirstName, phoneticLastName, domain, lastUpdated, new_empUUID) @@ -333,7 +333,7 @@ private function trimField2(string &$value, string $key): void // workaround for excel // author: tajhlande at gmail dot com - private function splitWithEscape($str, $delimiterChar = ',', $escapeChar = '"') + private function splitWithEscape(string $str, string $delimiterChar = ',', string $escapeChar = '"'): array { $len = strlen($str); $tokens = array(); @@ -383,73 +383,8 @@ private function splitWithEscape($str, $delimiterChar = ',', $escapeChar = '"') return $tokens; } - private function parseVAdomain($adPath) - { - $dc = ''; - $dcSrc = explode(',', $adPath); - - foreach ($dcSrc as $adElement) { - if (strpos($adElement, 'DC=') !== false) { - $dc .= substr($adElement, 3) . '.'; - } - } - - $dc = trim($dc, '.'); - - switch ($dc) { - case 'v01.med.va.gov': - return 'VHA01'; - case 'v02.med.va.gov': - return 'VHA02'; - case 'v03.med.va.gov': - return 'VHA03'; - case 'v04.med.va.gov': - return 'VHA04'; - case 'v05.med.va.gov': - return 'VHA05'; - case 'v06.med.va.gov': - return 'VHA06'; - case 'v07.med.va.gov': - return 'VHA07'; - case 'v08.med.va.gov': - return 'VHA08'; - case 'v09.med.va.gov': - return 'VHA09'; - case 'v10.med.va.gov': - return 'VHA10'; - case 'v11.med.va.gov': - return 'VHA11'; - case 'v12.med.va.gov': - return 'VHA12'; - case 'v13.med.va.gov': - return 'VHA13'; - case 'v14.med.va.gov': - return 'VHA14'; - case 'v15.med.va.gov': - return 'VHA15'; - case 'v16.med.va.gov': - return 'VHA16'; - case 'v17.med.va.gov': - return 'VHA17'; - case 'v18.med.va.gov': - return 'VHA18'; - case 'v19.med.va.gov': - return 'VHA19'; - case 'v20.med.va.gov': - return 'VHA20'; - case 'v21.med.va.gov': - return 'VHA21'; - case 'v22.med.va.gov': - return 'VHA22'; - case 'v23.med.va.gov': - return 'VHA23'; - default: - return $dc; - } - } - //tests stringToFix for format X'...', if it matches, it's a hex value, is decoded and returned - private function fixIfHex($stringToFix) + private function fixIfHex(string $stringToFix): string { if (substr( $stringToFix, 0, 2 ) === "X'") { $stringToFix = ltrim($stringToFix, "X'");