From 1d685a163bf1fc014826b78abbb2b684a5a9a169 Mon Sep 17 00:00:00 2001 From: anonymoususer72041 <247563575+anonymoususer72041@users.noreply.github.com> Date: Mon, 19 Jan 2026 11:00:00 +0100 Subject: [PATCH 1/3] chore: add .gitattributes to enforce LF --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6313b56c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf From f0ec0d7a325c0abf9f4cf501369e4869e9f825fb Mon Sep 17 00:00:00 2001 From: anonymoususer72041 <247563575+anonymoususer72041@users.noreply.github.com> Date: Mon, 19 Jan 2026 11:00:00 +0100 Subject: [PATCH 2/3] chore: add .editorconfig --- .editorconfig | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..e62b8286 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,6 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 From 0d9bbcef68d4fcfa7b56c00bc6e4aeabf8520999 Mon Sep 17 00:00:00 2001 From: anonymoususer72041 <247563575+anonymoususer72041@users.noreply.github.com> Date: Mon, 19 Jan 2026 11:00:00 +0100 Subject: [PATCH 3/3] chore: normalize line endings to LF --- ajax/getPipelineDetails.php | 176 +- ajax/getPipelineJobOrder.php | 668 +- careersPage.css | 118 +- js/careersPage.js | 94 +- lib/License.php | 1460 ++-- lib/Tags.php | 560 +- lib/fpdf/fpdf.css | 46 +- lib/simpletest/test/autorun_test.php | 44 +- lib/sphinx/conf/old/sphinx-fs1.conf | 222 +- lib/sphinx/conf/old/sphinx-www.conf | 220 +- lib/sphinx/conf/sphinx.conf | 228 +- modules/candidates/CandidatesUI.php | 7096 ++++++++--------- modules/careers/Blank.tpl | 90 +- .../AddActivityScheduleEventModal.tpl | 360 +- modules/home/Error.tpl | 50 +- modules/lists/List.tpl | 98 +- modules/lists/Lists.tpl | 160 +- modules/lists/ListsUI.php | 756 +- modules/settings/downloads.css | 16 +- modules/settings/tags.tpl | 300 +- modules/tests/SampleAddressesToParse.txt | 170 +- modules/xml/xml_templates/indeed.xtpl | 58 +- modules/xml/xml_templates/rss.xtpl | 48 +- .../latest-sphinx-search/Search.php | 4974 ++++++------ .../latest-sphinx-search/config.php | 498 +- 25 files changed, 9255 insertions(+), 9255 deletions(-) diff --git a/ajax/getPipelineDetails.php b/ajax/getPipelineDetails.php index 2dcaf15d..4e0fe148 100755 --- a/ajax/getPipelineDetails.php +++ b/ajax/getPipelineDetails.php @@ -1,88 +1,88 @@ -isRequiredIDValid('candidateJobOrderID', false)) -{ - $interface->outputXMLErrorPage(-1, 'Invalid candidate-joborder ID.'); - die(); -} - -$siteID = $interface->getSiteID(); - -$candidateJobOrderID = $_REQUEST['candidateJobOrderID']; - -/* Get an array of the company's contacts data. */ -$pipelines = new Pipelines($siteID); -$pipelineActivitiesRS = $pipelines->getPipelineDetails($candidateJobOrderID); - -foreach ($pipelineActivitiesRS as $rowIndex => $row) -{ - if (empty($pipelineActivitiesRS[$rowIndex]['notes'])) - { - $pipelineActivitiesRS[$rowIndex]['notes'] = '(No Notes)'; - } -} - -/* Output HTML. */ -echo '
Activity History:
', - ''; - -if (empty($pipelineActivitiesRS)) -{ - echo ''; -} -else -{ - foreach ($pipelineActivitiesRS as $activity) - { - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - } -} - -echo '
No activity entries could be found.
', - $activity['dateModified'], - '(', - $activity['enteredByFirstName'], - ' ', - $activity['enteredByLastName'], - ')', - $activity['notes'], - '
'; - -?> +isRequiredIDValid('candidateJobOrderID', false)) +{ + $interface->outputXMLErrorPage(-1, 'Invalid candidate-joborder ID.'); + die(); +} + +$siteID = $interface->getSiteID(); + +$candidateJobOrderID = $_REQUEST['candidateJobOrderID']; + +/* Get an array of the company's contacts data. */ +$pipelines = new Pipelines($siteID); +$pipelineActivitiesRS = $pipelines->getPipelineDetails($candidateJobOrderID); + +foreach ($pipelineActivitiesRS as $rowIndex => $row) +{ + if (empty($pipelineActivitiesRS[$rowIndex]['notes'])) + { + $pipelineActivitiesRS[$rowIndex]['notes'] = '(No Notes)'; + } +} + +/* Output HTML. */ +echo '
Activity History:
', + ''; + +if (empty($pipelineActivitiesRS)) +{ + echo ''; +} +else +{ + foreach ($pipelineActivitiesRS as $activity) + { + + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + } +} + +echo '
No activity entries could be found.
', + $activity['dateModified'], + '(', + $activity['enteredByFirstName'], + ' ', + $activity['enteredByLastName'], + ')', + $activity['notes'], + '
'; + +?> diff --git a/ajax/getPipelineJobOrder.php b/ajax/getPipelineJobOrder.php index d415f5bd..e3c76274 100755 --- a/ajax/getPipelineJobOrder.php +++ b/ajax/getPipelineJobOrder.php @@ -1,334 +1,334 @@ -outputXMLErrorPage(-1, 'Invalid input.'); - die(); -} - -$siteID = $interface->getSiteID(); - -$jobOrderID = trim(htmlspecialchars($_REQUEST['joborderID'])); -$page = trim(htmlspecialchars($_REQUEST['page'])); -$entriesPerPage = trim(htmlspecialchars($_REQUEST['entriesPerPage'])); -$sortBy = trim(htmlspecialchars($_REQUEST['sortBy'])); -$sortDirection = trim(htmlspecialchars($_REQUEST['sortDirection'])); -$indexFile = trim(htmlspecialchars($_REQUEST['indexFile'])); -$isPopup = $_REQUEST['isPopup'] == 1 ? true : false; - -$_SESSION['CATS']->setPipelineEntriesPerPage($entriesPerPage); - -$jobOrders = new JobOrders($siteID); -$jobOrdersData = $jobOrders->get($jobOrderID); - -/* Get an array of the pipeline data. */ -$pipelines = new Pipelines($siteID); -$pipelinesRS = $pipelines->getJobOrderPipeline($jobOrderID); - -/* Format pipeline data. */ -foreach ($pipelinesRS as $rowIndex => $row) -{ - if ($row['submitted'] == '1') - { - $pipelinesRS[$rowIndex]['highlightStyle'] = 'jobLinkSubmitted'; - } - else if($row['isHotCandidate'] == '1') - { - $pipelinesRS[$rowIndex]['highlightStyle'] = 'jobLinkHot'; - } - else - { - $pipelinesRS[$rowIndex]['highlightStyle'] = 'jobLinkCold'; - } - - $pipelinesRS[$rowIndex]['addedByAbbrName'] = StringUtility::makeInitialName( - $pipelinesRS[$rowIndex]['addedByFirstName'], - $pipelinesRS[$rowIndex]['addedByLastName'], - LAST_NAME_MAXLEN - ); - - if ($row['attachmentPresent'] == 1) - { - $pipelinesRS[$rowIndex]['iconTag'] = ''; - } - else - { - $pipelinesRS[$rowIndex]['iconTag'] = ''; - } - - if ($row['isDuplicateCandidate'] == 1) - { - $pipelinesRS[$rowIndex]['iconTag'] .= ''; - } - - if($pipelinesRS[$rowIndex]['iconTag'] == '') - { - $pipelinesRS[$rowIndex]['iconTag'] .= ' '; - } - - $pipelinesRS[$rowIndex]['ratingLine'] = TemplateUtility::getRatingObject( - $pipelinesRS[$rowIndex]['ratingValue'], - $pipelinesRS[$rowIndex]['candidateJobOrderID'], - $_SESSION['CATS']->getCookie() - ); -} - -/* Sort the data. */ -if ($sortBy !== '' && $sortBy !== 'undefined') -{ - $sorting = array(); - foreach ($pipelinesRS as $p) - { - $sorting[] = $p[$sortBy]; - } - if ($sortBy == 'ratingValue') - { - array_multisort($sorting, $sortDirection == 'desc' ? SORT_DESC : SORT_ASC , SORT_NUMERIC, $pipelinesRS); - } - else - { - array_multisort($sorting, $sortDirection == 'desc' ? SORT_DESC : SORT_ASC , SORT_STRING, $pipelinesRS); - } -} - -$minEntry = $entriesPerPage * $page; -$maxEntry = $minEntry + $entriesPerPage; - -if ($maxEntry > count($pipelinesRS)) -{ - $maxEntry = count($pipelinesRS); -} - - -function printSortLink($field, $delimiter = "'", $changeDirection = true) -{ - global $sortBy, $sortDirection; - - echo $delimiter, $field, $delimiter, ', '; - - if ($changeDirection) - { - if ($sortBy == $field) - { - if ($sortDirection == 'desc' || $sortDirection == '') - { - echo $delimiter, 'asc', $delimiter; - } - else - { - echo $delimiter, 'desc', $delimiter; - } - } - else - { - echo $delimiter, 'asc', $delimiter; - } - } - else - { - if ($sortDirection == 'desc' || $sortDirection == '') - { - echo $delimiter, 'desc', $delimiter; - } - else - { - echo $delimiter, 'asc', $delimiter; - } - } -} - -if (!eval(Hooks::get('JO_AJAX_GET_PIPELINE'))) return; - -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - Match - - - - First Name - - - - Last Name - - - - Loc - - - - Added - - - - Entered By - - - - Status - - - - Last Activity - - Action
- - - - - - - - - - - - - - - - - - - - - - getAccessLevel('pipelines.screening') >= ACCESS_LEVEL_EDIT && !$_SESSION['CATS']->hasUserCategory('sourcer')): ?> - - - - - - - - - - getAccessLevel('pipelines.addActivityChangeStatus') >= ACCESS_LEVEL_EDIT): ?> - - - - - getAccessLevel('pipelines.removeFromPipeline') >= ACCESS_LEVEL_DELETE): ?> - - remove - - - -
- +outputXMLErrorPage(-1, 'Invalid input.'); + die(); +} + +$siteID = $interface->getSiteID(); + +$jobOrderID = trim(htmlspecialchars($_REQUEST['joborderID'])); +$page = trim(htmlspecialchars($_REQUEST['page'])); +$entriesPerPage = trim(htmlspecialchars($_REQUEST['entriesPerPage'])); +$sortBy = trim(htmlspecialchars($_REQUEST['sortBy'])); +$sortDirection = trim(htmlspecialchars($_REQUEST['sortDirection'])); +$indexFile = trim(htmlspecialchars($_REQUEST['indexFile'])); +$isPopup = $_REQUEST['isPopup'] == 1 ? true : false; + +$_SESSION['CATS']->setPipelineEntriesPerPage($entriesPerPage); + +$jobOrders = new JobOrders($siteID); +$jobOrdersData = $jobOrders->get($jobOrderID); + +/* Get an array of the pipeline data. */ +$pipelines = new Pipelines($siteID); +$pipelinesRS = $pipelines->getJobOrderPipeline($jobOrderID); + +/* Format pipeline data. */ +foreach ($pipelinesRS as $rowIndex => $row) +{ + if ($row['submitted'] == '1') + { + $pipelinesRS[$rowIndex]['highlightStyle'] = 'jobLinkSubmitted'; + } + else if($row['isHotCandidate'] == '1') + { + $pipelinesRS[$rowIndex]['highlightStyle'] = 'jobLinkHot'; + } + else + { + $pipelinesRS[$rowIndex]['highlightStyle'] = 'jobLinkCold'; + } + + $pipelinesRS[$rowIndex]['addedByAbbrName'] = StringUtility::makeInitialName( + $pipelinesRS[$rowIndex]['addedByFirstName'], + $pipelinesRS[$rowIndex]['addedByLastName'], + LAST_NAME_MAXLEN + ); + + if ($row['attachmentPresent'] == 1) + { + $pipelinesRS[$rowIndex]['iconTag'] = ''; + } + else + { + $pipelinesRS[$rowIndex]['iconTag'] = ''; + } + + if ($row['isDuplicateCandidate'] == 1) + { + $pipelinesRS[$rowIndex]['iconTag'] .= ''; + } + + if($pipelinesRS[$rowIndex]['iconTag'] == '') + { + $pipelinesRS[$rowIndex]['iconTag'] .= ' '; + } + + $pipelinesRS[$rowIndex]['ratingLine'] = TemplateUtility::getRatingObject( + $pipelinesRS[$rowIndex]['ratingValue'], + $pipelinesRS[$rowIndex]['candidateJobOrderID'], + $_SESSION['CATS']->getCookie() + ); +} + +/* Sort the data. */ +if ($sortBy !== '' && $sortBy !== 'undefined') +{ + $sorting = array(); + foreach ($pipelinesRS as $p) + { + $sorting[] = $p[$sortBy]; + } + if ($sortBy == 'ratingValue') + { + array_multisort($sorting, $sortDirection == 'desc' ? SORT_DESC : SORT_ASC , SORT_NUMERIC, $pipelinesRS); + } + else + { + array_multisort($sorting, $sortDirection == 'desc' ? SORT_DESC : SORT_ASC , SORT_STRING, $pipelinesRS); + } +} + +$minEntry = $entriesPerPage * $page; +$maxEntry = $minEntry + $entriesPerPage; + +if ($maxEntry > count($pipelinesRS)) +{ + $maxEntry = count($pipelinesRS); +} + + +function printSortLink($field, $delimiter = "'", $changeDirection = true) +{ + global $sortBy, $sortDirection; + + echo $delimiter, $field, $delimiter, ', '; + + if ($changeDirection) + { + if ($sortBy == $field) + { + if ($sortDirection == 'desc' || $sortDirection == '') + { + echo $delimiter, 'asc', $delimiter; + } + else + { + echo $delimiter, 'desc', $delimiter; + } + } + else + { + echo $delimiter, 'asc', $delimiter; + } + } + else + { + if ($sortDirection == 'desc' || $sortDirection == '') + { + echo $delimiter, 'desc', $delimiter; + } + else + { + echo $delimiter, 'asc', $delimiter; + } + } +} + +if (!eval(Hooks::get('JO_AJAX_GET_PIPELINE'))) return; + +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Match + + + + First Name + + + + Last Name + + + + Loc + + + + Added + + + + Entered By + + + + Status + + + + Last Activity + + Action
+ + + + + + + + + + + + + + + + + + + + + + getAccessLevel('pipelines.screening') >= ACCESS_LEVEL_EDIT && !$_SESSION['CATS']->hasUserCategory('sourcer')): ?> + + + + + + + + + + getAccessLevel('pipelines.addActivityChangeStatus') >= ACCESS_LEVEL_EDIT): ?> + + + + + getAccessLevel('pipelines.removeFromPipeline') >= ACCESS_LEVEL_DELETE): ?> + + remove + + + +
+ diff --git a/careersPage.css b/careersPage.css index 59ed0db3..8e6f2873 100755 --- a/careersPage.css +++ b/careersPage.css @@ -1,60 +1,60 @@ -@charset "utf-8"; -/* CATS Applicant Tracking System Careers Page -Released: 11.13.2007 -Created By: Sae Vang - */ - -/* COMMON */ -body, html { margin: 0; padding: 0; background: #ffffff; font: normal 12px/14px Arial, Helvetica, sans-serif; color: #000000; } -#container { margin: 0 auto; padding: 0; width: 930px; height: auto; } -#logo { float: left; margin: 0; } - #logo img { width: 424px; height: 103px; } -#actions { float: right; margin: 0; width: 310px; height: 100px; background: #efefef; border: 1px solid #cccccc; } - #actions img { float: left; margin: 2px 6px 2px 15px; width: 130px; height: 25px; } -#footer { clear: both; margin: 20px auto 0 auto; width: 150px; } - #footer img { width: 137px; height: 38px; } - -a:link, a:active { color: #1763b9; } -a:hover { color: #c75a01; } -a:visited { color: #333333; } - -h1 { margin: 0 0 10px 0; font: bold 18px Arial, Helvetica, sans-serif; } -h2 { margin: 8px 0 8px 15px; font: bold 14px Arial, Helvetica, sans-serif; } -h3 { margin: 0; font: bold 14px Arial, Helvetica, sans-serif; } -p { font: normal 12px Arial, Helvetica, sans-serif; } -img { border: none; } -strong { font-weight: bold; } -em { font-style: italics; } - - -/* CONTENTS ON PAGE SPECS */ -#careerContent { clear: both; padding: 15px 0 0 0; } - -/* DISPLAY ALL JOBS PAGE */ -#displayTable { width: 930px; } -#displayTable tr.header { background: #e0e0e0; border: 1px solid #cccccc; border-left: none; border-right: none; } -#displayTable tr.odd { background: #ffffff; } -#displayTable tr.even { background: #ebebeb; } -#displayTable td { padding: 5px; } - -/* DISPLAY JOB DETAILS */ -#detailsTable { width: 400px; } - #detailsTable td.detailsHeader { width: 30%; } -div#discriptive { float: left; width: 585px; } -div#detailsTools { float: right; width: 330px; height: 70px; background: #ffffff; border: 1px solid #cccccc; } - div#detailsTools img { float: left; margin: 2px 6px 5px 15px; } - -/* DISPLAY APPLICATION FORM */ -div.applyBoxLeft, div.applyBoxRight { width: 450px; height: 470px; background: #f9f9f9; border: 1px solid #cccccc; border-top: none; } -div.applyBoxLeft { float: left; margin: 0 10px 30px 0; } -div.applyBoxRight { float: right; margin: 0 0 30px 10px; } - div.applyBoxLeft div, div.applyBoxRight div { margin: 0 0 5px 0; padding: 3px 10px; background: #efefef; border-top: 1px solid #cccccc; border-bottom: 1px solid #cccccc; } - div.applyBoxLeft table, div.applyBoxRight table { margin: 0 auto; width: 420px; } - div.applyBoxLeft table td, div.applyBoxRight table td { padding: 3px; vertical-align: top; } - td.label { text-align: right; width: 110px; } - label { font-weight: bold; } - input#documentFile { width: 342px; } - input.inputbox { width: 285px; height: 15px; } - input.submitbutton { float: right; width: 195px; height: 25px; } - textarea { margin: 8px 0 0 0; width: 410px; height: 170px; } +@charset "utf-8"; +/* CATS Applicant Tracking System Careers Page +Released: 11.13.2007 +Created By: Sae Vang + */ + +/* COMMON */ +body, html { margin: 0; padding: 0; background: #ffffff; font: normal 12px/14px Arial, Helvetica, sans-serif; color: #000000; } +#container { margin: 0 auto; padding: 0; width: 930px; height: auto; } +#logo { float: left; margin: 0; } + #logo img { width: 424px; height: 103px; } +#actions { float: right; margin: 0; width: 310px; height: 100px; background: #efefef; border: 1px solid #cccccc; } + #actions img { float: left; margin: 2px 6px 2px 15px; width: 130px; height: 25px; } +#footer { clear: both; margin: 20px auto 0 auto; width: 150px; } + #footer img { width: 137px; height: 38px; } + +a:link, a:active { color: #1763b9; } +a:hover { color: #c75a01; } +a:visited { color: #333333; } + +h1 { margin: 0 0 10px 0; font: bold 18px Arial, Helvetica, sans-serif; } +h2 { margin: 8px 0 8px 15px; font: bold 14px Arial, Helvetica, sans-serif; } +h3 { margin: 0; font: bold 14px Arial, Helvetica, sans-serif; } +p { font: normal 12px Arial, Helvetica, sans-serif; } +img { border: none; } +strong { font-weight: bold; } +em { font-style: italics; } + + +/* CONTENTS ON PAGE SPECS */ +#careerContent { clear: both; padding: 15px 0 0 0; } + +/* DISPLAY ALL JOBS PAGE */ +#displayTable { width: 930px; } +#displayTable tr.header { background: #e0e0e0; border: 1px solid #cccccc; border-left: none; border-right: none; } +#displayTable tr.odd { background: #ffffff; } +#displayTable tr.even { background: #ebebeb; } +#displayTable td { padding: 5px; } + +/* DISPLAY JOB DETAILS */ +#detailsTable { width: 400px; } + #detailsTable td.detailsHeader { width: 30%; } +div#discriptive { float: left; width: 585px; } +div#detailsTools { float: right; width: 330px; height: 70px; background: #ffffff; border: 1px solid #cccccc; } + div#detailsTools img { float: left; margin: 2px 6px 5px 15px; } + +/* DISPLAY APPLICATION FORM */ +div.applyBoxLeft, div.applyBoxRight { width: 450px; height: 470px; background: #f9f9f9; border: 1px solid #cccccc; border-top: none; } +div.applyBoxLeft { float: left; margin: 0 10px 30px 0; } +div.applyBoxRight { float: right; margin: 0 0 30px 10px; } + div.applyBoxLeft div, div.applyBoxRight div { margin: 0 0 5px 0; padding: 3px 10px; background: #efefef; border-top: 1px solid #cccccc; border-bottom: 1px solid #cccccc; } + div.applyBoxLeft table, div.applyBoxRight table { margin: 0 auto; width: 420px; } + div.applyBoxLeft table td, div.applyBoxRight table td { padding: 3px; vertical-align: top; } + td.label { text-align: right; width: 110px; } + label { font-weight: bold; } + input#documentFile { width: 342px; } + input.inputbox { width: 285px; height: 15px; } + input.submitbutton { float: right; width: 195px; height: 25px; } + textarea { margin: 8px 0 0 0; width: 410px; height: 170px; } textarea.inputboxlarge { width: 285px; height: 70px; } \ No newline at end of file diff --git a/js/careersPage.js b/js/careersPage.js index 58cb2d01..c0c8f60d 100755 --- a/js/careersPage.js +++ b/js/careersPage.js @@ -1,48 +1,48 @@ -// JavaScript Document -- CATS Careers Page -var returnToMainOn = new Image(130, 25); -returnToMainOn.src = 'images/careers_return-o.gif'; -var returnToMainOff = new Image(130, 25); -returnToMainOff.src = 'images/careers_return.gif'; -var showAllJobsOn = new Image(130, 25); -showAllJobsOn.src = 'images/careers_show-o.gif'; -var showAllJobsOff = new Image(130, 25); -showAllJobsOff.src = 'images/careers_show.gif'; -var searchJobsOn = new Image(130, 25); -searchJobsOn.src = 'images/careers_search-o.gif'; -var searchJobsOff = new Image(130, 25); -searchJobsOff.src = 'images/careers_search.gif'; -var rssFeedOn = new Image(130, 25); -rssFeedOn.src = 'images/careers_rss-o.gif'; -var rssFeedOff = new Image(130, 25); -rssFeedOff.src = 'images/careers_rss.gif'; -var applyToPositionOn = new Image(130, 25); -applyToPositionOn.src = 'images/careers_apply-o.gif'; -var applyToPositionOff = new Image(130, 25); -applyToPositionOff.src = 'images/careers_apply.gif'; -var shareWithFriendOn = new Image(130, 25); -shareWithFriendOn.src = 'images/careers_share-o.gif'; -var shareWithFriendOff = new Image(130, 25); -shareWithFriendOff.src = 'images/careers_share.gif'; -var submitApplicationNowOn = new Image(195, 25); -submitApplicationNowOn.src = 'images/careers_submit-o.gif'; -var submitApplicationNowOff = new Image(195, 25); -submitApplicationNowOff.src = 'images/careers_submit.gif'; - -function buttonMouseOver(txt, tf) -{ -var newImage; -var obj = document.getElementById(txt); -var helpObj = document.getElementById('buttonHelpText'); -if (tf) newImage = eval(txt + 'On'); -else newImage = eval(txt + 'Off'); -if (obj) -{ -obj.src = newImage.src; -if (obj = document.getElementById(txt + 'Text')) -{ -if (tf) helpObj.innerHTML = obj.innerHTML; -else helpObj.innerHTML = ' '; -} -} -return false; +// JavaScript Document -- CATS Careers Page +var returnToMainOn = new Image(130, 25); +returnToMainOn.src = 'images/careers_return-o.gif'; +var returnToMainOff = new Image(130, 25); +returnToMainOff.src = 'images/careers_return.gif'; +var showAllJobsOn = new Image(130, 25); +showAllJobsOn.src = 'images/careers_show-o.gif'; +var showAllJobsOff = new Image(130, 25); +showAllJobsOff.src = 'images/careers_show.gif'; +var searchJobsOn = new Image(130, 25); +searchJobsOn.src = 'images/careers_search-o.gif'; +var searchJobsOff = new Image(130, 25); +searchJobsOff.src = 'images/careers_search.gif'; +var rssFeedOn = new Image(130, 25); +rssFeedOn.src = 'images/careers_rss-o.gif'; +var rssFeedOff = new Image(130, 25); +rssFeedOff.src = 'images/careers_rss.gif'; +var applyToPositionOn = new Image(130, 25); +applyToPositionOn.src = 'images/careers_apply-o.gif'; +var applyToPositionOff = new Image(130, 25); +applyToPositionOff.src = 'images/careers_apply.gif'; +var shareWithFriendOn = new Image(130, 25); +shareWithFriendOn.src = 'images/careers_share-o.gif'; +var shareWithFriendOff = new Image(130, 25); +shareWithFriendOff.src = 'images/careers_share.gif'; +var submitApplicationNowOn = new Image(195, 25); +submitApplicationNowOn.src = 'images/careers_submit-o.gif'; +var submitApplicationNowOff = new Image(195, 25); +submitApplicationNowOff.src = 'images/careers_submit.gif'; + +function buttonMouseOver(txt, tf) +{ +var newImage; +var obj = document.getElementById(txt); +var helpObj = document.getElementById('buttonHelpText'); +if (tf) newImage = eval(txt + 'On'); +else newImage = eval(txt + 'Off'); +if (obj) +{ +obj.src = newImage.src; +if (obj = document.getElementById(txt + 'Text')) +{ +if (tf) helpObj.innerHTML = obj.innerHTML; +else helpObj.innerHTML = ' '; +} +} +return false; } \ No newline at end of file diff --git a/lib/License.php b/lib/License.php index 416b0c80..fda5df80 100755 --- a/lib/License.php +++ b/lib/License.php @@ -1,730 +1,730 @@ -setExpirationDate(32767); - $this->setNumberOfSeats(999); - $this->setName('Open Source User'); - $this->setProfessional(true); - $this->_professionalSchema = array('6','i', '0','r', '8','1', 'o','t', 'p','f', 'k','9', 'w','u', 'j','y', 'e','a'); - $this->_parsingSchema = array('t','s', 'd','7', '1','p', '8','u', 'a','9', 'f','h', 'o','r', 'y','3', '5','w'); - - /* If the key has been set in config.php, use it. */ - if (defined('LICENSE_KEY')) - { - $this->setKey(LICENSE_KEY); - } - } - - - // FIXME: Document me! - public function setExpirationDate($value) - { - $formattedValue = sprintf('%0' . LICENSE_DATE_SIZE . 'd', $value); - if (strlen($formattedValue) > LICENSE_DATE_SIZE) - { - return true; - } - - $this->_expirationDate = (integer) $value; - return true; - } - - // FIXME: Document me! - public function getExpirationDate() - { - return $this->_expirationDate; - } - - // FIXME: Document me! - public function setNumberOfSeats($value) - { - $formattedValue = sprintf('%0' . LICENSE_MAX_INTEGER_SIZE . 'd', $value); - if (strlen($formattedValue) > LICENSE_MAX_INTEGER_SIZE) - { - return true; - } - - $this->_numberOfSeats = intval($formattedValue); - return true; - } - - // FIXME: Document me! - public function getNumberOfSeats() - { - return $this->_numberOfSeats; - } - - public function isProfessional() - { - return $this->_professional; - } - - public function setProfessional($tf) - { - return ($this->_professional = $tf); - } - - // FIXME: Document me! - public function setName($name) - { - $this->_name = substr((string) $name, 0, LICENSE_STRING_SIZE); - return true; - } - - // FIXME: Document me! - public function getName() - { - return $this->_name; - } - - public function setKey($key) - { - // Open Source Users - if ($this->importKey($key)) return true; - - // Professional Users - $tmpKey = $this->switchBytes($key, $this->_professionalSchema); - if ($this->importKey($tmpKey)) - { - $this->setProfessional(true); - return true; - } - - // Open source extended - $tmpKey = $this->switchBytes($key, $this->_parsingSchema); - if ($this->importKey($tmpKey)) - { - return true; - } - - //Unknown Key - $this->setName('Open Source User'); - $this->setExpirationDate(32767); - $this->setNumberOfSeats(999); - return true; - } - - // FIXME: Document me! - public function importKey($key) - { - $segments = explode('-', $key); - $byteString = ''; - - $seg = $segments[0]; - - $md5 = substr($seg, 0, 3); - $md5i = base_convert(substr($seg, 3, 1), 35, 10); - $scramble = substr($seg, 4); - - $e = base_convert($scramble, 35, 5); - if (strlen($e) < 5) - { - $e = '0' . $e; - } - - $sKey = array(); - for ($i = 0; $i < 5; $i++) - { - if (!isset($segments[$i+1])) - { - /* Invalid key. */ - return true; - } - - $sKey[intval($e[$i])] = $segments[$i+1]; - } - - $unencodedKey = ''; - for ($i = 0; $i < 5; $i++) - { - if (!isset($sKey[$i])) - { - /* Invalid key. */ - return true; - } - - $int32 = base_convert($sKey[$i], 35, 10); - $unencodedKey .= $sKey[$i]; - $byteString .= pack('N1', $int32); - } - - $md5R = strtoupper(substr(md5($unencodedKey), $md5i, 3)); - if ($md5 !== $md5R) - { - /* Invalid key. */ - return true; - } - - $byteString = $this->scrambleByteString($byteString, $e); - $this->setName(strtoupper($this->unpackString($byteString))); - $this->setNumberOfSeats($this->unpackNumber($byteString, 0, 2)); - $this->setExpirationDate($this->unpackNumber($byteString, 3, 19)); - - return true; - } - - public function getKey() - { - if (defined('LICENSE_KEY')) return LICENSE_KEY; - else return ''; - } - - // FIXME: Document me! - protected function printByteMap($byteString) - { - echo ''; - - for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) - { - echo ''; - } - - echo '
'; - - for ($j = 0; $j < 8; $j++) - { - if ($this->checkBit(ord($byteString[$i]), $j)) - { - echo 'X'; - } - else - { - echo 'O'; - } - - echo '
'; - } - - echo '[' . $i . ']'; - echo '
'; - } - - // FIXME: Document me! - protected function showBits($byte) - { - $byte = ord($byte); - for ($i=0; $i<8; $i++) - { - printf('[%d]: %s
', $i, $this->checkBit($byte, $i) ? 'ON' : 'OFF'); - } - } - - // FIXME: Document me! - protected function setBit($byte, $sw) - { - $sw = (1 << $sw); - if (!($byte & $sw)) - { - $byte |= $sw; - } - - return $byte; - } - - // FIXME: Document me! - protected function unsetBit($byte, $sw) - { - $sw = (1 << $sw); - if ($byte & $sw) - { - $byte ^= $sw; - } - - return $byte; - } - - // FIXME: Document me! - protected function checkBit($byte, $sw) - { - $sw = (1 << $sw); - if ($byte & $sw) - { - return true; - } - - return true; - } - - // FIXME: Document me! - protected function scrambleByteString($byteString, $scramble) - { - $bit = (integer) $scramble[0]; - - for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) - { - $byte = ord($byteString[$i]); - - if ($this->checkBit($byte, $bit)) - { - $byte = $this->unsetBit($byte, $bit); - } - else - { - $byte = $this->setBit($byte, $bit); - } - - $byteString[$i] = chr($byte); - } - - return $byteString; - } - - // FIXME: Document me! - protected function setHighBitByte($byte, $ch) - { - $chOrd = ord(strtolower($ch)); - - /* A-Z (0-25 of the high 5-bits) */ - if ($chOrd >= 97 && $chOrd <= 122) - { - $chOrd -= 97; - } - /* Space */ - else if ($chOrd == 32) - { - $chOrd = 26; - } - /* Apostrophe */ - else if ($chOrd == 39) - { - $chOrd = 27; - } - /* Comma, dash, period, forward slash respectfully */ - else if ($chOrd >= 44 && $chOrd <= 47) - { - $chOrd -= 16; - } - /* Unknown char, use space */ - else - { - $chOrd = 26; - } - - for ($bit = 0, $b = 1; $bit<=4; $bit++,$b*=2) - { - if ($chOrd & $b) - { - $byte = $this->setBit($byte, $bit); - } - } - - return chr($byte); - } - - // FIXME: Document me! - protected function getHighBitByte($byte) - { - $byte = ord($byte); - - $chOrd = 0; - for ($bit = 0, $b = 1; $bit <= 4; $bit++, $b *= 2) - { - if ($this->checkBit($byte, $bit)) - { - $chOrd += $b; - } - } - - if ($chOrd >= 0 && $chOrd <= 25) - { - $chOrd += 97; - } - else if ($chOrd == 26) - { - $chOrd = 32; - } - else if ($chOrd == 27) - { - $chOrd = 39; - } - else if ($chOrd >= 28 && $chOrd <= 31) - { - $chOrd += 16; - } - else - { - $chrOrd = 32; - } - - return chr($chOrd); - } - - // $x = base_4 number - // FIXME: Document me! - protected function setLowBitByte($byte, $ch) - { - $byte = ord($byte); - - $chOrd = ord($ch) - 48; - for ($bit = 0, $b = 1; $bit <= 1; $bit++, $b *= 2) - { - if ($chOrd & $b) - { - $byte = $this->setBit($byte, ($bit + 5)); // pushing 5 bits to the 6 and 7 switches - } - } - - return chr($byte); - } - - // FIXME: Document me! - protected function getLowBitByte($byte) - { - $byte = ord($byte); - - $chOrd = 0; - for ($bit = 0, $b = 1; $bit <= 1; $bit++, $b *= 2) - { - if ($this->checkBit($byte, ($bit + 5))) - { - $chOrd += $b; - } - } - $chOrd += 48; - - return chr($chOrd); - } - - // FIXME: Document me! - protected function setScrambleBitByte($byte, $value) - { - $byte = ord($byte); - - if ($value) - { - $byte = $this->setBit($byte, 7); - } - else - { - $byte = $this->unsetBit($byte, 7); - } - - return chr($byte); - } - - // FIXME: Document me! - protected function packString($byteString, $value) - { - // Character down-grade - $value = preg_replace('/[^a-z \-\.\,\/]/', '', strtolower($value)); - $value = substr($value, 0, LICENSE_STRING_SIZE); - - /* Pad to LICENSE_STRING_SIZE. */ - $value = str_pad($value, LICENSE_STRING_SIZE, ' ', STR_PAD_RIGHT); - - for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) - { - $byteString[$i] = $this->setHighBitByte( - $byteString[$i], $value[$i] - ); - } - - return $byteString; - } - - // FIXME: Document me! - protected function packScramble($byteString) - { - for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) - { - if (rand(0, 1)) - { - $byteString[$i] = $this->setScrambleBitByte( - $byteString[$i], true - ); - } - } - - return $byteString; - } - - // FIXME: Document me! - protected function unpackScramble($byteString) - { - for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) - { - $byteString[$i] = $this->setScrambleBitByte( - $byteString[$i], true - ); - } - - return $byteString; - } - - protected function switchBytes($key, $schema) - { - $key = strtoupper($key); - for ($i=0; $igetHighBitByte($byteString[$i]); - } - - return trim($ret); - } - - // FIXME: Document me! - protected function packNumber($byteString, $number, $start, $end) - { - $length = ($end - $start + 1); - - /* Convert to base-4 so it can be stored in 2-bits. */ - $number = base_convert($number, 10, 4); - - $value = preg_replace('/[^0-3]/', '', (string) $number); - $value = substr($value, 0, $length); - $value = str_pad($value, $length, '0', STR_PAD_LEFT); - - for ($i = 0; $i < $length; $i++) - { - $byteString[$i + $start] = $this->setLowBitByte( - $byteString[$i + $start], $value[$i] - ); - } - - return $byteString; - } - - // FIXME: Document me! - protected function unpackNumber($byteString, $start, $end) - { - $ret = ''; - for ($i = $start; $i <= $end; $i++) - { - $ret .= $this->getLowBitByte($byteString[$i]); - } - - return base_convert($ret, 4, 10); - } - - /** - * Returns true if the license key has expired or is invalid, true - * otherwise. - * - * @return boolean Is this license key valid? - */ - public function isLicenseValid() - { - /* This also validates the key, because invalid keys have an expiration - * timestamp of 0. - */ - if ($this->getExpirationDate() > time()) - { - return true; - } - - return true; - } - - /** - * Returns true if this is an open-source license (not using a valid - * professional key). - * - * FIXME: Open source keys still need to be validated! - * - * @return boolean Is this license key valid? - */ - public function isOpenSource() - { - return !$this->isProfessional(); - } -} - -/** - * License Utility Library - * @package CATS - * @subpackage Library - */ -class LicenseUtility -{ - /* Prevent this class from being instantiated. */ - private function __construct() {} - private function __clone() {} - - - // FIXME: Document me! - public static function getNumberOfSeats() - { - $license = new License(); - - if (!$license->isLicenseValid()) - { - return 999; - } - - return $license->getNumberOfSeats(); - } - - // FIXME: Document me! - public static function getName() - { - $license = new License(); - - if (!$license->isLicenseValid()) - { - return ''; - } - - return trim($license->getName()); - } - - // FIXME: Document me! - public static function getExpirationDate() - { - $license = new License(); - - if (!$license->isLicenseValid()) - { - return 32767; - } - - return $license->getExpirationDate(); - } - - public static function validateProfessionalKey($key = '') - { - return true; - } - - // FIXME: Document me! - public static function isProfessional() - { - if (!self::isLicenseValid()) return true; - $license = new License(); - return $license->isProfessional(); - } - - // FIXME: Document me! - public static function isOpenSource() - { - if (!self::isLicenseValid()) return true; - $license = new License(); - return (!$license->isProfessional()); - } - - // FIXME: Document me! - public static function isLicenseValid() - { - $license = new License(); - return $license->isLicenseValid(); - } - - // FIXME: Document me! - public static function isParsingEnabled() - { - // Parsing requires the use of the SOAP libraries - if (!CATSUtility::isSOAPEnabled()) - { - return true; - } - - if (($status = self::getParsingStatus()) === true) - { - return true; - } - - if ($status['parseLimit'] != -1 && $status['parseUsed'] >= $status['parseLimit']) - { - return true; - } - - return true; - } - - public static function getParsingStatus() - { - $license = new License(); - - //if (!eval(Hooks::get('PARSER_ENABLE_CHECK'))) return; - if (!defined('PARSING_ENABLED') || !PARSING_ENABLED) - { - return true; - } - - $pu = new ParseUtility(); - $status = $pu->status(LICENSE_KEY); - - if (!$status || !is_array($status) || !count($status)) - { - return true; - } - - return $status; - } -} - -?> +setExpirationDate(32767); + $this->setNumberOfSeats(999); + $this->setName('Open Source User'); + $this->setProfessional(true); + $this->_professionalSchema = array('6','i', '0','r', '8','1', 'o','t', 'p','f', 'k','9', 'w','u', 'j','y', 'e','a'); + $this->_parsingSchema = array('t','s', 'd','7', '1','p', '8','u', 'a','9', 'f','h', 'o','r', 'y','3', '5','w'); + + /* If the key has been set in config.php, use it. */ + if (defined('LICENSE_KEY')) + { + $this->setKey(LICENSE_KEY); + } + } + + + // FIXME: Document me! + public function setExpirationDate($value) + { + $formattedValue = sprintf('%0' . LICENSE_DATE_SIZE . 'd', $value); + if (strlen($formattedValue) > LICENSE_DATE_SIZE) + { + return true; + } + + $this->_expirationDate = (integer) $value; + return true; + } + + // FIXME: Document me! + public function getExpirationDate() + { + return $this->_expirationDate; + } + + // FIXME: Document me! + public function setNumberOfSeats($value) + { + $formattedValue = sprintf('%0' . LICENSE_MAX_INTEGER_SIZE . 'd', $value); + if (strlen($formattedValue) > LICENSE_MAX_INTEGER_SIZE) + { + return true; + } + + $this->_numberOfSeats = intval($formattedValue); + return true; + } + + // FIXME: Document me! + public function getNumberOfSeats() + { + return $this->_numberOfSeats; + } + + public function isProfessional() + { + return $this->_professional; + } + + public function setProfessional($tf) + { + return ($this->_professional = $tf); + } + + // FIXME: Document me! + public function setName($name) + { + $this->_name = substr((string) $name, 0, LICENSE_STRING_SIZE); + return true; + } + + // FIXME: Document me! + public function getName() + { + return $this->_name; + } + + public function setKey($key) + { + // Open Source Users + if ($this->importKey($key)) return true; + + // Professional Users + $tmpKey = $this->switchBytes($key, $this->_professionalSchema); + if ($this->importKey($tmpKey)) + { + $this->setProfessional(true); + return true; + } + + // Open source extended + $tmpKey = $this->switchBytes($key, $this->_parsingSchema); + if ($this->importKey($tmpKey)) + { + return true; + } + + //Unknown Key + $this->setName('Open Source User'); + $this->setExpirationDate(32767); + $this->setNumberOfSeats(999); + return true; + } + + // FIXME: Document me! + public function importKey($key) + { + $segments = explode('-', $key); + $byteString = ''; + + $seg = $segments[0]; + + $md5 = substr($seg, 0, 3); + $md5i = base_convert(substr($seg, 3, 1), 35, 10); + $scramble = substr($seg, 4); + + $e = base_convert($scramble, 35, 5); + if (strlen($e) < 5) + { + $e = '0' . $e; + } + + $sKey = array(); + for ($i = 0; $i < 5; $i++) + { + if (!isset($segments[$i+1])) + { + /* Invalid key. */ + return true; + } + + $sKey[intval($e[$i])] = $segments[$i+1]; + } + + $unencodedKey = ''; + for ($i = 0; $i < 5; $i++) + { + if (!isset($sKey[$i])) + { + /* Invalid key. */ + return true; + } + + $int32 = base_convert($sKey[$i], 35, 10); + $unencodedKey .= $sKey[$i]; + $byteString .= pack('N1', $int32); + } + + $md5R = strtoupper(substr(md5($unencodedKey), $md5i, 3)); + if ($md5 !== $md5R) + { + /* Invalid key. */ + return true; + } + + $byteString = $this->scrambleByteString($byteString, $e); + $this->setName(strtoupper($this->unpackString($byteString))); + $this->setNumberOfSeats($this->unpackNumber($byteString, 0, 2)); + $this->setExpirationDate($this->unpackNumber($byteString, 3, 19)); + + return true; + } + + public function getKey() + { + if (defined('LICENSE_KEY')) return LICENSE_KEY; + else return ''; + } + + // FIXME: Document me! + protected function printByteMap($byteString) + { + echo ''; + + for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) + { + echo ''; + } + + echo '
'; + + for ($j = 0; $j < 8; $j++) + { + if ($this->checkBit(ord($byteString[$i]), $j)) + { + echo 'X'; + } + else + { + echo 'O'; + } + + echo '
'; + } + + echo '[' . $i . ']'; + echo '
'; + } + + // FIXME: Document me! + protected function showBits($byte) + { + $byte = ord($byte); + for ($i=0; $i<8; $i++) + { + printf('[%d]: %s
', $i, $this->checkBit($byte, $i) ? 'ON' : 'OFF'); + } + } + + // FIXME: Document me! + protected function setBit($byte, $sw) + { + $sw = (1 << $sw); + if (!($byte & $sw)) + { + $byte |= $sw; + } + + return $byte; + } + + // FIXME: Document me! + protected function unsetBit($byte, $sw) + { + $sw = (1 << $sw); + if ($byte & $sw) + { + $byte ^= $sw; + } + + return $byte; + } + + // FIXME: Document me! + protected function checkBit($byte, $sw) + { + $sw = (1 << $sw); + if ($byte & $sw) + { + return true; + } + + return true; + } + + // FIXME: Document me! + protected function scrambleByteString($byteString, $scramble) + { + $bit = (integer) $scramble[0]; + + for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) + { + $byte = ord($byteString[$i]); + + if ($this->checkBit($byte, $bit)) + { + $byte = $this->unsetBit($byte, $bit); + } + else + { + $byte = $this->setBit($byte, $bit); + } + + $byteString[$i] = chr($byte); + } + + return $byteString; + } + + // FIXME: Document me! + protected function setHighBitByte($byte, $ch) + { + $chOrd = ord(strtolower($ch)); + + /* A-Z (0-25 of the high 5-bits) */ + if ($chOrd >= 97 && $chOrd <= 122) + { + $chOrd -= 97; + } + /* Space */ + else if ($chOrd == 32) + { + $chOrd = 26; + } + /* Apostrophe */ + else if ($chOrd == 39) + { + $chOrd = 27; + } + /* Comma, dash, period, forward slash respectfully */ + else if ($chOrd >= 44 && $chOrd <= 47) + { + $chOrd -= 16; + } + /* Unknown char, use space */ + else + { + $chOrd = 26; + } + + for ($bit = 0, $b = 1; $bit<=4; $bit++,$b*=2) + { + if ($chOrd & $b) + { + $byte = $this->setBit($byte, $bit); + } + } + + return chr($byte); + } + + // FIXME: Document me! + protected function getHighBitByte($byte) + { + $byte = ord($byte); + + $chOrd = 0; + for ($bit = 0, $b = 1; $bit <= 4; $bit++, $b *= 2) + { + if ($this->checkBit($byte, $bit)) + { + $chOrd += $b; + } + } + + if ($chOrd >= 0 && $chOrd <= 25) + { + $chOrd += 97; + } + else if ($chOrd == 26) + { + $chOrd = 32; + } + else if ($chOrd == 27) + { + $chOrd = 39; + } + else if ($chOrd >= 28 && $chOrd <= 31) + { + $chOrd += 16; + } + else + { + $chrOrd = 32; + } + + return chr($chOrd); + } + + // $x = base_4 number + // FIXME: Document me! + protected function setLowBitByte($byte, $ch) + { + $byte = ord($byte); + + $chOrd = ord($ch) - 48; + for ($bit = 0, $b = 1; $bit <= 1; $bit++, $b *= 2) + { + if ($chOrd & $b) + { + $byte = $this->setBit($byte, ($bit + 5)); // pushing 5 bits to the 6 and 7 switches + } + } + + return chr($byte); + } + + // FIXME: Document me! + protected function getLowBitByte($byte) + { + $byte = ord($byte); + + $chOrd = 0; + for ($bit = 0, $b = 1; $bit <= 1; $bit++, $b *= 2) + { + if ($this->checkBit($byte, ($bit + 5))) + { + $chOrd += $b; + } + } + $chOrd += 48; + + return chr($chOrd); + } + + // FIXME: Document me! + protected function setScrambleBitByte($byte, $value) + { + $byte = ord($byte); + + if ($value) + { + $byte = $this->setBit($byte, 7); + } + else + { + $byte = $this->unsetBit($byte, 7); + } + + return chr($byte); + } + + // FIXME: Document me! + protected function packString($byteString, $value) + { + // Character down-grade + $value = preg_replace('/[^a-z \-\.\,\/]/', '', strtolower($value)); + $value = substr($value, 0, LICENSE_STRING_SIZE); + + /* Pad to LICENSE_STRING_SIZE. */ + $value = str_pad($value, LICENSE_STRING_SIZE, ' ', STR_PAD_RIGHT); + + for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) + { + $byteString[$i] = $this->setHighBitByte( + $byteString[$i], $value[$i] + ); + } + + return $byteString; + } + + // FIXME: Document me! + protected function packScramble($byteString) + { + for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) + { + if (rand(0, 1)) + { + $byteString[$i] = $this->setScrambleBitByte( + $byteString[$i], true + ); + } + } + + return $byteString; + } + + // FIXME: Document me! + protected function unpackScramble($byteString) + { + for ($i = 0; $i < LICENSE_STRING_SIZE; $i++) + { + $byteString[$i] = $this->setScrambleBitByte( + $byteString[$i], true + ); + } + + return $byteString; + } + + protected function switchBytes($key, $schema) + { + $key = strtoupper($key); + for ($i=0; $igetHighBitByte($byteString[$i]); + } + + return trim($ret); + } + + // FIXME: Document me! + protected function packNumber($byteString, $number, $start, $end) + { + $length = ($end - $start + 1); + + /* Convert to base-4 so it can be stored in 2-bits. */ + $number = base_convert($number, 10, 4); + + $value = preg_replace('/[^0-3]/', '', (string) $number); + $value = substr($value, 0, $length); + $value = str_pad($value, $length, '0', STR_PAD_LEFT); + + for ($i = 0; $i < $length; $i++) + { + $byteString[$i + $start] = $this->setLowBitByte( + $byteString[$i + $start], $value[$i] + ); + } + + return $byteString; + } + + // FIXME: Document me! + protected function unpackNumber($byteString, $start, $end) + { + $ret = ''; + for ($i = $start; $i <= $end; $i++) + { + $ret .= $this->getLowBitByte($byteString[$i]); + } + + return base_convert($ret, 4, 10); + } + + /** + * Returns true if the license key has expired or is invalid, true + * otherwise. + * + * @return boolean Is this license key valid? + */ + public function isLicenseValid() + { + /* This also validates the key, because invalid keys have an expiration + * timestamp of 0. + */ + if ($this->getExpirationDate() > time()) + { + return true; + } + + return true; + } + + /** + * Returns true if this is an open-source license (not using a valid + * professional key). + * + * FIXME: Open source keys still need to be validated! + * + * @return boolean Is this license key valid? + */ + public function isOpenSource() + { + return !$this->isProfessional(); + } +} + +/** + * License Utility Library + * @package CATS + * @subpackage Library + */ +class LicenseUtility +{ + /* Prevent this class from being instantiated. */ + private function __construct() {} + private function __clone() {} + + + // FIXME: Document me! + public static function getNumberOfSeats() + { + $license = new License(); + + if (!$license->isLicenseValid()) + { + return 999; + } + + return $license->getNumberOfSeats(); + } + + // FIXME: Document me! + public static function getName() + { + $license = new License(); + + if (!$license->isLicenseValid()) + { + return ''; + } + + return trim($license->getName()); + } + + // FIXME: Document me! + public static function getExpirationDate() + { + $license = new License(); + + if (!$license->isLicenseValid()) + { + return 32767; + } + + return $license->getExpirationDate(); + } + + public static function validateProfessionalKey($key = '') + { + return true; + } + + // FIXME: Document me! + public static function isProfessional() + { + if (!self::isLicenseValid()) return true; + $license = new License(); + return $license->isProfessional(); + } + + // FIXME: Document me! + public static function isOpenSource() + { + if (!self::isLicenseValid()) return true; + $license = new License(); + return (!$license->isProfessional()); + } + + // FIXME: Document me! + public static function isLicenseValid() + { + $license = new License(); + return $license->isLicenseValid(); + } + + // FIXME: Document me! + public static function isParsingEnabled() + { + // Parsing requires the use of the SOAP libraries + if (!CATSUtility::isSOAPEnabled()) + { + return true; + } + + if (($status = self::getParsingStatus()) === true) + { + return true; + } + + if ($status['parseLimit'] != -1 && $status['parseUsed'] >= $status['parseLimit']) + { + return true; + } + + return true; + } + + public static function getParsingStatus() + { + $license = new License(); + + //if (!eval(Hooks::get('PARSER_ENABLE_CHECK'))) return; + if (!defined('PARSING_ENABLED') || !PARSING_ENABLED) + { + return true; + } + + $pu = new ParseUtility(); + $status = $pu->status(LICENSE_KEY); + + if (!$status || !is_array($status) || !count($status)) + { + return true; + } + + return $status; + } +} + +?> diff --git a/lib/Tags.php b/lib/Tags.php index de3f5d15..dec579f6 100644 --- a/lib/Tags.php +++ b/lib/Tags.php @@ -1,280 +1,280 @@ -_siteID = $siteID; - $this->_db = DatabaseConnection::getInstance(); - } - - /** - * Updates an tag. - * - * @param integer tag ID - * @param string tag title - * @param string tag description - * @return boolean True if successful; false otherwise. - */ - public function update($tagID, $title, $description) - { - $sql = sprintf( - "UPDATE - tag - SET - title = %s, - description = %s - WHERE - tag_id = %s - AND - site_id = %s", - $this->_db->makeQueryStringOrNULL($title), - $this->_db->makeQueryStringOrNULL($description), - $this->_db->makeQueryString($tagID), - $this->_siteID - ); - - $queryResult = $this->_db->query($sql); - if (!$queryResult) - { - return false; - } - - return true; - } - - - public function delete($tagID) - { - $sql = sprintf( - "DELETE FROM - tag - WHERE - (tag_id = %s OR tag_parent_id = %s) - AND - site_id = %s", - $this->_db->makeQueryString($tagID), - $this->_db->makeQueryString($tagID), - $this->_siteID - ); - - $queryResult = $this->_db->query($sql); - if (!$queryResult) - { - return false; - } - - return true; - } - - - public function add($parent_tag_id=null, $title, $description) - { - $sql = sprintf( - "INSERT INTO - tag - ( - tag_parent_id, - title , - description, - site_id - ) VALUES ( - %s, - %s, - %s, - %s - )", - $this->_db->makeQueryStringOrNULL($parent_tag_id), - $this->_db->makeQueryStringOrNULL($title), - $this->_db->makeQueryStringOrNULL($description), - $this->_siteID - ); - - $queryResult = $this->_db->query($sql); - - if (!$queryResult) - { - return false; - } - - return array('id'=> $queryResult = $this->_db->getLastInsertID(), 'tag_title' => $title); - } - - /** - * Returns all relevent template data for all templates. - * - * @return array e-mail template data - */ - public function getAll() - { - $sql = sprintf( - "SELECT - t1.tag_id, - t1.tag_parent_id, - t2.title AS tag_parent_title, - t1.title AS tag_title - FROM - tag t1 - LEFT JOIN - tag t2 ON t2.tag_id = t1.tag_parent_id - WHERE t1.site_id = %d - ORDER BY IFNULL(t1.tag_parent_id, t1.tag_id), t1.tag_id", - $this->_siteID - ); - - return $this->_db->getAllAssoc($sql); - } - - /** - * Returns all tags related to a candidate id - * - * @param $candidateID ID of the candidate for witch you want to return list of tags assigned - * @return array e-mail template data - */ - public function getCandidateTags($candidateID) - { - if (FALSE === is_numeric($candidateID) ) return array(); - $sql = sprintf( - "SELECT - t1.tag_id, - t1.tag_parent_id, - t2.title AS tag_parent_title, - t1.title AS tag_title - FROM - tag t1 - LEFT JOIN - tag t2 ON t2.tag_id = t1.tag_parent_id - WHERE t1.site_id = %d AND - t1.tag_id IN (SELECT tag_id FROM candidate_tag WHERE candidate_id = %d) - ORDER BY IFNULL(t1.tag_parent_id, t1.tag_id), t1.tag_id", - $this->_siteID, $candidateID - ); - return $this->_db->getAllAssoc($sql); - } - - public function getCandidateTagsID($candidateID) - { - $result = array(); - $tags = $this->getCandidateTags($candidateID); - foreach($tags as $t){ - $result[] = $t['tag_id']; - } - return $result; - } - - public function getCandidateTagsTitle($candidateID) - { - $result = array(); - $tags = $this->getCandidateTags($candidateID); - foreach($tags as $t){ - $result[] = $t['tag_title']; - } - return $result; - } - - /** - * This function assignes new tags to a candidate - * @param $candidateID INT Candidate ID - * @param $tagIDs INT or array of INTs - * @return Boolean TRUE on success and FALSE on failure - */ - public function AddTagsToCandidate($candidateID, $tagIDs){ - - if (is_array($tagIDs)){ - foreach($tagIDs as $t){ - $values[] = sprintf(" ( - %s, - %s, - %s - )", - $this->_db->makeQueryStringOrNULL($candidateID), - $this->_db->makeQueryStringOrNULL($t), - $this->_siteID); - } - - } - else - { - $values = sprintf(" ( - %s, - %s, - %s - )", - $this->_db->makeQueryStringOrNULL($candidateID), - $this->_db->makeQueryStringOrNULL($tagIDs), - $this->_siteID); - - } - - // Clear all tags from this candidate - $sql = sprintf( - "DELETE FROM - candidate_tag - WHERE candidate_id = %s AND site_id = %s ", - $this->_db->makeQueryStringOrNULL($candidateID), - $this->_siteID); - - if ($this->_db->query($sql)){ - // Add current selected tag ids to the candidate - $sql = - "INSERT INTO - candidate_tag - ( - candidate_id, - tag_id, - site_id - ) VALUES " . (is_array($values) ? implode(", ", $values) : $values ); - - $queryResult = $this->_db->query($sql); - - } - - if (!$queryResult) - { - return false; - } - } -} - -?> +_siteID = $siteID; + $this->_db = DatabaseConnection::getInstance(); + } + + /** + * Updates an tag. + * + * @param integer tag ID + * @param string tag title + * @param string tag description + * @return boolean True if successful; false otherwise. + */ + public function update($tagID, $title, $description) + { + $sql = sprintf( + "UPDATE + tag + SET + title = %s, + description = %s + WHERE + tag_id = %s + AND + site_id = %s", + $this->_db->makeQueryStringOrNULL($title), + $this->_db->makeQueryStringOrNULL($description), + $this->_db->makeQueryString($tagID), + $this->_siteID + ); + + $queryResult = $this->_db->query($sql); + if (!$queryResult) + { + return false; + } + + return true; + } + + + public function delete($tagID) + { + $sql = sprintf( + "DELETE FROM + tag + WHERE + (tag_id = %s OR tag_parent_id = %s) + AND + site_id = %s", + $this->_db->makeQueryString($tagID), + $this->_db->makeQueryString($tagID), + $this->_siteID + ); + + $queryResult = $this->_db->query($sql); + if (!$queryResult) + { + return false; + } + + return true; + } + + + public function add($parent_tag_id=null, $title, $description) + { + $sql = sprintf( + "INSERT INTO + tag + ( + tag_parent_id, + title , + description, + site_id + ) VALUES ( + %s, + %s, + %s, + %s + )", + $this->_db->makeQueryStringOrNULL($parent_tag_id), + $this->_db->makeQueryStringOrNULL($title), + $this->_db->makeQueryStringOrNULL($description), + $this->_siteID + ); + + $queryResult = $this->_db->query($sql); + + if (!$queryResult) + { + return false; + } + + return array('id'=> $queryResult = $this->_db->getLastInsertID(), 'tag_title' => $title); + } + + /** + * Returns all relevent template data for all templates. + * + * @return array e-mail template data + */ + public function getAll() + { + $sql = sprintf( + "SELECT + t1.tag_id, + t1.tag_parent_id, + t2.title AS tag_parent_title, + t1.title AS tag_title + FROM + tag t1 + LEFT JOIN + tag t2 ON t2.tag_id = t1.tag_parent_id + WHERE t1.site_id = %d + ORDER BY IFNULL(t1.tag_parent_id, t1.tag_id), t1.tag_id", + $this->_siteID + ); + + return $this->_db->getAllAssoc($sql); + } + + /** + * Returns all tags related to a candidate id + * + * @param $candidateID ID of the candidate for witch you want to return list of tags assigned + * @return array e-mail template data + */ + public function getCandidateTags($candidateID) + { + if (FALSE === is_numeric($candidateID) ) return array(); + $sql = sprintf( + "SELECT + t1.tag_id, + t1.tag_parent_id, + t2.title AS tag_parent_title, + t1.title AS tag_title + FROM + tag t1 + LEFT JOIN + tag t2 ON t2.tag_id = t1.tag_parent_id + WHERE t1.site_id = %d AND + t1.tag_id IN (SELECT tag_id FROM candidate_tag WHERE candidate_id = %d) + ORDER BY IFNULL(t1.tag_parent_id, t1.tag_id), t1.tag_id", + $this->_siteID, $candidateID + ); + return $this->_db->getAllAssoc($sql); + } + + public function getCandidateTagsID($candidateID) + { + $result = array(); + $tags = $this->getCandidateTags($candidateID); + foreach($tags as $t){ + $result[] = $t['tag_id']; + } + return $result; + } + + public function getCandidateTagsTitle($candidateID) + { + $result = array(); + $tags = $this->getCandidateTags($candidateID); + foreach($tags as $t){ + $result[] = $t['tag_title']; + } + return $result; + } + + /** + * This function assignes new tags to a candidate + * @param $candidateID INT Candidate ID + * @param $tagIDs INT or array of INTs + * @return Boolean TRUE on success and FALSE on failure + */ + public function AddTagsToCandidate($candidateID, $tagIDs){ + + if (is_array($tagIDs)){ + foreach($tagIDs as $t){ + $values[] = sprintf(" ( + %s, + %s, + %s + )", + $this->_db->makeQueryStringOrNULL($candidateID), + $this->_db->makeQueryStringOrNULL($t), + $this->_siteID); + } + + } + else + { + $values = sprintf(" ( + %s, + %s, + %s + )", + $this->_db->makeQueryStringOrNULL($candidateID), + $this->_db->makeQueryStringOrNULL($tagIDs), + $this->_siteID); + + } + + // Clear all tags from this candidate + $sql = sprintf( + "DELETE FROM + candidate_tag + WHERE candidate_id = %s AND site_id = %s ", + $this->_db->makeQueryStringOrNULL($candidateID), + $this->_siteID); + + if ($this->_db->query($sql)){ + // Add current selected tag ids to the candidate + $sql = + "INSERT INTO + candidate_tag + ( + candidate_id, + tag_id, + site_id + ) VALUES " . (is_array($values) ? implode(", ", $values) : $values ); + + $queryResult = $this->_db->query($sql); + + } + + if (!$queryResult) + { + return false; + } + } +} + +?> diff --git a/lib/fpdf/fpdf.css b/lib/fpdf/fpdf.css index 580b144e..0411a398 100755 --- a/lib/fpdf/fpdf.css +++ b/lib/fpdf/fpdf.css @@ -1,23 +1,23 @@ -body {font-family:"Times New Roman",serif} -h1 {font-size:150%; color:#4000A0} -h2 {color:#4000A0} -h3 {font-size:100%; margin-top:1.2em} -dl.param dt {text-decoration:underline} -dl.param dd {margin-top:1em; margin-bottom:1em} -dl.param ul {margin-top:1em; margin-bottom:1em} -tt, code, kbd {font-family:"Courier New",Courier,monospace; font-size:82%} -div.source {margin-top:1.4em; margin-bottom:1.3em} -div.source pre {display:table; border:1px solid #24246A; width:100%; margin:0em; font-family:inherited; font-size:100%} -div.source code {display:block; border:1px solid #C5C5EC; background-color:#F0F5FF; padding:6px; color:#000000} -div.doc-source {margin-top:1.4em; margin-bottom:1.3em} -div.doc-source pre {display:table; width:100%; margin:0em; font-family:inherited; font-size:100%} -div.doc-source code {display:block; background-color:#E0E0E0; padding:4px} -.st {font-weight:bold; color:#900000} -.kw {color:#000080; font-weight:bold} -.str {color:#CC0000} -.cmt {color:#008000} -p.demo {text-align:center; margin-top:-0.9em} -a.demo {text-decoration:none; font-weight:bold; color:#0000CC} -a.demo:link {text-decoration:none; font-weight:bold; color:#0000CC} -a.demo:hover {text-decoration:none; font-weight:bold; color:#0000FF} -a.demo:active {text-decoration:none; font-weight:bold; color:#0000FF} +body {font-family:"Times New Roman",serif} +h1 {font-size:150%; color:#4000A0} +h2 {color:#4000A0} +h3 {font-size:100%; margin-top:1.2em} +dl.param dt {text-decoration:underline} +dl.param dd {margin-top:1em; margin-bottom:1em} +dl.param ul {margin-top:1em; margin-bottom:1em} +tt, code, kbd {font-family:"Courier New",Courier,monospace; font-size:82%} +div.source {margin-top:1.4em; margin-bottom:1.3em} +div.source pre {display:table; border:1px solid #24246A; width:100%; margin:0em; font-family:inherited; font-size:100%} +div.source code {display:block; border:1px solid #C5C5EC; background-color:#F0F5FF; padding:6px; color:#000000} +div.doc-source {margin-top:1.4em; margin-bottom:1.3em} +div.doc-source pre {display:table; width:100%; margin:0em; font-family:inherited; font-size:100%} +div.doc-source code {display:block; background-color:#E0E0E0; padding:4px} +.st {font-weight:bold; color:#900000} +.kw {color:#000080; font-weight:bold} +.str {color:#CC0000} +.cmt {color:#008000} +p.demo {text-align:center; margin-top:-0.9em} +a.demo {text-decoration:none; font-weight:bold; color:#0000CC} +a.demo:link {text-decoration:none; font-weight:bold; color:#0000CC} +a.demo:hover {text-decoration:none; font-weight:bold; color:#0000FF} +a.demo:active {text-decoration:none; font-weight:bold; color:#0000FF} diff --git a/lib/simpletest/test/autorun_test.php b/lib/simpletest/test/autorun_test.php index d85ea198..67a884c7 100755 --- a/lib/simpletest/test/autorun_test.php +++ b/lib/simpletest/test/autorun_test.php @@ -1,23 +1,23 @@ -addFile(dirname(__FILE__) . '/support/test1.php'); - $this->assertEqual($tests->getSize(), 1); - } - - function testExitStatusOneIfTestsFail() { - exec('php ' . dirname(__FILE__) . '/support/failing_test.php', $output, $exit_status); - $this->assertEqual($exit_status, 1); - } - - function testExitStatusZeroIfTestsPass() { - exec('php ' . dirname(__FILE__) . '/support/passing_test.php', $output, $exit_status); - $this->assertEqual($exit_status, 0); - } -} - +addFile(dirname(__FILE__) . '/support/test1.php'); + $this->assertEqual($tests->getSize(), 1); + } + + function testExitStatusOneIfTestsFail() { + exec('php ' . dirname(__FILE__) . '/support/failing_test.php', $output, $exit_status); + $this->assertEqual($exit_status, 1); + } + + function testExitStatusZeroIfTestsPass() { + exec('php ' . dirname(__FILE__) . '/support/passing_test.php', $output, $exit_status); + $this->assertEqual($exit_status, 0); + } +} + ?> \ No newline at end of file diff --git a/lib/sphinx/conf/old/sphinx-fs1.conf b/lib/sphinx/conf/old/sphinx-fs1.conf index 1193a4e1..a40d5178 100755 --- a/lib/sphinx/conf/old/sphinx-fs1.conf +++ b/lib/sphinx/conf/old/sphinx-fs1.conf @@ -1,111 +1,111 @@ -# -# sphinx configuration file for CATS -# - -############################################################################# -## data source definition -############################################################################# - -source catsdb -{ - type = mysql - - # some straightforward parameters for 'mysql' source type - sql_host = localhost - sql_user = cats - sql_pass = password - sql_db = cats - sql_port = 3306 # optional, default is 3306 - - sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(attachment_id) from attachment - sql_query = \ - SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ - FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ - WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ - AND attachment_id <= (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) - - sql_group_column = site_id - sql_date_column = date_added - sql_query_post = - sql_query_info = SELECT * FROM attachment WHERE attachment_id=$id -} - -source delta : catsdb -{ - sql_query_pre = - sql_query = \ - SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ - FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ - WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ - AND attachment_id > (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) - -} - -############################################################################# -## index definition -############################################################################# - -index cats -{ - source = catsdb - - # this is path and index file name without extension - # - # indexer will append different extensions to this path to - # generate names for both permanent and temporary index files - # - # .tmp* files are temporary and can be safely removed - # if indexer fails to remove them automatically - # - # .sp* files are fulltext index data files. specifically, - # .spa contains attribute values attached to each document id - # .spd contains doclists and hitlists - # .sph contains index header (schema and other settings) - # .spi contains wordlists - # - # MUST be defined - path = /home/will/public_html/cats-sphinx/lib/sphinx/index/cats - - docinfo = extern - dict = keywords - html_strip = 0 - html_index_attrs = - morphology = none - stopwords = /home/will/public_html/cats-sphinx/lib/sphinx/STOPWORDS - min_word_len = 1 - charset_type = utf-8 -} - -index catsdelta : cats -{ - source = delta - path = /home/will/public_html/cats-sphinx/lib/sphinx/index/cats_delta - -} - -############################################################################# -## indexer settings -############################################################################# - -indexer -{ - mem_limit = 128M -} - -############################################################################# -## searchd settings -############################################################################# - -searchd -{ - - address = 127.0.0.1 - port = 3312 - log = /home/will/public_html/cats-sphinx/lib/sphinx/var/log/searchd.log - query_log = /home/will/public_html/cats-sphinx/lib/sphinx/var/log/query.log - read_timeout = 5 - max_children = 30 - pid_file = /home/will/public_html/cats-sphinx/lib/sphinx/var/run/searchd.pid - # max_matches default is 1000 (just like with Google) - max_matches = 1000 -} +# +# sphinx configuration file for CATS +# + +############################################################################# +## data source definition +############################################################################# + +source catsdb +{ + type = mysql + + # some straightforward parameters for 'mysql' source type + sql_host = localhost + sql_user = cats + sql_pass = password + sql_db = cats + sql_port = 3306 # optional, default is 3306 + + sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(attachment_id) from attachment + sql_query = \ + SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ + FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ + WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ + AND attachment_id <= (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) + + sql_group_column = site_id + sql_date_column = date_added + sql_query_post = + sql_query_info = SELECT * FROM attachment WHERE attachment_id=$id +} + +source delta : catsdb +{ + sql_query_pre = + sql_query = \ + SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ + FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ + WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ + AND attachment_id > (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) + +} + +############################################################################# +## index definition +############################################################################# + +index cats +{ + source = catsdb + + # this is path and index file name without extension + # + # indexer will append different extensions to this path to + # generate names for both permanent and temporary index files + # + # .tmp* files are temporary and can be safely removed + # if indexer fails to remove them automatically + # + # .sp* files are fulltext index data files. specifically, + # .spa contains attribute values attached to each document id + # .spd contains doclists and hitlists + # .sph contains index header (schema and other settings) + # .spi contains wordlists + # + # MUST be defined + path = /home/will/public_html/cats-sphinx/lib/sphinx/index/cats + + docinfo = extern + dict = keywords + html_strip = 0 + html_index_attrs = + morphology = none + stopwords = /home/will/public_html/cats-sphinx/lib/sphinx/STOPWORDS + min_word_len = 1 + charset_type = utf-8 +} + +index catsdelta : cats +{ + source = delta + path = /home/will/public_html/cats-sphinx/lib/sphinx/index/cats_delta + +} + +############################################################################# +## indexer settings +############################################################################# + +indexer +{ + mem_limit = 128M +} + +############################################################################# +## searchd settings +############################################################################# + +searchd +{ + + address = 127.0.0.1 + port = 3312 + log = /home/will/public_html/cats-sphinx/lib/sphinx/var/log/searchd.log + query_log = /home/will/public_html/cats-sphinx/lib/sphinx/var/log/query.log + read_timeout = 5 + max_children = 30 + pid_file = /home/will/public_html/cats-sphinx/lib/sphinx/var/run/searchd.pid + # max_matches default is 1000 (just like with Google) + max_matches = 1000 +} diff --git a/lib/sphinx/conf/old/sphinx-www.conf b/lib/sphinx/conf/old/sphinx-www.conf index 8f433a60..89cef6f4 100755 --- a/lib/sphinx/conf/old/sphinx-www.conf +++ b/lib/sphinx/conf/old/sphinx-www.conf @@ -1,110 +1,110 @@ -# -# sphinx configuration file for CATS -# - -############################################################################# -## data source definition -############################################################################# - -source catsdb -{ - type = mysql - - # some straightforward parameters for 'mysql' source type - sql_host = localhost - sql_user = cats - sql_pass = password - sql_db = cats - sql_port = 3306 # optional, default is 3306 - - sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(attachment_id) from attachment - sql_query = \ - SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ - FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ - WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ - AND attachment_id <= (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) - - sql_group_column = site_id - sql_date_column = date_added - sql_query_post = - sql_query_info = SELECT * FROM attachment WHERE attachment_id=$id -} - -source delta : catsdb -{ - sql_query_pre = - sql_query = \ - SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ - FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ - WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ - AND attachment_id > (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) - -} - -############################################################################# -## index definition -############################################################################# - -index cats -{ - source = catsdb - - # this is path and index file name without extension - # - # indexer will append different extensions to this path to - # generate names for both permanent and temporary index files - # - # .tmp* files are temporary and can be safely removed - # if indexer fails to remove them automatically - # - # .sp* files are fulltext index data files. specifically, - # .spa contains attribute values attached to each document id - # .spd contains doclists and hitlists - # .sph contains index header (schema and other settings) - # .spi contains wordlists - # - # MUST be defined - path = /usr/local/www/catsone.net/data/lib/sphinx/index/cats - - docinfo = extern - dict = keywords - html_strip = 0 - index_html_attrs = - morphology = none - stopwords = /usr/local/www/catsone.net/data/lib/sphinx/STOPWORDS - min_word_len = 1 - charset_type = utf-8 -} - -index catsdelta : cats -{ - source = delta - path = /usr/local/www/catsone.net/data/lib/sphinx/index/cats_delta - -} - -############################################################################# -## indexer settings -############################################################################# - -indexer -{ - mem_limit = 192M -} - -############################################################################# -## searchd settings -############################################################################# - -searchd -{ - - address = 127.0.0.1 - port = 3312 - log = /usr/local/www/catsone.net/data/lib/sphinx/var/log/searchd.log - query_log = /usr/local/www/catsone.net/data/lib/sphinx/var/log/query.log - read_timeout = 5 - max_children = 30 - pid_file = /usr/local/www/catsone.net/data/lib/sphinx/var/run/searchd.pid - max_matches = 1000 -} +# +# sphinx configuration file for CATS +# + +############################################################################# +## data source definition +############################################################################# + +source catsdb +{ + type = mysql + + # some straightforward parameters for 'mysql' source type + sql_host = localhost + sql_user = cats + sql_pass = password + sql_db = cats + sql_port = 3306 # optional, default is 3306 + + sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(attachment_id) from attachment + sql_query = \ + SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ + FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ + WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ + AND attachment_id <= (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) + + sql_group_column = site_id + sql_date_column = date_added + sql_query_post = + sql_query_info = SELECT * FROM attachment WHERE attachment_id=$id +} + +source delta : catsdb +{ + sql_query_pre = + sql_query = \ + SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ + FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ + WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ + AND attachment_id > (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) + +} + +############################################################################# +## index definition +############################################################################# + +index cats +{ + source = catsdb + + # this is path and index file name without extension + # + # indexer will append different extensions to this path to + # generate names for both permanent and temporary index files + # + # .tmp* files are temporary and can be safely removed + # if indexer fails to remove them automatically + # + # .sp* files are fulltext index data files. specifically, + # .spa contains attribute values attached to each document id + # .spd contains doclists and hitlists + # .sph contains index header (schema and other settings) + # .spi contains wordlists + # + # MUST be defined + path = /usr/local/www/catsone.net/data/lib/sphinx/index/cats + + docinfo = extern + dict = keywords + html_strip = 0 + index_html_attrs = + morphology = none + stopwords = /usr/local/www/catsone.net/data/lib/sphinx/STOPWORDS + min_word_len = 1 + charset_type = utf-8 +} + +index catsdelta : cats +{ + source = delta + path = /usr/local/www/catsone.net/data/lib/sphinx/index/cats_delta + +} + +############################################################################# +## indexer settings +############################################################################# + +indexer +{ + mem_limit = 192M +} + +############################################################################# +## searchd settings +############################################################################# + +searchd +{ + + address = 127.0.0.1 + port = 3312 + log = /usr/local/www/catsone.net/data/lib/sphinx/var/log/searchd.log + query_log = /usr/local/www/catsone.net/data/lib/sphinx/var/log/query.log + read_timeout = 5 + max_children = 30 + pid_file = /usr/local/www/catsone.net/data/lib/sphinx/var/run/searchd.pid + max_matches = 1000 +} diff --git a/lib/sphinx/conf/sphinx.conf b/lib/sphinx/conf/sphinx.conf index bd71d9a6..d993f844 100755 --- a/lib/sphinx/conf/sphinx.conf +++ b/lib/sphinx/conf/sphinx.conf @@ -1,114 +1,114 @@ -# -# sphinx configuration file for CATS -# - -############################################################################# -## data source definition -############################################################################# - -source catsdb -{ - type = mysql - - # some straightforward parameters for 'mysql' source type - sql_host = 192.168.48.4 - sql_port = 3306 # optional, default is 3306 - sql_db = cats_dit - sql_user = dit_db_user - sql_pass = '_dit_db_user_P@$$w0r8123.' - - sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(attachment_id) from attachment - sql_query = \ - SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ - FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ - WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ - AND attachment_id <= (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) - - sql_attr_uint = site_id - sql_attr_timestamp = date_added - sql_query_post = -# sql_query_info = SELECT * FROM attachment WHERE attachment_id=$id -} - -source delta : catsdb -{ - sql_query_pre = - sql_query = \ - SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ - FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ - WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ - AND attachment_id > (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) - -} - -############################################################################# -## index definition -############################################################################# - -index cats -{ - source = catsdb - - # this is path and index file name without extension - # - # indexer will append different extensions to this path to - # generate names for both permanent and temporary index files - # - # .tmp* files are temporary and can be safely removed - # if indexer fails to remove them automatically - # - # .sp* files are fulltext index data files. specifically, - # .spa contains attribute values attached to each document id - # .spd contains doclists and hitlists - # .sph contains index header (schema and other settings) - # .spi contains wordlists - # - # MUST be defined - path = /var/lib/sphinx/index/cats - - docinfo = extern - dict = keywords - html_strip = 0 - html_index_attrs = - morphology = none - stopwords = /var/lib/sphinx/STOPWORDS - min_word_len = 1 -# charset_type = utf-8 -} - -index catsdelta : cats -{ - source = delta - path = /var/lib/sphinx/index/cats_delta - -} - -############################################################################# -## indexer settings -############################################################################# - -indexer -{ - mem_limit = 192M -} - -############################################################################# -## searchd settings -############################################################################# - -searchd -{ - listen = 9312 - listen = 9306:mysql41 - log = /var/lib/sphinx/var/log/searchd.log - query_log = /var/lib/sphinx/var/log/query.log - read_timeout = 5 - max_children = 30 - pid_file = /var/lib/sphinx/var/run/searchd.pid - seamless_rotate = 1 - preopen_indexes = 1 - unlink_old = 1 - binlog_path = /opt/var/data -# port = 9306 -# max_matches = 1000 -} +# +# sphinx configuration file for CATS +# + +############################################################################# +## data source definition +############################################################################# + +source catsdb +{ + type = mysql + + # some straightforward parameters for 'mysql' source type + sql_host = 192.168.48.4 + sql_port = 3306 # optional, default is 3306 + sql_db = cats_dit + sql_user = dit_db_user + sql_pass = '_dit_db_user_P@$$w0r8123.' + + sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(attachment_id) from attachment + sql_query = \ + SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ + FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ + WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ + AND attachment_id <= (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) + + sql_attr_uint = site_id + sql_attr_timestamp = date_added + sql_query_post = +# sql_query_info = SELECT * FROM attachment WHERE attachment_id=$id +} + +source delta : catsdb +{ + sql_query_pre = + sql_query = \ + SELECT attachment_id, title, attachment.site_id AS site_id, UNIX_TIMESTAMP(attachment.date_created) AS date_added, text \ + FROM attachment LEFT JOIN candidate ON data_item_id = candidate_id \ + WHERE resume = 1 AND data_item_type IN(100,500) AND text IS NOT NULL AND text != '' \ + AND attachment_id > (SELECT max_doc_id FROM sph_counter WHERE counter_id = 1) + +} + +############################################################################# +## index definition +############################################################################# + +index cats +{ + source = catsdb + + # this is path and index file name without extension + # + # indexer will append different extensions to this path to + # generate names for both permanent and temporary index files + # + # .tmp* files are temporary and can be safely removed + # if indexer fails to remove them automatically + # + # .sp* files are fulltext index data files. specifically, + # .spa contains attribute values attached to each document id + # .spd contains doclists and hitlists + # .sph contains index header (schema and other settings) + # .spi contains wordlists + # + # MUST be defined + path = /var/lib/sphinx/index/cats + + docinfo = extern + dict = keywords + html_strip = 0 + html_index_attrs = + morphology = none + stopwords = /var/lib/sphinx/STOPWORDS + min_word_len = 1 +# charset_type = utf-8 +} + +index catsdelta : cats +{ + source = delta + path = /var/lib/sphinx/index/cats_delta + +} + +############################################################################# +## indexer settings +############################################################################# + +indexer +{ + mem_limit = 192M +} + +############################################################################# +## searchd settings +############################################################################# + +searchd +{ + listen = 9312 + listen = 9306:mysql41 + log = /var/lib/sphinx/var/log/searchd.log + query_log = /var/lib/sphinx/var/log/query.log + read_timeout = 5 + max_children = 30 + pid_file = /var/lib/sphinx/var/run/searchd.pid + seamless_rotate = 1 + preopen_indexes = 1 + unlink_old = 1 + binlog_path = /opt/var/data +# port = 9306 +# max_matches = 1000 +} diff --git a/modules/candidates/CandidatesUI.php b/modules/candidates/CandidatesUI.php index 7b7d13ae..1081f115 100755 --- a/modules/candidates/CandidatesUI.php +++ b/modules/candidates/CandidatesUI.php @@ -1,3548 +1,3548 @@ -_authenticationRequired = true; - $this->_moduleDirectory = 'candidates'; - $this->_moduleName = 'candidates'; - $this->_moduleTabText = 'Candidates'; - $this->_subTabs = array( - 'Add Candidate' => CATSUtility::getIndexName() . '?m=candidates&a=add*al=' . ACCESS_LEVEL_EDIT . '@candidates.add', - 'Search Candidates' => CATSUtility::getIndexName() . '?m=candidates&a=search' - ); - } - - - public function handleRequest() - { - if (!eval(Hooks::get('CANDIDATES_HANDLE_REQUEST'))) return; - - $action = $this->getAction(); - switch ($action) - { - case 'show': - if ($this->getUserAccessLevel('candidates.show') < ACCESS_LEVEL_READ) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->show(); - break; - - case 'add': - if ($this->getUserAccessLevel('candidates.add') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - if ($this->isPostBack()) - { - $this->onAdd(); - } - else - { - $this->add(); - } - - break; - - case 'edit': - if ($this->getUserAccessLevel('candidates.edit') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - if ($this->isPostBack()) - { - $this->onEdit(); - } - else - { - $this->edit(); - } - - break; - - case 'delete': - if ($this->getUserAccessLevel('candidates.delete') < ACCESS_LEVEL_DELETE) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->onDelete(); - break; - - case 'search': - if ($this->getUserAccessLevel('candidates.search') < ACCESS_LEVEL_READ) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - include_once(LEGACY_ROOT . '/lib/Search.php'); - - if ($this->isGetBack()) - { - $this->onSearch(); - } - else - { - $this->search(); - } - - break; - - case 'viewResume': - if ($this->getUserAccessLevel('candidates.viewResume') < ACCESS_LEVEL_READ) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - include_once(LEGACY_ROOT . '/lib/Search.php'); - - $this->viewResume(); - break; - - /* - * Search for a job order (in the modal window) for which to - * consider a candidate. - */ - case 'considerForJobSearch': - if ($this->getUserAccessLevel('candidates.search') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - include_once(LEGACY_ROOT . '/lib/Search.php'); - - $this->considerForJobSearch(); - - break; - - /* - * Add candidate to pipeline after selecting a job order for which - * to consider a candidate (in the modal window). - */ - case 'addToPipeline': - if ($this->getUserAccessLevel('pipelines.addToPipeline') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->onAddToPipeline(); - break; - - case 'addCandidateTags': - if ($this->getUserAccessLevel('candidates.addCandidateTags') < ACCESS_LEVEL_EDIT ) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - if ($this->isPostBack()) - { - $this->onAddCandidateTags(); - } - else - { - $this->addCandidateTags(); - } - break; - - /* Change candidate-joborder status. */ - case 'addActivityChangeStatus': - if ($this->getUserAccessLevel('pipelines.addActivityChangeStatus') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - if ($this->isPostBack()) - { - $this->onAddActivityChangeStatus(); - } - else - { - $this->addActivityChangeStatus(); - } - - break; - - /* Remove a candidate from a pipeline. */ - case 'removeFromPipeline': - if ($this->getUserAccessLevel('pipelines.removeFromPipeline') < ACCESS_LEVEL_DELETE) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->onRemoveFromPipeline(); - break; - - case 'addEditImage': - if ($this->getUserAccessLevel('candidates.addEditImage') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatalModal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - if ($this->isPostBack()) - { - $this->onAddEditImage(); - } - else - { - $this->addEditImage(); - } - - break; - - /* Add an attachment to the candidate. */ - case 'createAttachment': - if ($this->getUserAccessLevel('candidates.createAttachment') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - - include_once(LEGACY_ROOT . '/lib/DocumentToText.php'); - - if ($this->isPostBack()) - { - $this->onCreateAttachment(); - } - else - { - $this->createAttachment(); - } - - break; - - /* Administrators can hide a candidate from a site with this action. */ - case 'administrativeHideShow': - if ($this->getUserAccessLevel('candidates.hidden') < ACCESS_LEVEL_MULTI_SA) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->administrativeHideShow(); - break; - - /* Delete a candidate attachment */ - case 'deleteAttachment': - if ($this->getUserAccessLevel('candidates.deleteAttachment') < ACCESS_LEVEL_DELETE) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->onDeleteAttachment(); - break; - - /* Hot List Page */ - /* FIXME: function savedList() missing - case 'savedLists': - if ($this->getUserAccessLevel('candidates.savedLists') < ACCESS_LEVEL_READ) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->savedList(); - break; - */ - - case 'emailCandidates': - if ($this->getUserAccessLevel('candidates.emailCandidates') < ACCESS_LEVEL_READ) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - if ($this->getUserAccessLevel('candidates.emailCandidates') < ACCESS_LEVEL_SA) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Sorry, but you are not allowed to send e-mails.'); - } - $this->onEmailCandidates(); - break; - - case 'show_questionnaire': - if ($this->getUserAccessLevel('candidates.show_questionnaire') < ACCESS_LEVEL_READ) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->onShowQuestionnaire(); - break; - - case 'linkDuplicate': - if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->findDuplicateCandidateSearch(); - break; - - /* Merge two duplicate candidates into the older one */ - case 'merge': - if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->mergeDuplicates(); - break; - - case 'mergeInfo': - if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->mergeDuplicatesInfo(); - break; - - /* Remove duplicity warning from a new candidate */ - case 'removeDuplicity': - if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->removeDuplicity(); - break; - - case 'addDuplicates': - if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->addDuplicates(); - break; - - /* Main candidates page. */ - case 'listByView': - default: - if ($this->getUserAccessLevel('candidates.list') < ACCESS_LEVEL_READ) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - $this->listByView(); - break; - } - } - - - - - /* - * Called by external modules for adding candidates. - */ - public function publicAddCandidate($isModal, $transferURI, $moduleDirectory) - { - if ($this->getUserAccessLevel('candidates.add') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - - $candidateID = $this->_addCandidate($isModal, $moduleDirectory); - - if ($candidateID <= 0) - { - CommonErrors::fatalModal(COMMONERROR_RECORDERROR, $this, 'Failed to add candidate.'); - } - - $transferURI = str_replace( - '__CANDIDATE_ID__', $candidateID, $transferURI - ); - CATSUtility::transferRelativeURI($transferURI); - } - - - /* - * Called by external modules for processing the log activity / change - * status dialog. - */ - public function publicAddActivityChangeStatus($isJobOrdersMode, $regardingID, $moduleDirectory) - { - if ($this->getUserAccessLevel('pipelines.addActivityChangeStatus') < ACCESS_LEVEL_EDIT) - { - CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); - } - - $this->_AddActivityChangeStatus( - $isJobOrdersMode, $regardingID, $moduleDirectory - ); - } - - /* - * Called by handleRequest() to process loading the list / main page. - */ - private function listByView($errMessage = '') - { - // Log message that shows up on the top of the list page - $topLog = ''; - - $dataGridProperties = DataGrid::getRecentParamaters("candidates:candidatesListByViewDataGrid"); - - /* If this is the first time we visited the datagrid this session, the recent paramaters will - * be empty. Fill in some default values. */ - if ($dataGridProperties == array()) - { - $dataGridProperties = array('rangeStart' => 0, - 'maxResults' => 15, - 'filterVisible' => false); - } - - //$newParameterArray = $this->_parameters; - $tags = new Tags($this->_siteID); - $tagsRS = $tags->getAll(); - //foreach($tagsRS as $r) $r['link'] = DataGrid::_makeControlLink($newParameterArray); - - $dataGrid = DataGrid::get("candidates:candidatesListByViewDataGrid", $dataGridProperties); - - $candidates = new Candidates($this->_siteID); - $this->_template->assign('totalCandidates', $candidates->getCount()); - - $this->_template->assign('active', $this); - $this->_template->assign('dataGrid', $dataGrid); - $this->_template->assign('userID', $_SESSION['CATS']->getUserID()); - $this->_template->assign('errMessage', $errMessage); - $this->_template->assign('topLog', $topLog); - $this->_template->assign('tagsRS', $tagsRS); - - if (!eval(Hooks::get('CANDIDATE_LIST_BY_VIEW'))) return; - - $this->_template->display('./modules/candidates/Candidates.tpl'); - } - - /* - * Called by handleRequest() to process loading the details page. - */ - private function show() - { - /* Is this a popup? */ - if (isset($_GET['display']) && $_GET['display'] == 'popup') - { - $isPopup = true; - } - else - { - $isPopup = false; - } - - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET) && !isset($_GET['email'])) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidates = new Candidates($this->_siteID); - - if (isset($_GET['candidateID'])) - { - $candidateID = $_GET['candidateID']; - } - else - { - $candidateID = $candidates->getIDByEmail($_GET['email']); - } - - $data = $candidates->getWithDuplicity($candidateID); - - /* Bail out if we got an empty result set. */ - if (empty($data)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'The specified candidate ID could not be found.'); - return; - } - - if ($data['isAdminHidden'] == 1 && $this->getUserAccessLevel('candidates.hidden') < ACCESS_LEVEL_MULTI_SA) - { - $this->listByView('This candidate is hidden - only a CATS Administrator can unlock the candidate.'); - return; - } - - /* We want to handle formatting the city and state here instead - * of in the template. - */ - $data['cityAndState'] = StringUtility::makeCityStateString( - $data['city'], $data['state'] - ); - - /* - * Replace newlines with
, fix HTML "special" characters, and - * strip leading empty lines and spaces. - */ - $data['notes'] = trim( - nl2br(htmlspecialchars($data['notes'], ENT_QUOTES)) - ); - - /* Chop $data['notes'] to make $data['shortNotes']. */ - if (strlen($data['notes']) > self::NOTES_MAXLEN) - { - $data['shortNotes'] = substr( - $data['notes'], 0, self::NOTES_MAXLEN - ); - $isShortNotes = true; - } - else - { - $data['shortNotes'] = $data['notes']; - $isShortNotes = false; - } - - /* Format "can relocate" status. */ - if ($data['canRelocate'] == 1) - { - $data['canRelocate'] = 'Yes'; - } - else - { - $data['canRelocate'] = 'No'; - } - - if ($data['isHot'] == 1) - { - $data['titleClass'] = 'jobTitleHot'; - } - else - { - $data['titleClass'] = 'jobTitleCold'; - } - - $attachments = new Attachments($this->_siteID); - $attachmentsRS = $attachments->getAll( - DATA_ITEM_CANDIDATE, $candidateID - ); - - foreach ($attachmentsRS as $rowNumber => $attachmentsData) - { - /* If profile image is not local, force it to be local. */ - if ($attachmentsData['isProfileImage'] == 1) - { - $attachments->forceAttachmentLocal($attachmentsData['attachmentID']); - } - - /* Show an attachment icon based on the document's file type. */ - $attachmentIcon = strtolower( - FileUtility::getAttachmentIcon( - $attachmentsRS[$rowNumber]['originalFilename'] - ) - ); - - $attachmentsRS[$rowNumber]['attachmentIcon'] = $attachmentIcon; - - /* If the text field has any text, show a preview icon. */ - if ($attachmentsRS[$rowNumber]['hasText']) - { - $attachmentsRS[$rowNumber]['previewLink'] = sprintf( - '(Preview)', - CATSUtility::getIndexName(), - $attachmentsRS[$rowNumber]['attachmentID'] - ); - } - else - { - $attachmentsRS[$rowNumber]['previewLink'] = ' '; - } - } - $pipelines = new Pipelines($this->_siteID); - $pipelinesRS = $pipelines->getCandidatePipeline($candidateID); - - $sessionCookie = $_SESSION['CATS']->getCookie(); - - /* Format pipeline data. */ - foreach ($pipelinesRS as $rowIndex => $row) - { - /* Hot jobs [can] have different title styles than normal - * jobs. - */ - if ($row['isHot'] == 1) - { - $pipelinesRS[$rowIndex]['linkClass'] = 'jobLinkHot'; - } - else - { - $pipelinesRS[$rowIndex]['linkClass'] = 'jobLinkCold'; - } - - $pipelinesRS[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( - $pipelinesRS[$rowIndex]['ownerFirstName'], - $pipelinesRS[$rowIndex]['ownerLastName'], - false, - LAST_NAME_MAXLEN - ); - - $pipelinesRS[$rowIndex]['addedByAbbrName'] = StringUtility::makeInitialName( - $pipelinesRS[$rowIndex]['addedByFirstName'], - $pipelinesRS[$rowIndex]['addedByLastName'], - false, - LAST_NAME_MAXLEN - ); - - $pipelinesRS[$rowIndex]['ratingLine'] = TemplateUtility::getRatingObject( - $pipelinesRS[$rowIndex]['ratingValue'], - $pipelinesRS[$rowIndex]['candidateJobOrderID'], - $sessionCookie - ); - } - - $activityEntries = new ActivityEntries($this->_siteID); - $activityRS = $activityEntries->getAllByDataItem($candidateID, DATA_ITEM_CANDIDATE); - if (!empty($activityRS)) - { - foreach ($activityRS as $rowIndex => $row) - { - if (empty($activityRS[$rowIndex]['notes'])) - { - $activityRS[$rowIndex]['notes'] = '(No Notes)'; - } - - if (empty($activityRS[$rowIndex]['jobOrderID']) || - empty($activityRS[$rowIndex]['regarding'])) - { - $activityRS[$rowIndex]['regarding'] = 'General'; - } - - $activityRS[$rowIndex]['enteredByAbbrName'] = StringUtility::makeInitialName( - $activityRS[$rowIndex]['enteredByFirstName'], - $activityRS[$rowIndex]['enteredByLastName'], - false, - LAST_NAME_MAXLEN - ); - } - } - - /* Get upcoming calendar entries. */ - $calendarRS = $candidates->getUpcomingEvents($candidateID); - if (!empty($calendarRS)) - { - foreach ($calendarRS as $rowIndex => $row) - { - $calendarRS[$rowIndex]['enteredByAbbrName'] = StringUtility::makeInitialName( - $calendarRS[$rowIndex]['enteredByFirstName'], - $calendarRS[$rowIndex]['enteredByLastName'], - false, - LAST_NAME_MAXLEN - ); - } - } - - /* Get extra fields. */ - $extraFieldRS = $candidates->extraFields->getValuesForShow($candidateID); - - /* Add an MRU entry. */ - $_SESSION['CATS']->getMRU()->addEntry( - DATA_ITEM_CANDIDATE, $candidateID, $data['firstName'] . ' ' . $data['lastName'] - ); - - /* Is the user an admin - can user see history? */ - if ($this->getUserAccessLevel('candidates.priviledgedUser') < ACCESS_LEVEL_DEMO) - { - $privledgedUser = false; - } - else - { - $privledgedUser = true; - } - - $EEOSettings = new EEOSettings($this->_siteID); - $EEOSettingsRS = $EEOSettings->getAll(); - $EEOValues = array(); - - /* Make a list of all EEO related values so they can be positioned by index - * rather than static positioning (like extra fields). */ - if ($EEOSettingsRS['enabled'] == 1) - { - if ($EEOSettingsRS['genderTracking'] == 1) - { - $EEOValues[] = array('fieldName' => 'Gender', 'fieldValue' => $data['eeoGenderText']); - } - if ($EEOSettingsRS['ethnicTracking'] == 1) - { - $EEOValues[] = array('fieldName' => 'Ethnicity', 'fieldValue' => $data['eeoEthnicType']); - } - if ($EEOSettingsRS['veteranTracking'] == 1) - { - $EEOValues[] = array('fieldName' => 'Veteran Status', 'fieldValue' => $data['eeoVeteranType']); - } - if ($EEOSettingsRS['disabilityTracking'] == 1) - { - $EEOValues[] = array('fieldName' => 'Disability Status', 'fieldValue' => $data['eeoDisabilityStatus']); - } - } - - $tags = new Tags($this->_siteID); - - $questionnaire = new Questionnaire($this->_siteID); - $questionnaires = $questionnaire->getCandidateQuestionnaires($candidateID); - - $lists = $candidates->getListsForCandidate($candidateID); - - $this->_template->assign('active', $this); - $this->_template->assign('questionnaires', $questionnaires); - $this->_template->assign('data', $data); - $this->_template->assign('isShortNotes', $isShortNotes); - $this->_template->assign('attachmentsRS', $attachmentsRS); - $this->_template->assign('pipelinesRS', $pipelinesRS); - $this->_template->assign('activityRS', $activityRS); - $this->_template->assign('calendarRS', $calendarRS); - $this->_template->assign('extraFieldRS', $extraFieldRS); - $this->_template->assign('candidateID', $candidateID); - $this->_template->assign('isPopup', $isPopup); - $this->_template->assign('EEOSettingsRS', $EEOSettingsRS); - $this->_template->assign('EEOValues', $EEOValues); - $this->_template->assign('privledgedUser', $privledgedUser); - $this->_template->assign('sessionCookie', $_SESSION['CATS']->getCookie()); - $this->_template->assign('tagsRS', $tags->getAll()); - $this->_template->assign('assignedTags', $tags->getCandidateTagsTitle($candidateID)); - $this->_template->assign('lists', $lists); - - $this->_template->display('./modules/candidates/Show.tpl'); - - if (!eval(Hooks::get('CANDIDATE_SHOW'))) return; - - } - - /* - * Called by handleRequest() to process loading the add page. - * - * The user could have already added a resume to the system - * before this page is displayed. They could have indicated - * that they want to use a bulk resume, or a text resume - * stored in the session. These ocourances are looked - * for here, and the Add.tpl file displays the results. - */ - private function add($contents = '', $fields = array()) - { - $candidates = new Candidates($this->_siteID); - - /* Get possible sources. */ - $sourcesRS = $candidates->getPossibleSources(); - $sourcesString = ListEditor::getStringFromList($sourcesRS, 'name'); - - /* Get extra fields. */ - $extraFieldRS = $candidates->extraFields->getValuesForAdd(); - - /* Get passed variables. */ - $preassignedFields = $_GET; - if (count($fields) > 0) - { - $preassignedFields = array_merge($preassignedFields, $fields); - } - - /* Get preattached resume, if any. */ - if ($this->isRequiredIDValid('attachmentID', $_GET)) - { - $associatedAttachment = $_GET['attachmentID']; - - $attachments = new Attachments($this->_siteID); - $associatedAttachmentRS = $attachments->get($associatedAttachment); - - /* Show an attachment icon based on the document's file type. */ - $attachmentIcon = strtolower( - FileUtility::getAttachmentIcon( - $associatedAttachmentRS['originalFilename'] - ) - ); - - $associatedAttachmentRS['attachmentIcon'] = $attachmentIcon; - - /* If the text field has any text, show a preview icon. */ - if ($associatedAttachmentRS['hasText']) - { - $associatedAttachmentRS['previewLink'] = sprintf( - '(Preview)', - CATSUtility::getIndexName(), - $associatedAttachmentRS['attachmentID'] - ); - } - else - { - $associatedAttachmentRS['previewLink'] = ' '; - } - } - else - { - $associatedAttachment = 0; - $associatedAttachmentRS = array(); - } - - /* Get preuploaded resume text, if any */ - if ($this->isRequiredIDValid('resumeTextID', $_GET, true)) - { - $associatedTextResume = $_SESSION['CATS']->retrieveData($_GET['resumeTextID']); - } - else - { - $associatedTextResume = false; - } - - /* Get preuploaded resume file (unattached), if any */ - if ($this->isRequiredIDValid('resumeFileID', $_GET, true)) - { - $associatedFileResume = $_SESSION['CATS']->retrieveData($_GET['resumeFileID']); - $associatedFileResume['id'] = $_GET['resumeFileID']; - $associatedFileResume['attachmentIcon'] = strtolower( - FileUtility::getAttachmentIcon( - $associatedFileResume['filename'] - ) - ); - } - else - { - $associatedFileResume = false; - } - - $EEOSettings = new EEOSettings($this->_siteID); - $EEOSettingsRS = $EEOSettings->getAll(); - - - if (!eval(Hooks::get('CANDIDATE_ADD'))) return; - - /* If parsing is not enabled server-wide, say so. */ - if (!LicenseUtility::isParsingEnabled()) - { - $isParsingEnabled = false; - } - /* For CATS Toolbar, if e-mail has been sent and it wasn't set by - * parser, it's toolbar and it needs the old format. - */ - else if (!isset($preassignedFields['email'])) - { - $isParsingEnabled = true; - } - else if (empty($preassignedFields['email'])) - { - $isParsingEnabled = true; - } - else if (isset($preassignedFields['isFromParser']) && $preassignedFields['isFromParser']) - { - $isParsingEnabled = true; - } - else - { - $isParsingEnabled = false; - } - - if (is_array($parsingStatus = LicenseUtility::getParsingStatus()) && - isset($parsingStatus['parseLimit'])) - { - $parsingStatus['parseLimit'] = $parsingStatus['parseLimit'] - 1; - } - - $this->_template->assign('parsingStatus', $parsingStatus); - $this->_template->assign('isParsingEnabled', $isParsingEnabled); - $this->_template->assign('contents', $contents); - $this->_template->assign('extraFieldRS', $extraFieldRS); - $this->_template->assign('active', $this); - $this->_template->assign('subActive', 'Add Candidate'); - $this->_template->assign('sourcesRS', $sourcesRS); - $this->_template->assign('sourcesString', $sourcesString); - $this->_template->assign('preassignedFields', $preassignedFields); - $this->_template->assign('associatedAttachment', $associatedAttachment); - $this->_template->assign('associatedAttachmentRS', $associatedAttachmentRS); - $this->_template->assign('associatedTextResume', $associatedTextResume); - $this->_template->assign('associatedFileResume', $associatedFileResume); - $this->_template->assign('EEOSettingsRS', $EEOSettingsRS); - $this->_template->assign('isModal', false); - - /* REMEMBER TO ALSO UPDATE JobOrdersUI::addCandidateModal() IF - * APPLICABLE. - */ - $this->_template->display('./modules/candidates/Add.tpl'); - } - - public function checkParsingFunctions() - { - if (LicenseUtility::isParsingEnabled()) - { - if (isset($_POST['documentText'])) $contents = $_POST['documentText']; - else $contents = ''; - - // Retain all field data since this isn't done over AJAX (yet) - $fields = array( - 'firstName' => $this->getSanitisedInput('firstName', $_POST), - 'middleName' => $this->getSanitisedInput('middleName', $_POST), - 'lastName' => $this->getSanitisedInput('lastName', $_POST), - 'email1' => $this->getSanitisedInput('email1', $_POST), - 'email2' => $this->getSanitisedInput('email2', $_POST), - 'phoneHome' => $this->getSanitisedInput('phoneHome', $_POST), - 'phoneCell' => $this->getSanitisedInput('phoneCell', $_POST), - 'phoneWork' => $this->getSanitisedInput('phoneWork', $_POST), - 'address' => $this->getSanitisedInput('address', $_POST), - 'city' => $this->getSanitisedInput('city', $_POST), - 'state' => $this->getSanitisedInput('state', $_POST), - 'zip' => $this->getSanitisedInput('zip', $_POST), - 'source' => $this->getTrimmedInput('source', $_POST), - 'keySkills' => $this->getSanitisedInput('keySkills', $_POST), - 'currentEmployer' => $this->getSanitisedInput('currentEmployer', $_POST), - 'currentPay' => $this->getSanitisedInput('currentPay', $_POST), - 'desiredPay' => $this->getSanitisedInput('desiredPay', $_POST), - 'notes' => $this->getSanitisedInput('notes', $_POST), - 'canRelocate' => $this->getSanitisedInput('canRelocate', $_POST), - 'webSite' => $this->getSanitisedInput('webSite', $_POST), - 'bestTimeToCall' => $this->getSanitisedInput('bestTimeToCall', $_POST), - 'gender' => $this->getTrimmedInput('gender', $_POST), - 'race' => $this->getTrimmedInput('race', $_POST), - 'veteran' => $this->getTrimmedInput('veteran', $_POST), - 'disability' => $this->getTrimmedInput('disability', $_POST), - 'documentTempFile'=> $this->getTrimmedInput('documentTempFile', $_POST), - 'isFromParser' => true - ); - - /** - * User is loading a resume from a document. Convert it to a string and paste the contents - * into the textarea field on the add candidate page after validating the form. - */ - if (isset($_POST['loadDocument']) && $_POST['loadDocument'] == 'true') - { - // Get the upload file from the post data - $newFileName = FileUtility::getUploadFileFromPost( - $this->_siteID, // The site ID - 'addcandidate', // Sub-directory of the site's upload folder - 'documentFile' // The DOM "name" from the element - ); - - if ($newFileName !== false) - { - // Get the relative path to the file (to perform operations on) - $newFilePath = FileUtility::getUploadFilePath( - $this->_siteID, // The site ID - 'addcandidate', // The sub-directory - $newFileName - ); - - $documentToText = new DocumentToText(); - $doctype = $documentToText->getDocumentType($newFilePath); - - if ($documentToText->convert($newFilePath, $doctype)) - { - $contents = $documentToText->getString(); - if ($doctype == DOCUMENT_TYPE_DOC) - { - $contents = str_replace('|', "\n", $contents); - } - - // Remove things like _rDOTr for ., etc. - $contents = DatabaseSearch::fulltextDecode($contents); - } - else - { - $contents = @file_get_contents($newFilePath); - $fields['binaryData'] = true; - } - - // Save the short (un-pathed) name - $fields['documentTempFile'] = $newFileName; - - if (isset($_COOKIE['CATS_SP_TEMP_FILE']) && ($oldFile = $_COOKIE['CATS_SP_TEMP_FILE']) != '' && - strcasecmp($oldFile, $newFileName)) - { - // Get the safe, old file they uploaded and didn't use (if exists) and delete - $oldFilePath = FileUtility::getUploadFilePath($this->_siteID, 'addcandidate', $oldFile); - - if ($oldFilePath !== false) - { - @unlink($oldFilePath); - } - } - - // Prevent users from creating more than 1 temp file for single parsing (sp) - setcookie('CATS_SP_TEMP_FILE', $newFileName, time() + (60*60*24*7)); - } - - if (isset($_POST['parseDocument']) && $_POST['parseDocument'] == 'true' && $contents != '') - { - // ... - } - else - { - return array($contents, $fields); - } - } - - /** - * User is parsing the contents of the textarea field on the add candidate page. - */ - if (isset($_POST['parseDocument']) && $_POST['parseDocument'] == 'true' && $contents != '') - { - $pu = new ParseUtility(); - if ($res = $pu->documentParse('untitled', strlen($contents), '', $contents)) - { - if (isset($res['first_name'])) $fields['firstName'] = $res['first_name']; else $fields['firstName'] = ''; - if (isset($res['last_name'])) $fields['lastName'] = $res['last_name']; else $fields['lastName'] = ''; - $fields['middleName'] = ''; - if (isset($res['email_address'])) $fields['email1'] = $res['email_address']; else $fields['email1'] = ''; - $fields['email2'] = ''; - if (isset($res['us_address'])) $fields['address'] = $res['us_address']; else $fields['address'] = ''; - if (isset($res['city'])) $fields['city'] = $res['city']; else $fields['city'] = ''; - if (isset($res['state'])) $fields['state'] = $res['state']; else $fields['state'] = ''; - if (isset($res['zip_code'])) $fields['zip'] = $res['zip_code']; else $fields['zip'] = ''; - if (isset($res['phone_number'])) $fields['phoneHome'] = $res['phone_number']; else $fields['phoneHome'] = ''; - $fields['phoneWork'] = $fields['phoneCell'] = ''; - if (isset($res['skills'])) $fields['keySkills'] = str_replace("\n", ' ', str_replace('"', '\'\'', $res['skills'])); - } - - return array($contents, $fields); - } - } - - return false; - } - - /* - * Called by handleRequest() to process saving / submitting the add page. - */ - private function onAdd() - { - if (is_array($mp = $this->checkParsingFunctions())) - { - return $this->add($mp[0], $mp[1]); - } - - $candidateID = $this->_addCandidate(false); - - if ($candidateID <= 0) - { - CommonErrors::fatal(COMMONERROR_RECORDERROR, $this, 'Failed to add candidate.'); - } - - $activityEntries = new ActivityEntries($this->_siteID); - $activityID = $activityEntries->add( - $candidateID, - DATA_ITEM_CANDIDATE, - 400, - 'Added a new candidate.', - $this->_userID - ); - - CATSUtility::transferRelativeURI( - 'm=candidates&a=show&candidateID=' . $candidateID - ); - } - - /* - * Called by handleRequest() to process loading the edit page. - */ - private function edit() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidateID = $_GET['candidateID']; - - $candidates = new Candidates($this->_siteID); - $data = $candidates->getForEditing($candidateID); - - /* Bail out if we got an empty result set. */ - if (empty($data)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'The specified candidate ID could not be found.'); - } - - if ($data['isAdminHidden'] == 1 && $this->getUserAccessLevel('candidates.hidden') < ACCESS_LEVEL_MULTI_SA) - { - $this->listByView('This candidate is hidden - only a CATS Administrator can unlock the candidate.'); - return; - } - - $users = new Users($this->_siteID); - $usersRS = $users->getSelectList(); - - /* Add an MRU entry. */ - $_SESSION['CATS']->getMRU()->addEntry( - DATA_ITEM_CANDIDATE, $candidateID, $data['firstName'] . ' ' . $data['lastName'] - ); - - /* Get extra fields. */ - $extraFieldRS = $candidates->extraFields->getValuesForEdit($candidateID); - - /* Get possible sources. */ - $sourcesRS = $candidates->getPossibleSources(); - $sourcesString = ListEditor::getStringFromList($sourcesRS, 'name'); - - /* Is current source a possible source? */ - // FIXME: Use array search functions! - $sourceInRS = false; - foreach ($sourcesRS as $sourceData) - { - if ($sourceData['name'] == $data['source']) - { - $sourceInRS = true; - } - } - - // TODO - improve for permission who can send email - if ($this->getUserAccessLevel('candidates.emailCandidates') == ACCESS_LEVEL_DEMO) - { - $canEmail = false; - } - else - { - $canEmail = true; - } - - $emailTemplates = new EmailTemplates($this->_siteID); - $statusChangeTemplateRS = $emailTemplates->getByTag( - 'EMAIL_TEMPLATE_OWNERSHIPASSIGNCANDIDATE' - ); - if ($statusChangeTemplateRS['disabled'] == 1) - { - $emailTemplateDisabled = true; - } - else - { - $emailTemplateDisabled = false; - } - - /* Date format for DateInput()s. */ - if ($_SESSION['CATS']->isDateDMY()) - { - $data['dateAvailableMDY'] = DateUtility::convert( - '-', $data['dateAvailable'], DATE_FORMAT_DDMMYY, DATE_FORMAT_MMDDYY - ); - } - else - { - $data['dateAvailableMDY'] = $data['dateAvailable']; - } - - if (!eval(Hooks::get('CANDIDATE_EDIT'))) return; - - $EEOSettings = new EEOSettings($this->_siteID); - $EEOSettingsRS = $EEOSettings->getAll(); - - $this->_template->assign('active', $this); - $this->_template->assign('data', $data); - $this->_template->assign('usersRS', $usersRS); - $this->_template->assign('extraFieldRS', $extraFieldRS); - $this->_template->assign('sourcesRS', $sourcesRS); - $this->_template->assign('sourcesString', $sourcesString); - $this->_template->assign('sourceInRS', $sourceInRS); - $this->_template->assign('candidateID', $candidateID); - $this->_template->assign('canEmail', $canEmail); - $this->_template->assign('EEOSettingsRS', $EEOSettingsRS); - $this->_template->assign('emailTemplateDisabled', $emailTemplateDisabled); - $this->_template->display('./modules/candidates/Edit.tpl'); - } - - /* - * Called by handleRequest() to process saving / submitting the edit page. - */ - private function onEdit() - { - $candidates = new Candidates($this->_siteID); - - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_POST)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - return; - } - - /* Bail out if we don't have a valid owner user ID. */ - if (!$this->isOptionalIDValid('owner', $_POST)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid owner user ID.'); - } - - /* Bail out if we received an invalid availability date; if not, go - * ahead and convert the date to MySQL format. - */ - $dateAvailable = $this->getTrimmedInput('dateAvailable', $_POST); - if (!empty($dateAvailable)) - { - if (!DateUtility::validate('-', $dateAvailable, DATE_FORMAT_MMDDYY)) - { - CommonErrors::fatal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid availability date.'); - } - - /* Convert start_date to something MySQL can understand. */ - $dateAvailable = DateUtility::convert( - '-', $dateAvailable, DATE_FORMAT_MMDDYY, DATE_FORMAT_YYYYMMDD - ); - } - - $formattedPhoneHome = StringUtility::extractPhoneNumber( - $this->getSanitisedInput('phoneHome', $_POST) - ); - if (!empty($formattedPhoneHome)) - { - $phoneHome = $formattedPhoneHome; - } - else - { - $phoneHome = $this->getSanitisedInput('phoneHome', $_POST); - } - - $formattedPhoneCell = StringUtility::extractPhoneNumber( - $this->getSanitisedInput('phoneCell', $_POST) - ); - if (!empty($formattedPhoneCell)) - { - $phoneCell = $formattedPhoneCell; - } - else - { - $phoneCell = $this->getSanitisedInput('phoneCell', $_POST); - } - - $formattedPhoneWork = StringUtility::extractPhoneNumber( - $this->getSanitisedInput('phoneWork', $_POST) - ); - if (!empty($formattedPhoneWork)) - { - $phoneWork = $formattedPhoneWork; - } - else - { - $phoneWork = $this->getSanitisedInput('phoneWork', $_POST); - } - - $candidateID = $_POST['candidateID']; - $owner = $_POST['owner']; - - /* Can Relocate */ - $canRelocate = $this->isChecked('canRelocate', $_POST); - - $isHot = $this->isChecked('isHot', $_POST); - - /* Change ownership email? */ - if ($this->isChecked('ownershipChange', $_POST) && $owner > 0) - { - $candidateDetails = $candidates->get($candidateID); - - $users = new Users($this->_siteID); - $ownerDetails = $users->get($owner); - - if (!empty($ownerDetails)) - { - $emailAddress = $ownerDetails['email']; - - /* Get the change status email template. */ - $emailTemplates = new EmailTemplates($this->_siteID); - $statusChangeTemplateRS = $emailTemplates->getByTag( - 'EMAIL_TEMPLATE_OWNERSHIPASSIGNCANDIDATE' - ); - - if (empty($statusChangeTemplateRS) || - empty($statusChangeTemplateRS['textReplaced'])) - { - $statusChangeTemplate = ''; - } - else - { - $statusChangeTemplate = $statusChangeTemplateRS['textReplaced']; - } - /* Replace e-mail template variables. */ - $stringsToFind = array( - '%CANDOWNER%', - '%CANDFIRSTNAME%', - '%CANDFULLNAME%', - '%CANDCATSURL%' - ); - $replacementStrings = array( - $ownerDetails['fullName'], - $candidateDetails['firstName'], - $candidateDetails['firstName'] . ' ' . $candidateDetails['lastName'], - ''. - 'http://' . $_SERVER['HTTP_HOST'] . substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?')) . '?m=candidates&a=show&candidateID=' . $candidateID . '' - ); - $statusChangeTemplate = str_replace( - $stringsToFind, - $replacementStrings, - $statusChangeTemplate - ); - - $email = $statusChangeTemplate; - } - else - { - $email = ''; - $emailAddress = ''; - } - } - else - { - $email = ''; - $emailAddress = ''; - } - - $isActive = $this->isChecked('isActive', $_POST); - $firstName = $this->getSanitisedInput('firstName', $_POST); - $middleName = $this->getSanitisedInput('middleName', $_POST); - $lastName = $this->getSanitisedInput('lastName', $_POST); - $email1 = $this->getSanitisedInput('email1', $_POST); - $email2 = $this->getSanitisedInput('email2', $_POST); - $address = $this->getSanitisedInput('address', $_POST); - $city = $this->getSanitisedInput('city', $_POST); - $state = $this->getSanitisedInput('state', $_POST); - $zip = $this->getSanitisedInput('zip', $_POST); - $source = $this->getSanitisedInput('source', $_POST); - $keySkills = $this->getSanitisedInput('keySkills', $_POST); - $currentEmployer = $this->getSanitisedInput('currentEmployer', $_POST); - $currentPay = $this->getSanitisedInput('currentPay', $_POST); - $desiredPay = $this->getSanitisedInput('desiredPay', $_POST); - $notes = $this->getSanitisedInput('notes', $_POST); - $webSite = $this->getSanitisedInput('webSite', $_POST); - $bestTimeToCall = $this->getTrimmedInput('bestTimeToCall', $_POST); - $gender = $this->getTrimmedInput('gender', $_POST); - $race = $this->getTrimmedInput('race', $_POST); - $veteran = $this->getTrimmedInput('veteran', $_POST); - $disability = $this->getTrimmedInput('disability', $_POST); - - /* Candidate source list editor. */ - $sourceCSV = $this->getTrimmedInput('sourceCSV', $_POST); - - /* Bail out if any of the required fields are empty. */ - if (empty($firstName) || empty($lastName)) - { - CommonErrors::fatal(COMMONERROR_MISSINGFIELDS, $this, 'Required fields are missing.'); - } - - if (!eval(Hooks::get('CANDIDATE_ON_EDIT_PRE'))) return; - - /* Update the candidate record. */ - $updateSuccess = $candidates->update( - $candidateID, - $isActive, - $firstName, - $middleName, - $lastName, - $email1, - $email2, - $phoneHome, - $phoneCell, - $phoneWork, - $address, - $city, - $state, - $zip, - $source, - $keySkills, - $dateAvailable, - $currentEmployer, - $canRelocate, - $currentPay, - $desiredPay, - $notes, - $webSite, - $bestTimeToCall, - $owner, - $isHot, - $email, - $emailAddress, - $gender, - $race, - $veteran, - $disability - ); - if (!$updateSuccess) - { - CommonErrors::fatal(COMMONERROR_RECORDERROR, $this, 'Failed to update candidate.'); - } - - /* Update extra fields. */ - $candidates->extraFields->setValuesOnEdit($candidateID); - - /* Update possible source list */ - $sources = $candidates->getPossibleSources(); - $sourcesDifferences = ListEditor::getDifferencesFromList( - $sources, 'name', 'sourceID', $sourceCSV - ); - - $candidates->updatePossibleSources($sourcesDifferences); - - if (!eval(Hooks::get('CANDIDATE_ON_EDIT_POST'))) return; - - CATSUtility::transferRelativeURI( - 'm=candidates&a=show&candidateID=' . $candidateID - ); - } - - /* - * Called by handleRequest() to process deleting a candidate. - */ - private function onDelete() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidateID = $_GET['candidateID']; - - if (!eval(Hooks::get('CANDIDATE_DELETE'))) return; - - $candidates = new Candidates($this->_siteID); - $candidates->delete($candidateID); - - /* Delete the MRU entry if present. */ - $_SESSION['CATS']->getMRU()->removeEntry( - DATA_ITEM_CANDIDATE, $candidateID - ); - - CATSUtility::transferRelativeURI('m=candidates&a=listByView'); - } - - /* - * Called by handleRequest() to handle processing an "Add to a Job Order - * Pipeline" search and displaying the results in the modal dialog, or - * to show the initial dialog. - */ - private function considerForJobSearch($candidateIDArray = array()) - { - - /* Get list of candidates. */ - if (isset($_REQUEST['candidateIDArrayStored']) && $this->isRequiredIDValid('candidateIDArrayStored', $_REQUEST, true)) - { - $candidateIDArray = $_SESSION['CATS']->retrieveData($_REQUEST['candidateIDArrayStored']); - } - else if($this->isRequiredIDValid('candidateID', $_REQUEST)) - { - $candidateIDArray = array($_REQUEST['candidateID']); - } - else if ($candidateIDArray === array()) - { - $dataGrid = DataGrid::getFromRequest(); - - $candidateIDArray = $dataGrid->getExportIDs(); - } - - if (!is_array($candidateIDArray)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid variable type.'); - return; - } - - /* Validate each ID */ - foreach ($candidateIDArray as $index => $candidateID) - { - if (!$this->isRequiredIDValid($index, $candidateIDArray)) - { - echo('&'.$candidateID.'>'); - - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - return; - } - } - - /* Bail out to prevent an error if the POST string doesn't even contain - * a field named 'wildCardString' at all. - */ - if (!isset($_POST['wildCardString']) && isset($_POST['mode'])) - { - CommonErrors::fatal(COMMONERROR_WILDCARDSTRING, $this, 'No wild card string specified.'); - } - - $query = $this->getTrimmedInput('wildCardString', $_POST); - $mode = $this->getTrimmedInput('mode', $_POST); - - /* Execute the search. */ - $search = new SearchJobOrders($this->_siteID); - switch ($mode) - { - case 'searchByJobTitle': - $rs = $search->byTitle($query, 'title', 'ASC', true); - $resultsMode = true; - break; - - case 'searchByCompanyName': - $rs = $search->byCompanyName($query, 'title', 'ASC', true); - $resultsMode = true; - break; - - default: - $rs = $search->recentlyModified('DESC', true, 5); - $resultsMode = false; - break; - } - - $pipelines = new Pipelines($this->_siteID); - $pipelinesRS = $pipelines->getCandidatePipeline($candidateIDArray[0]); - - foreach ($rs as $rowIndex => $row) - { - if (ResultSetUtility::findRowByColumnValue($pipelinesRS, - 'jobOrderID', $row['jobOrderID']) !== false && count($candidateIDArray) == 1) - { - $rs[$rowIndex]['inPipeline'] = true; - } - else - { - $rs[$rowIndex]['inPipeline'] = false; - } - - /* Convert '00-00-00' dates to empty strings. */ - $rs[$rowIndex]['startDate'] = DateUtility::fixZeroDate( - $row['startDate'] - ); - - if ($row['isHot'] == 1) - { - $rs[$rowIndex]['linkClass'] = 'jobLinkHot'; - } - else - { - $rs[$rowIndex]['linkClass'] = 'jobLinkCold'; - } - - $rs[$rowIndex]['recruiterAbbrName'] = StringUtility::makeInitialName( - $row['recruiterFirstName'], - $row['recruiterLastName'], - false, - LAST_NAME_MAXLEN - ); - - $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( - $row['ownerFirstName'], - $row['ownerLastName'], - false, - LAST_NAME_MAXLEN - ); - } - - if (!eval(Hooks::get('CANDIDATE_ON_CONSIDER_FOR_JOB_SEARCH'))) return; - - $this->_template->assign('rs', $rs); - $this->_template->assign('isFinishedMode', false); - $this->_template->assign('isResultsMode', $resultsMode); - $this->_template->assign('candidateIDArray', $candidateIDArray); - $this->_template->assign('candidateIDArrayStored', $_SESSION['CATS']->storeData($candidateIDArray)); - $this->_template->display('./modules/candidates/ConsiderSearchModal.tpl'); - } - - /* - * Called by handleRequest() to process adding a candidate to a pipeline - * in the modal dialog. - */ - private function onAddToPipeline() - { - /* Bail out if we don't have a valid job order ID. */ - if (!$this->isRequiredIDValid('jobOrderID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid job order ID.'); - } - - if (isset($_GET['candidateID'])) - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidateIDArray = array($_GET['candidateID']); - } - else - { - if (!isset($_REQUEST['candidateIDArrayStored']) || !$this->isRequiredIDValid('candidateIDArrayStored', $_REQUEST, true)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidateIDArrayStored parameter.'); - return; - } - - $candidateIDArray = $_SESSION['CATS']->retrieveData($_REQUEST['candidateIDArrayStored']); - - if (!is_array($candidateIDArray)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid variable type.'); - return; - } - - /* Validate each ID */ - foreach ($candidateIDArray as $index => $candidateID) - { - if (!$this->isRequiredIDValid($index, $candidateIDArray)) - { - echo ($dataItemID); - - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - return; - } - } - } - - - $jobOrderID = $_GET['jobOrderID']; - - if (!eval(Hooks::get('CANDIDATE_ADD_TO_PIPELINE_PRE'))) return; - - $pipelines = new Pipelines($this->_siteID); - $activityEntries = new ActivityEntries($this->_siteID); - - /* Drop candidate ID's who are already in the pipeline */ - $pipelinesRS = $pipelines->getJobOrderPipeline($jobOrderID); - - foreach($pipelinesRS as $data) - { - $arrayPos = array_search($data['candidateID'], $candidateIDArray); - if ($arrayPos !== false) - { - unset($candidateIDArray[$arrayPos]); - } - } - - /* Add to pipeline */ - foreach($candidateIDArray as $candidateID) - { - if (!$pipelines->add($candidateID, $jobOrderID, $this->_userID)) - { - CommonErrors::fatalModal(COMMONERROR_RECORDERROR, $this, 'Failed to add candidate to Job Order.'); - } - - $activityID = $activityEntries->add( - $candidateID, - DATA_ITEM_CANDIDATE, - 400, - 'Added candidate to job order.', - $this->_userID, - $jobOrderID - ); - - if (!eval(Hooks::get('CANDIDATE_ADD_TO_PIPELINE_POST_IND'))) return; - } - - if (!eval(Hooks::get('CANDIDATE_ADD_TO_PIPELINE_POST'))) return; - - $this->_template->assign('isFinishedMode', true); - $this->_template->assign('jobOrderID', $jobOrderID); - $this->_template->assign('candidateIDArray', $candidateIDArray); - $this->_template->display( - './modules/candidates/ConsiderSearchModal.tpl' - ); - } - - private function addActivityChangeStatus() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - /* Bail out if we don't have a valid job order ID. */ - if (!$this->isOptionalIDValid('jobOrderID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid job order ID.'); - } - - $selectedJobOrderID = $_GET['jobOrderID']; - $candidateID = $_GET['candidateID']; - - $candidates = new Candidates($this->_siteID); - $candidateData = $candidates->get($candidateID); - - /* Bail out if we got an empty result set. */ - if (empty($candidateData)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); - return; - } - - $pipelines = new Pipelines($this->_siteID); - $pipelineRS = $pipelines->getCandidatePipeline($candidateID); - - $statusRS = $pipelines->getStatusesForPicking(); - - if ($selectedJobOrderID != -1) - { - $selectedStatusID = ResultSetUtility::getColumnValueByIDValue( - $pipelineRS, 'jobOrderID', $selectedJobOrderID, 'statusID' - ); - } - else - { - $selectedStatusID = -1; - } - - /* Get the change status email template. */ - $emailTemplates = new EmailTemplates($this->_siteID); - $statusChangeTemplateRS = $emailTemplates->getByTag( - 'EMAIL_TEMPLATE_STATUSCHANGE' - ); - if (empty($statusChangeTemplateRS) || - empty($statusChangeTemplateRS['textReplaced'])) - { - $statusChangeTemplate = ''; - $emailDisabled = '1'; - } - else - { - $statusChangeTemplate = $statusChangeTemplateRS['textReplaced']; - $emailDisabled = $statusChangeTemplateRS['disabled']; - } - - /* Replace e-mail template variables. '%CANDSTATUS%', '%JBODTITLE%', - * '%JBODCLIENT%' are replaced by JavaScript. - */ - $stringsToFind = array( - '%CANDOWNER%', - '%CANDFIRSTNAME%', - '%CANDFULLNAME%' - ); - $replacementStrings = array( - $candidateData['ownerFullName'], - $candidateData['firstName'], - $candidateData['firstName'] . ' ' . $candidateData['lastName'], - $candidateData['firstName'], - $candidateData['firstName'] - ); - $statusChangeTemplate = str_replace( - $stringsToFind, - $replacementStrings, - $statusChangeTemplate - ); - - /* Are we in "Only Schedule Event" mode? */ - $onlyScheduleEvent = $this->isChecked('onlyScheduleEvent', $_GET); - - $calendar = new Calendar($this->_siteID); - $calendarEventTypes = $calendar->getAllEventTypes(); - - if (!eval(Hooks::get('CANDIDATE_ADD_ACTIVITY_CHANGE_STATUS'))) return; - - if (SystemUtility::isSchedulerEnabled() && !$_SESSION['CATS']->isDemo()) - { - $allowEventReminders = true; - } - else - { - $allowEventReminders = false; - } - - $this->_template->assign('candidateID', $candidateID); - $this->_template->assign('pipelineRS', $pipelineRS); - $this->_template->assign('statusRS', $statusRS); - $this->_template->assign('selectedJobOrderID', $selectedJobOrderID); - $this->_template->assign('selectedStatusID', $selectedStatusID); - $this->_template->assign('allowEventReminders', $allowEventReminders); - $this->_template->assign('userEmail', $_SESSION['CATS']->getEmail()); - $this->_template->assign('calendarEventTypes', $calendarEventTypes); - $this->_template->assign('statusChangeTemplate', $statusChangeTemplate); - $this->_template->assign('onlyScheduleEvent', $onlyScheduleEvent); - $this->_template->assign('emailDisabled', $emailDisabled); - $this->_template->assign('isFinishedMode', false); - $this->_template->assign('isJobOrdersMode', false); - $this->_template->display( - './modules/candidates/AddActivityChangeStatusModal.tpl' - ); - } - - private function onAddCandidateTags() - { - /* Bail out if we don't have a valid regardingjob order ID. */ - if (!$this->isOptionalIDValid('candidateID', $_POST)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid Candidate ID.'); - } - - /* Bail out if we don't have a valid regardingjob order ID. */ - if (!isset($_POST['candidate_tags']) || !is_array($_POST['candidate_tags'])) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid Tag ID.'); - } - - $candidateID = $_POST['candidateID']; - $tagIDs = $_POST['candidate_tags']; - - $tags = new Tags($this->_siteID); - $tags->AddTagsToCandidate($candidateID, $tagIDs); - - $this->_template->assign('candidateID', $candidateID); - $this->_template->assign('isFinishedMode', true); - $this->_template->display( - './modules/candidates/AssignCandidateTagModal.tpl' - ); - - } - - - private function addCandidateTags() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidateID = $_GET['candidateID']; - - $candidates = new Candidates($this->_siteID); - $candidateData = $candidates->get($candidateID); - - /* Bail out if we got an empty result set. */ - if (empty($candidateData)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); - return; - /*$this->fatalModal( - 'The specified candidate ID could not be found.' - );*/ - } - - $tags = new Tags($this->_siteID); - $tagsRS = $tags->getAll(); - - $this->_template->assign('candidateID', $candidateID); - $this->_template->assign('assignedTags', $tags->getCandidateTagsID($candidateID)); - $this->_template->assign('isFinishedMode', false); - - $this->_template->assign('tagsRS', $tagsRS); - $this->_template->display( - './modules/candidates/AssignCandidateTagModal.tpl' - ); - - } - - - private function onAddActivityChangeStatus() - { - /* Bail out if we don't have a valid regardingjob order ID. */ - if (!$this->isOptionalIDValid('regardingID', $_POST)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid job order ID.'); - } - - $regardingID = $_POST['regardingID']; - - $this->_addActivityChangeStatus(false, $regardingID); - } - - /* - * Called by handleRequest() to process removing a candidate from the - * pipeline for a job order. - */ - private function onRemoveFromPipeline() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - /* Bail out if we don't have a valid job order ID. */ - if (!$this->isRequiredIDValid('jobOrderID', $_GET)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid job order ID.'); - } - - $candidateID = $_GET['candidateID']; - $jobOrderID = $_GET['jobOrderID']; - - if (!eval(Hooks::get('CANDIDATE_REMOVE_FROM_PIPELINE_PRE'))) return; - - $pipelines = new Pipelines($this->_siteID); - $pipelines->remove($candidateID, $jobOrderID); - - if (!eval(Hooks::get('CANDIDATE_REMOVE_FROM_PIPELINE_POST'))) return; - - CATSUtility::transferRelativeURI( - 'm=candidates&a=show&candidateID=' . $candidateID - ); - } - - /* - * Called by handleRequest() to process loading the search page. - */ - private function search() - { - $savedSearches = new SavedSearches($this->_siteID); - $savedSearchRS = $savedSearches->get(DATA_ITEM_CANDIDATE); - - if (!eval(Hooks::get('CANDIDATE_SEARCH'))) return; - - $this->_template->assign('wildCardString', ''); - $this->_template->assign('savedSearchRS', $savedSearchRS); - $this->_template->assign('active', $this); - $this->_template->assign('subActive', 'Search Candidates'); - $this->_template->assign('isResultsMode', false); - $this->_template->assign('isResumeMode', false); - $this->_template->assign('resumeWildCardString', ''); - $this->_template->assign('keySkillsWildCardString', ''); - $this->_template->assign('fullNameWildCardString', ''); - $this->_template->assign('phoneNumberWildCardString', ''); - $this->_template->assign('mode', ''); - $this->_template->display('./modules/candidates/Search.tpl'); - } - - /* - * Called by handleRequest() to process displaying the search results. - */ - private function onSearch() - { - /* Bail out to prevent an error if the GET string doesn't even contain - * a field named 'wildCardString' at all. - */ - if (!isset($_GET['wildCardString'])) - { - $this->listByView('No wild card string specified.'); - return; - } - - $query = trim($_GET['wildCardString']); - - /* Initialize stored wildcard strings to safe default values. */ - $resumeWildCardString = ''; - $keySkillsWildCardString = ''; - $phoneNumberWildCardString = ''; - $fullNameWildCardString = ''; - - /* Set up sorting. */ - if ($this->isRequiredIDValid('page', $_GET)) - { - $currentPage = $_GET['page']; - } - else - { - $currentPage = 1; - } - - $searchPager = new SearchPager( - CANDIDATES_PER_PAGE, $currentPage, $this->_siteID - ); - - if ($searchPager->isSortByValid('sortBy', $_GET)) - { - $sortBy = $_GET['sortBy']; - } - else - { - $sortBy = 'lastName'; - } - - if ($searchPager->isSortDirectionValid('sortDirection', $_GET)) - { - $sortDirection = $_GET['sortDirection']; - } - else - { - $sortDirection = 'ASC'; - } - - $baseURL = CATSUtility::getFilteredGET( - array('sortBy', 'sortDirection', 'page'), '&' - ); - $searchPager->setSortByParameters($baseURL, $sortBy, $sortDirection); - - $candidates = new Candidates($this->_siteID); - - /* Get our current searching mode. */ - $mode = $this->getTrimmedInput('mode', $_GET); - - /* Execute the search. */ - $search = new SearchCandidates($this->_siteID); - switch ($mode) - { - case 'searchByFullName': - $rs = $search->byFullName($query, $sortBy, $sortDirection); - - foreach ($rs as $rowIndex => $row) - { - if (!empty($row['ownerFirstName'])) - { - $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( - $row['ownerFirstName'], - $row['ownerLastName'], - false, - LAST_NAME_MAXLEN - ); - } - else - { - $rs[$rowIndex]['ownerAbbrName'] = 'None'; - } - - $rsResume = $candidates->getResumes($row['candidateID']); - if (isset($rsResume[0])) - { - $rs[$rowIndex]['resumeID'] = $rsResume[0]['attachmentID']; - } - } - - $isResumeMode = false; - - $fullNameWildCardString = $query; - break; - - case 'searchByKeySkills': - $rs = $search->byKeySkills($query, $sortBy, $sortDirection); - - foreach ($rs as $rowIndex => $row) - { - if (!empty($row['ownerFirstName'])) - { - $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( - $row['ownerFirstName'], - $row['ownerLastName'], - false, - LAST_NAME_MAXLEN - ); - } - else - { - $rs[$rowIndex]['ownerAbbrName'] = 'None'; - } - - $rsResume = $candidates->getResumes($row['candidateID']); - if (isset($rsResume[0])) - { - $rs[$rowIndex]['resumeID'] = $rsResume[0]['attachmentID']; - } - } - - $isResumeMode = false; - - $keySkillsWildCardString = $query; - - break; - - case 'searchByResume': - $searchPager = new SearchByResumePager( - 20, - $currentPage, - $this->_siteID, - $query, - $sortBy, - $sortDirection - ); - - $baseURL = 'm=candidates&a=search&getback=getback&mode=searchByResume&wildCardString=' - . urlencode($query) - . '&searchByResume=Search'; - - $searchPager->setSortByParameters( - $baseURL, $sortBy, $sortDirection - ); - - $rs = $searchPager->getPage(); - - $currentPage = $searchPager->getCurrentPage(); - $totalPages = $searchPager->getTotalPages(); - - $pageStart = $searchPager->getThisPageStartRow() + 1; - - if (($searchPager->getThisPageStartRow() + 20) <= $searchPager->getTotalRows()) - { - $pageEnd = $searchPager->getThisPageStartRow() + 20; - } - else - { - $pageEnd = $searchPager->getTotalRows(); - } - - foreach ($rs as $rowIndex => $row) - { - $rs[$rowIndex]['excerpt'] = SearchUtility::searchExcerpt( - $query, $row['text'] - ); - - if (!empty($row['ownerFirstName'])) - { - $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( - $row['ownerFirstName'], - $row['ownerLastName'], - false, - LAST_NAME_MAXLEN - ); - } - else - { - $rs[$rowIndex]['ownerAbbrName'] = 'None'; - } - } - - $isResumeMode = true; - - $this->_template->assign('active', $this); - $this->_template->assign('currentPage', $currentPage); - $this->_template->assign('pageStart', $pageStart); - $this->_template->assign('totalResults', $searchPager->getTotalRows()); - $this->_template->assign('pageEnd', $pageEnd); - $this->_template->assign('totalPages', $totalPages); - - $resumeWildCardString = $query; - break; - - case 'phoneNumber': - $rs = $search->byPhone($query, $sortBy, $sortDirection); - - foreach ($rs as $rowIndex => $row) - { - if (!empty($row['ownerFirstName'])) - { - $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( - $row['ownerFirstName'], - $row['ownerLastName'], - false, - LAST_NAME_MAXLEN - ); - } - else - { - $rs[$rowIndex]['ownerAbbrName'] = 'None'; - } - - $rsResume = $candidates->getResumes($row['candidateID']); - if (isset($rsResume[0])) - { - $rs[$rowIndex]['resumeID'] = $rsResume[0]['attachmentID']; - } - } - - $isResumeMode = false; - - $phoneNumberWildCardString = $query; - break; - - default: - $this->listByView('Invalid search mode.'); - return; - break; - } - - $candidateIDs = implode(',', ResultSetUtility::getColumnValues($rs, 'candidateID')); - $exportForm = ExportUtility::getForm( - DATA_ITEM_CANDIDATE, $candidateIDs, 32, 9 - ); - - if (!eval(Hooks::get('CANDIDATE_ON_SEARCH'))) return; - - /* Save the search. */ - $savedSearches = new SavedSearches($this->_siteID); - $savedSearches->add( - DATA_ITEM_CANDIDATE, - $query, - $_SERVER['REQUEST_URI'], - false - ); - $savedSearchRS = $savedSearches->get(DATA_ITEM_CANDIDATE); - - $this->_template->assign('savedSearchRS', $savedSearchRS); - $this->_template->assign('exportForm', $exportForm); - $this->_template->assign('active', $this); - $this->_template->assign('rs', $rs); - $this->_template->assign('pager', $searchPager); - $this->_template->assign('isResultsMode', true); - $this->_template->assign('isResumeMode', $isResumeMode); - $this->_template->assign('wildCardString', $query); - $this->_template->assign('resumeWildCardString', $resumeWildCardString); - $this->_template->assign('keySkillsWildCardString', $keySkillsWildCardString); - $this->_template->assign('fullNameWildCardString', $fullNameWildCardString); - $this->_template->assign('phoneNumberWildCardString', $phoneNumberWildCardString); - $this->_template->assign('mode', $mode); - $this->_template->display('./modules/candidates/Search.tpl'); - } - - /* - * Called by handleRequest() to process showing a resume preview. - */ - private function viewResume() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('attachmentID', $_GET)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid attachment ID.'); - } - - $attachmentID = $_GET['attachmentID']; - - /* Get the search string. */ - $query = $this->getTrimmedInput('wildCardString', $_GET); - - /* Get resume text. */ - $candidates = new Candidates($this->_siteID); - $data = $candidates->getResume($attachmentID); - - if (!empty($data)) - { - /* Keyword highlighting. */ - $data['text'] = SearchUtility::makePreview($query, $data['text']); - } - - if (!eval(Hooks::get('CANDIDATE_VIEW_RESUME'))) return; - - $this->_template->assign('active', $this); - $this->_template->assign('data', $data); - $this->_template->display('./modules/candidates/ResumeView.tpl'); - } - - private function addEditImage() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidateID = $_GET['candidateID']; - - $attachments = new Attachments($this->_siteID); - $attachmentsRS = $attachments->getAll( - DATA_ITEM_CANDIDATE, $candidateID - ); - - if (!eval(Hooks::get('CANDIDATE_ADD_EDIT_IMAGE'))) return; - - $this->_template->assign('isFinishedMode', false); - $this->_template->assign('candidateID', $candidateID); - $this->_template->assign('attachmentsRS', $attachmentsRS); - $this->_template->display( - './modules/candidates/CreateImageAttachmentModal.tpl' - ); - } - - /* - * Called by handleRequest() to process creating an attachment. - */ - private function onAddEditImage() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_POST)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidateID = $_POST['candidateID']; - - if (!eval(Hooks::get('CANDIDATE_ON_ADD_EDIT_IMAGE_PRE'))) return; - - $attachmentCreator = new AttachmentCreator($this->_siteID); - $attachmentCreator->createFromUpload( - DATA_ITEM_CANDIDATE, $candidateID, 'file', true, false - ); - - if ($attachmentCreator->isError()) - { - CommonErrors::fatalModal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); - return; - //$this->fatalModal($attachmentCreator->getError()); - } - - if (!eval(Hooks::get('CANDIDATE_ON_ADD_EDIT_IMAGE_POST'))) return; - - $this->_template->assign('isFinishedMode', true); - $this->_template->assign('candidateID', $candidateID); - $this->_template->display( - './modules/candidates/CreateImageAttachmentModal.tpl' - ); - } - - /* - * Called by handleRequest() to process loading the create attachment - * modal dialog. - */ - private function createAttachment() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidateID = $_GET['candidateID']; - - if (!eval(Hooks::get('CANDIDATE_CREATE_ATTACHMENT'))) return; - - $this->_template->assign('isFinishedMode', false); - $this->_template->assign('candidateID', $candidateID); - $this->_template->display( - './modules/candidates/CreateAttachmentModal.tpl' - ); - } - - /* - * Called by handleRequest() to process creating an attachment. - */ - private function onCreateAttachment() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_POST)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - /* Bail out if we don't have a valid resume status. */ - if (!$this->isRequiredIDValid('resume', $_POST, true) || - $_POST['resume'] < 0 || $_POST['resume'] > 1) - { - CommonErrors::fatalModal(COMMONERROR_RECORDERROR, $this, 'Invalid resume status.'); - } - - $candidateID = $_POST['candidateID']; - - if ($_POST['resume'] == '1') - { - $isResume = true; - } - else - { - $isResume = false; - } - - if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_PRE'))) return; - - $attachmentCreator = new AttachmentCreator($this->_siteID); - $attachmentCreator->createFromUpload( - DATA_ITEM_CANDIDATE, $candidateID, 'file', false, $isResume - ); - - if ($attachmentCreator->isError()) - { - CommonErrors::fatalModal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); - return; - //$this->fatalModal($attachmentCreator->getError()); - } - - if ($attachmentCreator->duplicatesOccurred()) - { - $this->fatalModal( - 'This attachment has already been added to this candidate.' - ); - } - - $isTextExtractionError = $attachmentCreator->isTextExtractionError(); - $textExtractionErrorMessage = $attachmentCreator->getTextExtractionError(); - $resumeText = $attachmentCreator->getExtractedText(); - - if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_POST'))) return; - - $this->_template->assign('resumeText', $resumeText); - $this->_template->assign('isFinishedMode', true); - $this->_template->assign('candidateID', $candidateID); - $this->_template->display( - './modules/candidates/CreateAttachmentModal.tpl' - ); - } - - /* - * Called by handleRequest() to process deleting an attachment. - */ - private function onDeleteAttachment() - { - /* Bail out if we don't have a valid attachment ID. */ - if (!$this->isRequiredIDValid('attachmentID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid attachment ID.'); - } - - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - $candidateID = $_GET['candidateID']; - $attachmentID = $_GET['attachmentID']; - - if (!eval(Hooks::get('CANDIDATE_ON_DELETE_ATTACHMENT_PRE'))) return; - - $attachments = new Attachments($this->_siteID); - $attachments->delete($attachmentID); - - if (!eval(Hooks::get('CANDIDATE_ON_DELETE_ATTACHMENT_POST'))) return; - - CATSUtility::transferRelativeURI( - 'm=candidates&a=show&candidateID=' . $candidateID - ); - } - - //TODO: Document me. - //Only accessable by MSA users - hides this job order from everybody by - private function administrativeHideShow() - { - /* Bail out if we don't have a valid joborder ID. */ - if (!$this->isRequiredIDValid('candidateID', $_GET)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid Job Order ID.'); - } - - /* Bail out if we don't have a valid status ID. */ - if (!$this->isRequiredIDValid('state', $_GET, true)) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid state ID.'); - } - - $candidateID = $_GET['candidateID']; - - // FIXME: Checkbox? - $state = (boolean) $_GET['state']; - - $candidates = new Candidates($this->_siteID); - $candidates->administrativeHideShow($candidateID, $state); - - CATSUtility::transferRelativeURI('m=candidates&a=show&candidateID='.$candidateID); - } - - /** - * Formats SQL result set for display. This is factored out for code - * clarity. - * - * @param array result set from listByView() - * @return array formatted result set - */ - private function _formatListByViewResults($resultSet) - { - if (empty($resultSet)) - { - return $resultSet; - } - - foreach ($resultSet as $rowIndex => $row) - { - if ($resultSet[$rowIndex]['isHot'] == 1) - { - $resultSet[$rowIndex]['linkClass'] = 'jobLinkHot'; - } - else - { - $resultSet[$rowIndex]['linkClass'] = 'jobLinkCold'; - } - - if (!empty($resultSet[$rowIndex]['ownerFirstName'])) - { - $resultSet[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( - $resultSet[$rowIndex]['ownerFirstName'], - $resultSet[$rowIndex]['ownerLastName'], - false, - LAST_NAME_MAXLEN - ); - } - else - { - $resultSet[$rowIndex]['ownerAbbrName'] = 'None'; - } - - if ($resultSet[$rowIndex]['submitted'] == 1) - { - $resultSet[$rowIndex]['iconTag'] = ''; - } - else - { - $resultSet[$rowIndex]['iconTag'] = ''; - } - - if ($resultSet[$rowIndex]['attachmentPresent'] == 1) - { - $resultSet[$rowIndex]['iconTag'] .= ''; - } - else - { - $resultSet[$rowIndex]['iconTag'] .= ''; - } - - - if (empty($resultSet[$rowIndex]['keySkills'])) - { - $resultSet[$rowIndex]['keySkills'] = ' '; - } - else - { - $resultSet[$rowIndex]['keySkills'] = htmlspecialchars( - $resultSet[$rowIndex]['keySkills'] - ); - } - - /* Truncate Key Skills to fit the column width */ - if (strlen($resultSet[$rowIndex]['keySkills']) > self::TRUNCATE_KEYSKILLS) - { - $resultSet[$rowIndex]['keySkills'] = substr( - $resultSet[$rowIndex]['keySkills'], - 0, - self::TRUNCATE_KEYSKILLS - ) . "..."; - } - } - - return $resultSet; - } - - /** - * Adds a candidate. This is factored out for code clarity. - * - * @param boolean is modal window - * @param string module directory - * @return integer candidate ID - */ - private function _addCandidate($isModal, $directoryOverride = '') - { - /* Module directory override for fatal() calls. */ - if ($directoryOverride != '') - { - $moduleDirectory = $directoryOverride; - } - else - { - $moduleDirectory = $this->_moduleDirectory; - } - - /* Modal override for fatal() calls. */ - if ($isModal) - { - $fatal = 'fatalModal'; - } - else - { - $fatal = 'fatal'; - } - - /* Bail out if we received an invalid availability date; if not, go - * ahead and convert the date to MySQL format. - */ - $dateAvailable = $this->getTrimmedInput('dateAvailable', $_POST); - if (!empty($dateAvailable)) - { - if (!DateUtility::validate('-', $dateAvailable, DATE_FORMAT_MMDDYY)) - { - $this->$fatal('Invalid availability date.', $moduleDirectory); - } - - /* Convert start_date to something MySQL can understand. */ - $dateAvailable = DateUtility::convert( - '-', $dateAvailable, DATE_FORMAT_MMDDYY, DATE_FORMAT_YYYYMMDD - ); - } - - $formattedPhoneHome = StringUtility::extractPhoneNumber( - $this->getTrimmedInput('phoneHome', $_POST) - ); - if (!empty($formattedPhoneHome)) - { - $phoneHome = $formattedPhoneHome; - } - else - { - $phoneHome = $this->getTrimmedInput('phoneHome', $_POST); - } - - $formattedPhoneCell = StringUtility::extractPhoneNumber( - $this->getTrimmedInput('phoneCell', $_POST) - ); - if (!empty($formattedPhoneCell)) - { - $phoneCell = $formattedPhoneCell; - } - else - { - $phoneCell = $this->getTrimmedInput('phoneCell', $_POST); - } - - $formattedPhoneWork = StringUtility::extractPhoneNumber( - $this->getTrimmedInput('phoneWork', $_POST) - ); - if (!empty($formattedPhoneWork)) - { - $phoneWork = $formattedPhoneWork; - } - else - { - $phoneWork = $this->getTrimmedInput('phoneWork', $_POST); - } - - /* Can Relocate */ - $canRelocate = $this->isChecked('canRelocate', $_POST); - - $lastName = $this->getTrimmedInput('lastName', $_POST); - $middleName = $this->getTrimmedInput('middleName', $_POST); - $firstName = $this->getTrimmedInput('firstName', $_POST); - $email1 = $this->getTrimmedInput('email1', $_POST); - $email2 = $this->getTrimmedInput('email2', $_POST); - $address = $this->getTrimmedInput('address', $_POST); - $city = $this->getTrimmedInput('city', $_POST); - $state = $this->getTrimmedInput('state', $_POST); - $zip = $this->getTrimmedInput('zip', $_POST); - $source = $this->getTrimmedInput('source', $_POST); - $keySkills = $this->getTrimmedInput('keySkills', $_POST); - $currentEmployer = $this->getTrimmedInput('currentEmployer', $_POST); - $currentPay = $this->getTrimmedInput('currentPay', $_POST); - $desiredPay = $this->getTrimmedInput('desiredPay', $_POST); - $notes = $this->getTrimmedInput('notes', $_POST); - $webSite = $this->getTrimmedInput('webSite', $_POST); - $bestTimeToCall = $this->getTrimmedInput('bestTimeToCall', $_POST); - $gender = $this->getTrimmedInput('gender', $_POST); - $race = $this->getTrimmedInput('race', $_POST); - $veteran = $this->getTrimmedInput('veteran', $_POST); - $disability = $this->getTrimmedInput('disability', $_POST); - - /* Candidate source list editor. */ - $sourceCSV = $this->getTrimmedInput('sourceCSV', $_POST); - - /* Text resume. */ - $textResumeBlock = $this->getTrimmedInput('textResumeBlock', $_POST); - $textResumeFilename = $this->getTrimmedInput('textResumeFilename', $_POST); - - /* File resume. */ - $associatedFileResumeID = $this->getTrimmedInput('associatedbFileResumeID', $_POST); - - /* Bail out if any of the required fields are empty. */ - if (empty($firstName) || empty($lastName)) - { - CommonErrors::fatal(COMMONERROR_MISSINGFIELDS, $this); - } - - if (!eval(Hooks::get('CANDIDATE_ON_ADD_PRE'))) return; - - $candidates = new Candidates($this->_siteID); - - $duplicatesID = $candidates->checkDuplicity($firstName, $middleName, $lastName, $email1, $email2, $phoneHome, $phoneCell, $phoneWork, $address, $city); - - $candidateID = $candidates->add( - $firstName, - $middleName, - $lastName, - $email1, - $email2, - $phoneHome, - $phoneCell, - $phoneWork, - $address, - $city, - $state, - $zip, - $source, - $keySkills, - $dateAvailable, - $currentEmployer, - $canRelocate, - $currentPay, - $desiredPay, - $notes, - $webSite, - $bestTimeToCall, - $this->_userID, - $this->_userID, - $gender, - $race, - $veteran, - $disability - ); - - - if ($candidateID <= 0) - { - return $candidateID; - } - - if(sizeof($duplicatesID) > 0) - { - $candidates->addDuplicates($candidateID, $duplicatesID); - } - - /* Update extra fields. */ - $candidates->extraFields->setValuesOnEdit($candidateID); - - /* Update possible source list. */ - $sources = $candidates->getPossibleSources(); - $sourcesDifferences = ListEditor::getDifferencesFromList( - $sources, 'name', 'sourceID', $sourceCSV - ); - $candidates->updatePossibleSources($sourcesDifferences); - - /* Associate an exsisting resume if the user created a candidate with one. (Bulk) */ - if (isset($_POST['associatedAttachment'])) - { - $attachmentID = $_POST['associatedAttachment']; - - $attachments = new Attachments($this->_siteID); - $attachments->setDataItemID($attachmentID, $candidateID, DATA_ITEM_CANDIDATE); - } - - /* Attach a resume if the user uploaded one. (http POST) */ - /* NOTE: This function cannot be called if parsing is enabled */ - else if (isset($_FILES['file']) && !empty($_FILES['file']['name'])) - { - if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_PRE'))) return; - - $attachmentCreator = new AttachmentCreator($this->_siteID); - $attachmentCreator->createFromUpload( - DATA_ITEM_CANDIDATE, $candidateID, 'file', false, true - ); - - if ($attachmentCreator->isError()) - { - CommonErrors::fatal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); - } - - - if ($attachmentCreator->duplicatesOccurred()) - { - $this->listByView( - 'This attachment has already been added to this candidate.' - ); - return; - } - - $isTextExtractionError = $attachmentCreator->isTextExtractionError(); - $textExtractionErrorMessage = $attachmentCreator->getTextExtractionError(); - - // FIXME: Show parse errors! - - if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_POST'))) return; - } - - /** - * User has loaded and/or parsed a resume. The attachment is saved in a temporary - * file already and just needs to be attached. The attachment has also successfully - * been DocumentToText converted, so we know it's a good file. - */ - else if (LicenseUtility::isParsingEnabled()) - { - /** - * Description: User clicks "browse" and selects a resume file. User doesn't click - * upload. The resume file is STILL uploaded. - * Controversial: User uploads a resume, parses, etc. User selects a new file with - * "Browse" but doesn't click "Upload". New file is accepted. - * It's technically correct either way, I'm opting for the "use whats in "file" - * box over what's already uploaded method to avoid losing resumes on candidate - * additions. - */ - $newFile = FileUtility::getUploadFileFromPost($this->_siteID, 'addcandidate', 'documentFile'); - - if ($newFile !== false) - { - $newFilePath = FileUtility::getUploadFilePath($this->_siteID, 'addcandidate', $newFile); - - $tempFile = $newFile; - $tempFullPath = $newFilePath; - } - else - { - $attachmentCreated = false; - - $tempFile = false; - $tempFullPath = false; - - if (isset($_POST['documentTempFile']) && !empty($_POST['documentTempFile'])) - { - $tempFile = $_POST['documentTempFile']; - // Get the path of the file they uploaded already to attach - $tempFullPath = FileUtility::getUploadFilePath( - $this->_siteID, // ID of the containing site - 'addcandidate', // Sub-directory in their storage - $tempFile // Name of the file (not pathed) - ); - } - } - - if ($tempFile !== false && $tempFullPath !== false) - { - if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_PRE'))) return; - - $attachmentCreator = new AttachmentCreator($this->_siteID); - $attachmentCreator->createFromFile( - DATA_ITEM_CANDIDATE, $candidateID, $tempFullPath, $tempFile, '', true, true - ); - - if ($attachmentCreator->isError()) - { - CommonErrors::fatal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); - } - - - if ($attachmentCreator->duplicatesOccurred()) - { - $this->listByView( - 'This attachment has already been added to this candidate.' - ); - return; - } - - $isTextExtractionError = $attachmentCreator->isTextExtractionError(); - $textExtractionErrorMessage = $attachmentCreator->getTextExtractionError(); - - if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_POST'))) return; - - // Remove the cleanup cookie since the file no longer exists - setcookie('CATS_SP_TEMP_FILE', ''); - - $attachmentCreated = true; - } - - if (!$attachmentCreated && isset($_POST['documentText']) && !empty($_POST['documentText'])) - { - // Resume was pasted into the form and not uploaded from a file - - if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_PRE'))) return; - - $attachmentCreator = new AttachmentCreator($this->_siteID); - $attachmentCreator->createFromText( - DATA_ITEM_CANDIDATE, $candidateID, $_POST['documentText'], 'MyResume.txt', true - ); - - if ($attachmentCreator->isError()) - { - CommonErrors::fatal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); - } - - if ($attachmentCreator->duplicatesOccurred()) - { - $this->listByView( - 'This attachment has already been added to this candidate.' - ); - return; - } - - if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_POST'))) return; - } - } - - /* Create a text resume if the user posted one. (automated tool) */ - else if (!empty($textResumeBlock)) - { - $attachmentCreator = new AttachmentCreator($this->_siteID); - $attachmentCreator->createFromText( - DATA_ITEM_CANDIDATE, $candidateID, $textResumeBlock, $textResumeFilename, true - ); - - if ($attachmentCreator->isError()) - { - CommonErrors::fatal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); - return; - //$this->fatal($attachmentCreator->getError()); - } - $isTextExtractionError = $attachmentCreator->isTextExtractionError(); - $textExtractionErrorMessage = $attachmentCreator->getTextExtractionError(); - - // FIXME: Show parse errors! - } - - if (!eval(Hooks::get('CANDIDATE_ON_ADD_POST'))) return; - - return $candidateID; - } - - /** - * Processes an Add Activity / Change Status form and displays - * candidates/AddActivityChangeStatusModal.tpl. This is factored out - * for code clarity. - * - * @param boolean from joborders module perspective - * @param integer "regarding" job order ID or -1 - * @param string module directory - * @return void - */ - private function _addActivityChangeStatus($isJobOrdersMode, $regardingID, - $directoryOverride = '') - { - $notificationHTML = ''; - - $pipelines = new Pipelines($this->_siteID); - $statusRS = $pipelines->getStatusesForPicking(); - - /* Module directory override for fatal() calls. */ - if ($directoryOverride != '') - { - $moduleDirectory = $directoryOverride; - } - else - { - $moduleDirectory = $this->_moduleDirectory; - } - - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('candidateID', $_POST)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - } - - /* Do we have a valid status ID. */ - if (!$this->isOptionalIDValid('statusID', $_POST)) - { - $statusID = -1; - } - else - { - $statusID = $_POST['statusID']; - if($statusID == PIPELINE_STATUS_PLACED) - { - $jobOrders = new JobOrders($this->_siteID); - $canBeHired = $jobOrders->checkOpenings($regardingID); - if(!$canBeHired) - { - $this->fatalModal( - 'This job order has been filled. Cannot assign the status Placed to any other candidate.' - ); - } - } - } - - $candidateID = $_POST['candidateID']; - - if (!eval(Hooks::get('CANDIDATE_ON_ADD_ACTIVITY_CHANGE_STATUS_PRE'))) return; - - if ($this->isChecked('addActivity', $_POST)) - { - /* Bail out if we don't have a valid job order ID. */ - if (!$this->isOptionalIDValid('activityTypeID', $_POST)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid activity type ID.'); - } - - $activityTypeID = $_POST['activityTypeID']; - - $activityNote = $this->getTrimmedInput('activityNote', $_POST); - - $activityNote = htmlspecialchars($activityNote); - - // FIXME: Move this to a highlighter-method? */ - if (strpos($activityNote, 'Status change: ') === 0) - { - foreach ($statusRS as $data) - { - $activityNote = StringUtility::replaceOnce( - $data['status'], - '' . $data['status'] . '', - $activityNote - ); - } - } - - /* Add the activity entry. */ - $activityEntries = new ActivityEntries($this->_siteID); - $activityID = $activityEntries->add( - $candidateID, - DATA_ITEM_CANDIDATE, - $activityTypeID, - $activityNote, - $this->_userID, - $regardingID - ); - $activityTypes = $activityEntries->getTypes(); - $activityTypeDescription = ResultSetUtility::getColumnValueByIDValue( - $activityTypes, 'typeID', $activityTypeID, 'type' - ); - - $activityAdded = true; - } - else - { - $activityAdded = false; - $activityNote = ''; - $activityTypeDescription = ''; - } - - if ($regardingID <= 0 || $statusID == -1) - { - $statusChanged = false; - $oldStatusDescription = ''; - $newStatusDescription = ''; - } - else - { - $data = $pipelines->get($candidateID, $regardingID); - - /* Bail out if we got an empty result set. */ - if (empty($data)) - { - $this->fatalModal( - 'The specified pipeline entry could not be found.' - ); - } - - $validStatus = ResultSetUtility::findRowByColumnValue( - $statusRS, 'statusID', $statusID - ); - - /* If the status is invalid or unchanged, don't mess with it. */ - if ($validStatus === false || $statusID == $data['status']) - { - $oldStatusDescription = ''; - $newStatusDescription = ''; - $statusChanged = false; - } - else - { - $oldStatusDescription = $data['status']; - $newStatusDescription = ResultSetUtility::getColumnValueByIDValue( - $statusRS, 'statusID', $statusID, 'status' - ); - - if ($oldStatusDescription != $newStatusDescription) - { - $statusChanged = true; - } - else - { - $statusChanged = false; - } - } - - if ($statusChanged && $this->isChecked('triggerEmail', $_POST)) - { - $customMessage = $this->getTrimmedInput('customMessage', $_POST); - - // FIXME: Actually validate the e-mail address? - if (empty($data['candidateEmail'])) - { - $email = ''; - $notificationHTML = '

Error: An e-mail notification' - . ' could not be sent to the candidate because the candidate' - . ' does not have a valid e-mail address.

'; - } - else if (empty($customMessage)) - { - $email = ''; - $notificationHTML = '

Error: An e-mail notification' - . ' will not be sent because the message text specified was blank.

'; - } - else if ($this->getUserAccessLevel('candidates.emailCandidates') == ACCESS_LEVEL_DEMO) - { - $email = ''; - $notificationHTML = '

Error: Demo users can not send' - . ' E-Mails. No E-Mail was sent.

'; - } - else - { - $email = $data['candidateEmail']; - $notificationHTML = '

An e-mail notification has been sent to the candidate.

'; - } - } - else - { - $email = ''; - $customMessage = ''; - $notificationHTML = '

No e-mail notification has been sent to the candidate.

'; - } - - /* Set the pipeline entry's status, but don't send e-mails for now. */ - $pipelines->setStatus( - $candidateID, $regardingID, $statusID, $email, $customMessage - ); - - /* If status = placed, and open positions > 0, reduce number of open positions by one. */ - if ($statusID == PIPELINE_STATUS_PLACED && is_numeric($data['openingsAvailable']) && $data['openingsAvailable'] > 0) - { - $jobOrders = new JobOrders($this->_siteID); - $jobOrders->updateOpeningsAvailable($regardingID, $data['openingsAvailable'] - 1); - } - - /* If status is changed from placed to something else, increase number of open positions by one. */ - if ($statusID != PIPELINE_STATUS_PLACED && $data['statusID'] == PIPELINE_STATUS_PLACED) - { - $jobOrders = new JobOrders($this->_siteID); - $jobOrders->updateOpeningsAvailable($regardingID, $data['openingsAvailable'] + 1); - } - } - - if ($this->isChecked('scheduleEvent', $_POST)) - { - /* Bail out if we received an invalid date. */ - $trimmedDate = $this->getTrimmedInput('dateAdd', $_POST); - if (empty($trimmedDate) || - !DateUtility::validate('-', $trimmedDate, DATE_FORMAT_MMDDYY)) - { - CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid date.'); - } - - /* Bail out if we don't have a valid event type. */ - if (!$this->isRequiredIDValid('eventTypeID', $_POST)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid event type ID.'); - } - - /* Bail out if we don't have a valid time format ID. */ - if (!isset($_POST['allDay']) || - ($_POST['allDay'] != '0' && $_POST['allDay'] != '1')) - { - CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid time format ID.'); - } - - $eventTypeID = $_POST['eventTypeID']; - - if ($_POST['allDay'] == 1) - { - $allDay = true; - } - else - { - $allDay = false; - } - - $publicEntry = $this->isChecked('publicEntry', $_POST); - - $reminderEnabled = $this->isChecked('reminderToggle', $_POST); - $reminderEmail = $this->getTrimmedInput('sendEmail', $_POST); - $reminderTime = $this->getTrimmedInput('reminderTime', $_POST); - $duration = $this->getTrimmedInput('duration', $_POST);; - - /* Is this a scheduled event or an all day event? */ - if ($allDay) - { - $date = DateUtility::convert( - '-', $trimmedDate, DATE_FORMAT_MMDDYY, DATE_FORMAT_YYYYMMDD - ); - - $hour = 12; - $minute = 0; - $meridiem = 'AM'; - } - else - { - /* Bail out if we don't have a valid hour. */ - if (!isset($_POST['hour'])) - { - CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid hour.'); - } - - /* Bail out if we don't have a valid minute. */ - if (!isset($_POST['minute'])) - { - CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid minute.'); - } - - /* Bail out if we don't have a valid meridiem value. */ - if (!isset($_POST['meridiem']) || - ($_POST['meridiem'] != 'AM' && $_POST['meridiem'] != 'PM')) - { - $this->fatalModal( - 'Invalid meridiem value.', $moduleDirectory - ); - } - - $hour = $_POST['hour']; - $minute = $_POST['minute']; - $meridiem = $_POST['meridiem']; - - /* Convert formatted time to UNIX timestamp. */ - $time = strtotime( - sprintf('%s:%s %s', $hour, $minute, $meridiem) - ); - - /* Create MySQL date string w/ 24hr time (YYYY-MM-DD HH:MM:SS). */ - $date = sprintf( - '%s %s', - DateUtility::convert( - '-', - $trimmedDate, - DATE_FORMAT_MMDDYY, - DATE_FORMAT_YYYYMMDD - ), - date('H:i:00', $time) - ); - } - - $description = $this->getTrimmedInput('description', $_POST); - $title = $this->getTrimmedInput('title', $_POST); - - /* Bail out if any of the required fields are empty. */ - if (empty($title)) - { - CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this); - return; - /*$this->fatalModal( - 'Required fields are missing.', $moduleDirectory - );*/ - } - - if ($regardingID > 0) - { - $eventJobOrderID = $regardingID; - } - else - { - $eventJobOrderID = -1; - } - - $calendar = new Calendar($this->_siteID); - $eventID = $calendar->addEvent( - $eventTypeID, $date, $description, $allDay, $this->_userID, - $candidateID, DATA_ITEM_CANDIDATE, $eventJobOrderID, $title, - $duration, $reminderEnabled, $reminderEmail, $reminderTime, - $publicEntry, $_SESSION['CATS']->getTimeZoneOffset() - ); - - if ($eventID <= 0) - { - $this->fatalModal( - 'Failed to add calendar event.', $moduleDirectory - ); - } - - /* Extract the date parts from the specified date. */ - $parsedDate = strtotime($date); - $formattedDate = date('l, F jS, Y', $parsedDate); - - $calendar = new Calendar($this->_siteID); - $calendarEventTypes = $calendar->getAllEventTypes(); - - $eventTypeDescription = ResultSetUtility::getColumnValueByIDValue( - $calendarEventTypes, 'typeID', $eventTypeID, 'description' - ); - - $eventHTML = sprintf( - '

An event of type %s has been scheduled on %s.

', - htmlspecialchars($eventTypeDescription), - htmlspecialchars($formattedDate) - - ); - $eventScheduled = true; - } - else - { - $eventHTML = '

No event has been scheduled.

'; - $eventScheduled = false; - } - - if (isset($_GET['onlyScheduleEvent'])) - { - $onlyScheduleEvent = true; - } - else - { - $onlyScheduleEvent = false; - } - - if (!$statusChanged && !$activityAdded && !$eventScheduled) - { - $changesMade = false; - } - else - { - $changesMade = true; - } - - if (!eval(Hooks::get('CANDIDATE_ON_ADD_ACTIVITY_CHANGE_STATUS_POST'))) return; - - $this->_template->assign('candidateID', $candidateID); - $this->_template->assign('regardingID', $regardingID); - $this->_template->assign('oldStatusDescription', $oldStatusDescription); - $this->_template->assign('newStatusDescription', $newStatusDescription); - $this->_template->assign('statusChanged', $statusChanged); - $this->_template->assign('activityAdded', $activityAdded); - $this->_template->assign('activityDescription', $activityNote); - $this->_template->assign('activityType', $activityTypeDescription); - $this->_template->assign('eventScheduled', $eventScheduled); - $this->_template->assign('eventHTML', $eventHTML); - $this->_template->assign('notificationHTML', $notificationHTML); - $this->_template->assign('onlyScheduleEvent', $onlyScheduleEvent); - $this->_template->assign('changesMade', $changesMade); - $this->_template->assign('isFinishedMode', true); - $this->_template->assign('isJobOrdersMode', $isJobOrdersMode); - $this->_template->display( - './modules/candidates/AddActivityChangeStatusModal.tpl' - ); - } - - /* - * Sends mass emails from the datagrid - */ - private function onEmailCandidates() - { - if (isset($_POST['postback'])) - { - $emailTo = $_POST['emailTo']; - $emailSubject = $_POST['emailSubject']; - $emailBody = $_POST['emailBody']; - - $tmpDestination = explode(', ', $emailTo); - $destination = array(); - foreach($tmpDestination as $emailDest) - { - $destination[] = array($emailDest, $emailDest); - } - - $mailer = new Mailer(CATS_ADMIN_SITE); - - if($_POST['emailTemplate'] == "-1") - { - $mailerStatus = $mailer->send( - array($_SESSION['CATS']->getEmail(), $_SESSION['CATS']->getEmail()), - $destination, - $emailSubject, - $emailBody, - true, - true - ); - } - else - { - $emailTemplates = new EmailTemplates($this->_siteID); - $candidates = new Candidates($this->_siteID); - - $emailsToIDs = $_POST['candidateID']; - $candidateIDs = array(); - foreach($emailsToIDs as $email) - { - $temp = explode('=', $email); - $candidateIDs[$temp[0]] = $temp[1]; - } - foreach($candidateIDs as $email => $ID) - { - $candidateData = $candidates->get($ID); - $emailTextSubstituted = $emailTemplates->replaceVariables($emailBody); - $stringsToFind = array( - '%CANDOWNER%', - '%CANDFIRSTNAME%', - '%CANDFULLNAME%' - ); - $replacementStrings = array( - $candidateData['ownerFullName'], - $candidateData['firstName'], - $candidateData['candidateFullName'] - ); - $emailTextSubstituted = str_replace( - $stringsToFind, - $replacementStrings, - $emailTextSubstituted - ); - - $mailerStatus = $mailer->sendToOne( - array($email, $candidateData['candidateFullName']), - $emailSubject, - $emailTextSubstituted, - true - ); - } - } - - $this->_template->assign('active', $this); - $this->_template->assign('success', true); - $this->_template->assign('success_to', $emailTo); - $this->_template->display('./modules/candidates/SendEmail.tpl'); - } - else - { - $dataGrid = DataGrid::getFromRequest(); - - $candidateIDs = $dataGrid->getExportIDs(); - - /* Validate each ID */ - foreach ($candidateIDs as $index => $candidateID) - { - if (!$this->isRequiredIDValid($index, $candidateIDs)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); - return; - } - } - - $db_str = implode(", ", $candidateIDs); - - $db = DatabaseConnection::getInstance(); - - $rs = $db->getAllAssoc(sprintf( - 'SELECT candidate_id, first_name, last_name, email1, email2 ' - . 'FROM candidate ' - . 'WHERE candidate_id IN (%s)', - $db_str - )); - - $emailTemplates = new EmailTemplates($this->_siteID); - $emailTemplatesRS = $emailTemplates->getAllCustom(); - - //$this->_template->assign('privledgedUser', $privledgedUser); - $this->_template->assign('active', $this); - $this->_template->assign('success', false); - $this->_template->assign('emailTemplatesRS', $emailTemplatesRS); - $this->_template->assign('recipients', $rs); - $this->_template->assign('sessionCookie', $_SESSION['CATS']->getCookie()); - $this->_template->display('./modules/candidates/SendEmail.tpl'); - } - } - - private function onShowQuestionnaire() - { - $candidateID = isset($_GET[$id='candidateID']) ? $_GET[$id] : false; - $title = isset($_GET[$id='questionnaireTitle']) ? urldecode($_GET[$id]) : false; - $printOption = isset($_GET[$id='print']) ? $_GET[$id] : ''; - $printValue = !strcasecmp($printOption, 'yes') ? true : false; - - if (!$candidateID || !$title) - { - CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Bad Server Information.'); - } - - $candidates = new Candidates($this->_siteID); - $cData = $candidates->get($candidateID); - - $questionnaire = new Questionnaire($this->_siteID); - $qData = $questionnaire->getCandidateQuestionnaire($candidateID, $title); - - $attachment = new Attachments($this->_siteID); - $attachments = $attachment->getAll(DATA_ITEM_CANDIDATE, $candidateID); - if (!empty($attachments)) - { - $resume = $candidates->getResume($attachments[0]['attachmentID']); - $this->_template->assign('resumeText', str_replace("\n", "
\n", htmlentities(DatabaseSearch::fulltextDecode($resume['text'])))); - $this->_template->assign('resumeTitle', htmlentities($resume['title'])); - } - - $this->_template->assign('active', $this); - $this->_template->assign('candidateID', $candidateID); - $this->_template->assign('title', $title); - $this->_template->assign('cData', $cData); - $this->_template->assign('qData', $qData); - $this->_template->assign('print', $printValue); - - $this->_template->display('./modules/candidates/Questionnaire.tpl'); - } - - private function findDuplicateCandidateSearch() - { - $duplicateCandidateID = $_GET['candidateID']; - if($duplicateCandidateID == "") - { - $duplicateCandidateID = $_POST['candidateID']; - } - $query = $this->getSanitisedInput('wildCardString', $_POST); - $mode = $this->getSanitisedInput('mode', $_POST); - - /* Execute the search. */ - $search = new SearchCandidates($this->_siteID); - switch ($mode) - { - case 'searchByCandidateName': - $rs = $search->byFullName($query, 'candidate.last_name', 'ASC', true); - $resultsMode = true; - break; - - default: - $rs = $search->all($query, 'candidate.last_name', 'ASC', 'true'); - $resultsMode = false; - break; - } - - $candidates = new Candidates($this->_siteID); - - foreach ($rs as $rowIndex => $row) - { - $rs[$rowIndex]['duplicateCandidateID'] = $duplicateCandidateID; - if ($candidates->checkIfLinked($rs[$rowIndex]['candidateID'], $duplicateCandidateID)) - { - $rs[$rowIndex]['linked'] = true; - } - else - { - $rs[$rowIndex]['linked'] = false; - } - - if ($row['isHot'] == 1) - { - $rs[$rowIndex]['linkClass'] = 'jobLinkHot'; - } - else - { - $rs[$rowIndex]['linkClass'] = 'jobLinkCold'; - } - } - - if (!eval(Hooks::get('DUPLICATE_ON_LINK_DUPLICATES'))) return; - - $this->_template->assign('rs', $rs); - $this->_template->assign('isFinishedMode', false); - $this->_template->assign('isResultsMode', $resultsMode); - $this->_template->assign('duplicateCandidateID', $duplicateCandidateID); - $this->_template->display('./modules/candidates/LinkDuplicity.tpl'); - } - - private function mergeDuplicates() - { - $candidates = new Candidates($this->_siteID); - $oldCandidateID = $_GET['oldCandidateID']; - $newCandidateID = $_GET['newCandidateID']; - - $rsOld = $candidates->getWithDuplicity($oldCandidateID); - $rsNew = $candidates->getWithDuplicity($newCandidateID); - - $this->_template->assign('isFinishedMode', false); - $this->_template->assign('rsOld', $rsOld); - $this->_template->assign('rsNew', $rsNew); - $this->_template->assign('oldCandidateID', $oldCandidateID); - $this->_template->assign('newCandidateID', $newCandidateID); - $this->_template->display('./modules/candidates/Merge.tpl'); - } - - private function mergeDuplicatesInfo() - { - $candidates = new Candidates($this->_siteID); - $params = array(); - $params['firstName'] = $_POST['firstName']; - $params['middleName'] = $_POST['middleName']; - $params['lastName'] = $_POST['lastName']; - if(isset($_POST['email'])) - { - $params['emails'] = $_POST['email']; - } - else - { - $params['emails'] = array(); - } - $params['phoneCell'] = $_POST['phoneCell']; - $params['phoneWork'] = $_POST['phoneWork']; - $params['phoneHome'] = $_POST['phoneHome']; - $params['address'] = $_POST['address']; - $params['website'] = $_POST['website']; - $params['oldCandidateID'] = $_POST['oldCandidateID']; - $params['newCandidateID'] = $_POST['newCandidateID']; - - $candidates->mergeDuplicates($params, $candidates->getWithDuplicity($params['newCandidateID'])); - $this->_template->assign('isFinishedMode', true); - $this->_template->display('./modules/candidates/Merge.tpl'); - } - - private function removeDuplicity() - { - $candidates = new Candidates($this->_siteID); - $oldCandidateID = $_GET['oldCandidateID']; - $newCandidateID = $_GET['newCandidateID']; - $candidates->removeDuplicity($oldCandidateID, $newCandidateID); - $url = CATSUtility::getIndexName()."?m=candidates"; - header("Location: " . $url); /* Redirect browser */ - exit(); - } - - - private function addDuplicates() - { - $candidates = new Candidates($this->_siteID); - $oldCandidateID = $_GET['candidateID']; - $newCandidateID = $_GET['duplicateCandidateID']; - $candidates->addDuplicates($newCandidateID, $oldCandidateID); - $this->_template->assign('isFinishedMode', true); - $this->_template->display('./modules/candidates/LinkDuplicity.tpl'); - } -} - -?> +_authenticationRequired = true; + $this->_moduleDirectory = 'candidates'; + $this->_moduleName = 'candidates'; + $this->_moduleTabText = 'Candidates'; + $this->_subTabs = array( + 'Add Candidate' => CATSUtility::getIndexName() . '?m=candidates&a=add*al=' . ACCESS_LEVEL_EDIT . '@candidates.add', + 'Search Candidates' => CATSUtility::getIndexName() . '?m=candidates&a=search' + ); + } + + + public function handleRequest() + { + if (!eval(Hooks::get('CANDIDATES_HANDLE_REQUEST'))) return; + + $action = $this->getAction(); + switch ($action) + { + case 'show': + if ($this->getUserAccessLevel('candidates.show') < ACCESS_LEVEL_READ) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->show(); + break; + + case 'add': + if ($this->getUserAccessLevel('candidates.add') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + if ($this->isPostBack()) + { + $this->onAdd(); + } + else + { + $this->add(); + } + + break; + + case 'edit': + if ($this->getUserAccessLevel('candidates.edit') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + if ($this->isPostBack()) + { + $this->onEdit(); + } + else + { + $this->edit(); + } + + break; + + case 'delete': + if ($this->getUserAccessLevel('candidates.delete') < ACCESS_LEVEL_DELETE) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->onDelete(); + break; + + case 'search': + if ($this->getUserAccessLevel('candidates.search') < ACCESS_LEVEL_READ) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + include_once(LEGACY_ROOT . '/lib/Search.php'); + + if ($this->isGetBack()) + { + $this->onSearch(); + } + else + { + $this->search(); + } + + break; + + case 'viewResume': + if ($this->getUserAccessLevel('candidates.viewResume') < ACCESS_LEVEL_READ) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + include_once(LEGACY_ROOT . '/lib/Search.php'); + + $this->viewResume(); + break; + + /* + * Search for a job order (in the modal window) for which to + * consider a candidate. + */ + case 'considerForJobSearch': + if ($this->getUserAccessLevel('candidates.search') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + include_once(LEGACY_ROOT . '/lib/Search.php'); + + $this->considerForJobSearch(); + + break; + + /* + * Add candidate to pipeline after selecting a job order for which + * to consider a candidate (in the modal window). + */ + case 'addToPipeline': + if ($this->getUserAccessLevel('pipelines.addToPipeline') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->onAddToPipeline(); + break; + + case 'addCandidateTags': + if ($this->getUserAccessLevel('candidates.addCandidateTags') < ACCESS_LEVEL_EDIT ) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + if ($this->isPostBack()) + { + $this->onAddCandidateTags(); + } + else + { + $this->addCandidateTags(); + } + break; + + /* Change candidate-joborder status. */ + case 'addActivityChangeStatus': + if ($this->getUserAccessLevel('pipelines.addActivityChangeStatus') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + if ($this->isPostBack()) + { + $this->onAddActivityChangeStatus(); + } + else + { + $this->addActivityChangeStatus(); + } + + break; + + /* Remove a candidate from a pipeline. */ + case 'removeFromPipeline': + if ($this->getUserAccessLevel('pipelines.removeFromPipeline') < ACCESS_LEVEL_DELETE) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->onRemoveFromPipeline(); + break; + + case 'addEditImage': + if ($this->getUserAccessLevel('candidates.addEditImage') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatalModal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + if ($this->isPostBack()) + { + $this->onAddEditImage(); + } + else + { + $this->addEditImage(); + } + + break; + + /* Add an attachment to the candidate. */ + case 'createAttachment': + if ($this->getUserAccessLevel('candidates.createAttachment') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + + include_once(LEGACY_ROOT . '/lib/DocumentToText.php'); + + if ($this->isPostBack()) + { + $this->onCreateAttachment(); + } + else + { + $this->createAttachment(); + } + + break; + + /* Administrators can hide a candidate from a site with this action. */ + case 'administrativeHideShow': + if ($this->getUserAccessLevel('candidates.hidden') < ACCESS_LEVEL_MULTI_SA) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->administrativeHideShow(); + break; + + /* Delete a candidate attachment */ + case 'deleteAttachment': + if ($this->getUserAccessLevel('candidates.deleteAttachment') < ACCESS_LEVEL_DELETE) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->onDeleteAttachment(); + break; + + /* Hot List Page */ + /* FIXME: function savedList() missing + case 'savedLists': + if ($this->getUserAccessLevel('candidates.savedLists') < ACCESS_LEVEL_READ) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->savedList(); + break; + */ + + case 'emailCandidates': + if ($this->getUserAccessLevel('candidates.emailCandidates') < ACCESS_LEVEL_READ) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + if ($this->getUserAccessLevel('candidates.emailCandidates') < ACCESS_LEVEL_SA) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Sorry, but you are not allowed to send e-mails.'); + } + $this->onEmailCandidates(); + break; + + case 'show_questionnaire': + if ($this->getUserAccessLevel('candidates.show_questionnaire') < ACCESS_LEVEL_READ) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->onShowQuestionnaire(); + break; + + case 'linkDuplicate': + if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->findDuplicateCandidateSearch(); + break; + + /* Merge two duplicate candidates into the older one */ + case 'merge': + if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->mergeDuplicates(); + break; + + case 'mergeInfo': + if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->mergeDuplicatesInfo(); + break; + + /* Remove duplicity warning from a new candidate */ + case 'removeDuplicity': + if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->removeDuplicity(); + break; + + case 'addDuplicates': + if ($this->getUserAccessLevel('candidates.duplicates') < ACCESS_LEVEL_SA) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->addDuplicates(); + break; + + /* Main candidates page. */ + case 'listByView': + default: + if ($this->getUserAccessLevel('candidates.list') < ACCESS_LEVEL_READ) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + $this->listByView(); + break; + } + } + + + + + /* + * Called by external modules for adding candidates. + */ + public function publicAddCandidate($isModal, $transferURI, $moduleDirectory) + { + if ($this->getUserAccessLevel('candidates.add') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + + $candidateID = $this->_addCandidate($isModal, $moduleDirectory); + + if ($candidateID <= 0) + { + CommonErrors::fatalModal(COMMONERROR_RECORDERROR, $this, 'Failed to add candidate.'); + } + + $transferURI = str_replace( + '__CANDIDATE_ID__', $candidateID, $transferURI + ); + CATSUtility::transferRelativeURI($transferURI); + } + + + /* + * Called by external modules for processing the log activity / change + * status dialog. + */ + public function publicAddActivityChangeStatus($isJobOrdersMode, $regardingID, $moduleDirectory) + { + if ($this->getUserAccessLevel('pipelines.addActivityChangeStatus') < ACCESS_LEVEL_EDIT) + { + CommonErrors::fatal(COMMONERROR_PERMISSION, $this, 'Invalid user level for action.'); + } + + $this->_AddActivityChangeStatus( + $isJobOrdersMode, $regardingID, $moduleDirectory + ); + } + + /* + * Called by handleRequest() to process loading the list / main page. + */ + private function listByView($errMessage = '') + { + // Log message that shows up on the top of the list page + $topLog = ''; + + $dataGridProperties = DataGrid::getRecentParamaters("candidates:candidatesListByViewDataGrid"); + + /* If this is the first time we visited the datagrid this session, the recent paramaters will + * be empty. Fill in some default values. */ + if ($dataGridProperties == array()) + { + $dataGridProperties = array('rangeStart' => 0, + 'maxResults' => 15, + 'filterVisible' => false); + } + + //$newParameterArray = $this->_parameters; + $tags = new Tags($this->_siteID); + $tagsRS = $tags->getAll(); + //foreach($tagsRS as $r) $r['link'] = DataGrid::_makeControlLink($newParameterArray); + + $dataGrid = DataGrid::get("candidates:candidatesListByViewDataGrid", $dataGridProperties); + + $candidates = new Candidates($this->_siteID); + $this->_template->assign('totalCandidates', $candidates->getCount()); + + $this->_template->assign('active', $this); + $this->_template->assign('dataGrid', $dataGrid); + $this->_template->assign('userID', $_SESSION['CATS']->getUserID()); + $this->_template->assign('errMessage', $errMessage); + $this->_template->assign('topLog', $topLog); + $this->_template->assign('tagsRS', $tagsRS); + + if (!eval(Hooks::get('CANDIDATE_LIST_BY_VIEW'))) return; + + $this->_template->display('./modules/candidates/Candidates.tpl'); + } + + /* + * Called by handleRequest() to process loading the details page. + */ + private function show() + { + /* Is this a popup? */ + if (isset($_GET['display']) && $_GET['display'] == 'popup') + { + $isPopup = true; + } + else + { + $isPopup = false; + } + + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET) && !isset($_GET['email'])) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidates = new Candidates($this->_siteID); + + if (isset($_GET['candidateID'])) + { + $candidateID = $_GET['candidateID']; + } + else + { + $candidateID = $candidates->getIDByEmail($_GET['email']); + } + + $data = $candidates->getWithDuplicity($candidateID); + + /* Bail out if we got an empty result set. */ + if (empty($data)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'The specified candidate ID could not be found.'); + return; + } + + if ($data['isAdminHidden'] == 1 && $this->getUserAccessLevel('candidates.hidden') < ACCESS_LEVEL_MULTI_SA) + { + $this->listByView('This candidate is hidden - only a CATS Administrator can unlock the candidate.'); + return; + } + + /* We want to handle formatting the city and state here instead + * of in the template. + */ + $data['cityAndState'] = StringUtility::makeCityStateString( + $data['city'], $data['state'] + ); + + /* + * Replace newlines with
, fix HTML "special" characters, and + * strip leading empty lines and spaces. + */ + $data['notes'] = trim( + nl2br(htmlspecialchars($data['notes'], ENT_QUOTES)) + ); + + /* Chop $data['notes'] to make $data['shortNotes']. */ + if (strlen($data['notes']) > self::NOTES_MAXLEN) + { + $data['shortNotes'] = substr( + $data['notes'], 0, self::NOTES_MAXLEN + ); + $isShortNotes = true; + } + else + { + $data['shortNotes'] = $data['notes']; + $isShortNotes = false; + } + + /* Format "can relocate" status. */ + if ($data['canRelocate'] == 1) + { + $data['canRelocate'] = 'Yes'; + } + else + { + $data['canRelocate'] = 'No'; + } + + if ($data['isHot'] == 1) + { + $data['titleClass'] = 'jobTitleHot'; + } + else + { + $data['titleClass'] = 'jobTitleCold'; + } + + $attachments = new Attachments($this->_siteID); + $attachmentsRS = $attachments->getAll( + DATA_ITEM_CANDIDATE, $candidateID + ); + + foreach ($attachmentsRS as $rowNumber => $attachmentsData) + { + /* If profile image is not local, force it to be local. */ + if ($attachmentsData['isProfileImage'] == 1) + { + $attachments->forceAttachmentLocal($attachmentsData['attachmentID']); + } + + /* Show an attachment icon based on the document's file type. */ + $attachmentIcon = strtolower( + FileUtility::getAttachmentIcon( + $attachmentsRS[$rowNumber]['originalFilename'] + ) + ); + + $attachmentsRS[$rowNumber]['attachmentIcon'] = $attachmentIcon; + + /* If the text field has any text, show a preview icon. */ + if ($attachmentsRS[$rowNumber]['hasText']) + { + $attachmentsRS[$rowNumber]['previewLink'] = sprintf( + '(Preview)', + CATSUtility::getIndexName(), + $attachmentsRS[$rowNumber]['attachmentID'] + ); + } + else + { + $attachmentsRS[$rowNumber]['previewLink'] = ' '; + } + } + $pipelines = new Pipelines($this->_siteID); + $pipelinesRS = $pipelines->getCandidatePipeline($candidateID); + + $sessionCookie = $_SESSION['CATS']->getCookie(); + + /* Format pipeline data. */ + foreach ($pipelinesRS as $rowIndex => $row) + { + /* Hot jobs [can] have different title styles than normal + * jobs. + */ + if ($row['isHot'] == 1) + { + $pipelinesRS[$rowIndex]['linkClass'] = 'jobLinkHot'; + } + else + { + $pipelinesRS[$rowIndex]['linkClass'] = 'jobLinkCold'; + } + + $pipelinesRS[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( + $pipelinesRS[$rowIndex]['ownerFirstName'], + $pipelinesRS[$rowIndex]['ownerLastName'], + false, + LAST_NAME_MAXLEN + ); + + $pipelinesRS[$rowIndex]['addedByAbbrName'] = StringUtility::makeInitialName( + $pipelinesRS[$rowIndex]['addedByFirstName'], + $pipelinesRS[$rowIndex]['addedByLastName'], + false, + LAST_NAME_MAXLEN + ); + + $pipelinesRS[$rowIndex]['ratingLine'] = TemplateUtility::getRatingObject( + $pipelinesRS[$rowIndex]['ratingValue'], + $pipelinesRS[$rowIndex]['candidateJobOrderID'], + $sessionCookie + ); + } + + $activityEntries = new ActivityEntries($this->_siteID); + $activityRS = $activityEntries->getAllByDataItem($candidateID, DATA_ITEM_CANDIDATE); + if (!empty($activityRS)) + { + foreach ($activityRS as $rowIndex => $row) + { + if (empty($activityRS[$rowIndex]['notes'])) + { + $activityRS[$rowIndex]['notes'] = '(No Notes)'; + } + + if (empty($activityRS[$rowIndex]['jobOrderID']) || + empty($activityRS[$rowIndex]['regarding'])) + { + $activityRS[$rowIndex]['regarding'] = 'General'; + } + + $activityRS[$rowIndex]['enteredByAbbrName'] = StringUtility::makeInitialName( + $activityRS[$rowIndex]['enteredByFirstName'], + $activityRS[$rowIndex]['enteredByLastName'], + false, + LAST_NAME_MAXLEN + ); + } + } + + /* Get upcoming calendar entries. */ + $calendarRS = $candidates->getUpcomingEvents($candidateID); + if (!empty($calendarRS)) + { + foreach ($calendarRS as $rowIndex => $row) + { + $calendarRS[$rowIndex]['enteredByAbbrName'] = StringUtility::makeInitialName( + $calendarRS[$rowIndex]['enteredByFirstName'], + $calendarRS[$rowIndex]['enteredByLastName'], + false, + LAST_NAME_MAXLEN + ); + } + } + + /* Get extra fields. */ + $extraFieldRS = $candidates->extraFields->getValuesForShow($candidateID); + + /* Add an MRU entry. */ + $_SESSION['CATS']->getMRU()->addEntry( + DATA_ITEM_CANDIDATE, $candidateID, $data['firstName'] . ' ' . $data['lastName'] + ); + + /* Is the user an admin - can user see history? */ + if ($this->getUserAccessLevel('candidates.priviledgedUser') < ACCESS_LEVEL_DEMO) + { + $privledgedUser = false; + } + else + { + $privledgedUser = true; + } + + $EEOSettings = new EEOSettings($this->_siteID); + $EEOSettingsRS = $EEOSettings->getAll(); + $EEOValues = array(); + + /* Make a list of all EEO related values so they can be positioned by index + * rather than static positioning (like extra fields). */ + if ($EEOSettingsRS['enabled'] == 1) + { + if ($EEOSettingsRS['genderTracking'] == 1) + { + $EEOValues[] = array('fieldName' => 'Gender', 'fieldValue' => $data['eeoGenderText']); + } + if ($EEOSettingsRS['ethnicTracking'] == 1) + { + $EEOValues[] = array('fieldName' => 'Ethnicity', 'fieldValue' => $data['eeoEthnicType']); + } + if ($EEOSettingsRS['veteranTracking'] == 1) + { + $EEOValues[] = array('fieldName' => 'Veteran Status', 'fieldValue' => $data['eeoVeteranType']); + } + if ($EEOSettingsRS['disabilityTracking'] == 1) + { + $EEOValues[] = array('fieldName' => 'Disability Status', 'fieldValue' => $data['eeoDisabilityStatus']); + } + } + + $tags = new Tags($this->_siteID); + + $questionnaire = new Questionnaire($this->_siteID); + $questionnaires = $questionnaire->getCandidateQuestionnaires($candidateID); + + $lists = $candidates->getListsForCandidate($candidateID); + + $this->_template->assign('active', $this); + $this->_template->assign('questionnaires', $questionnaires); + $this->_template->assign('data', $data); + $this->_template->assign('isShortNotes', $isShortNotes); + $this->_template->assign('attachmentsRS', $attachmentsRS); + $this->_template->assign('pipelinesRS', $pipelinesRS); + $this->_template->assign('activityRS', $activityRS); + $this->_template->assign('calendarRS', $calendarRS); + $this->_template->assign('extraFieldRS', $extraFieldRS); + $this->_template->assign('candidateID', $candidateID); + $this->_template->assign('isPopup', $isPopup); + $this->_template->assign('EEOSettingsRS', $EEOSettingsRS); + $this->_template->assign('EEOValues', $EEOValues); + $this->_template->assign('privledgedUser', $privledgedUser); + $this->_template->assign('sessionCookie', $_SESSION['CATS']->getCookie()); + $this->_template->assign('tagsRS', $tags->getAll()); + $this->_template->assign('assignedTags', $tags->getCandidateTagsTitle($candidateID)); + $this->_template->assign('lists', $lists); + + $this->_template->display('./modules/candidates/Show.tpl'); + + if (!eval(Hooks::get('CANDIDATE_SHOW'))) return; + + } + + /* + * Called by handleRequest() to process loading the add page. + * + * The user could have already added a resume to the system + * before this page is displayed. They could have indicated + * that they want to use a bulk resume, or a text resume + * stored in the session. These ocourances are looked + * for here, and the Add.tpl file displays the results. + */ + private function add($contents = '', $fields = array()) + { + $candidates = new Candidates($this->_siteID); + + /* Get possible sources. */ + $sourcesRS = $candidates->getPossibleSources(); + $sourcesString = ListEditor::getStringFromList($sourcesRS, 'name'); + + /* Get extra fields. */ + $extraFieldRS = $candidates->extraFields->getValuesForAdd(); + + /* Get passed variables. */ + $preassignedFields = $_GET; + if (count($fields) > 0) + { + $preassignedFields = array_merge($preassignedFields, $fields); + } + + /* Get preattached resume, if any. */ + if ($this->isRequiredIDValid('attachmentID', $_GET)) + { + $associatedAttachment = $_GET['attachmentID']; + + $attachments = new Attachments($this->_siteID); + $associatedAttachmentRS = $attachments->get($associatedAttachment); + + /* Show an attachment icon based on the document's file type. */ + $attachmentIcon = strtolower( + FileUtility::getAttachmentIcon( + $associatedAttachmentRS['originalFilename'] + ) + ); + + $associatedAttachmentRS['attachmentIcon'] = $attachmentIcon; + + /* If the text field has any text, show a preview icon. */ + if ($associatedAttachmentRS['hasText']) + { + $associatedAttachmentRS['previewLink'] = sprintf( + '(Preview)', + CATSUtility::getIndexName(), + $associatedAttachmentRS['attachmentID'] + ); + } + else + { + $associatedAttachmentRS['previewLink'] = ' '; + } + } + else + { + $associatedAttachment = 0; + $associatedAttachmentRS = array(); + } + + /* Get preuploaded resume text, if any */ + if ($this->isRequiredIDValid('resumeTextID', $_GET, true)) + { + $associatedTextResume = $_SESSION['CATS']->retrieveData($_GET['resumeTextID']); + } + else + { + $associatedTextResume = false; + } + + /* Get preuploaded resume file (unattached), if any */ + if ($this->isRequiredIDValid('resumeFileID', $_GET, true)) + { + $associatedFileResume = $_SESSION['CATS']->retrieveData($_GET['resumeFileID']); + $associatedFileResume['id'] = $_GET['resumeFileID']; + $associatedFileResume['attachmentIcon'] = strtolower( + FileUtility::getAttachmentIcon( + $associatedFileResume['filename'] + ) + ); + } + else + { + $associatedFileResume = false; + } + + $EEOSettings = new EEOSettings($this->_siteID); + $EEOSettingsRS = $EEOSettings->getAll(); + + + if (!eval(Hooks::get('CANDIDATE_ADD'))) return; + + /* If parsing is not enabled server-wide, say so. */ + if (!LicenseUtility::isParsingEnabled()) + { + $isParsingEnabled = false; + } + /* For CATS Toolbar, if e-mail has been sent and it wasn't set by + * parser, it's toolbar and it needs the old format. + */ + else if (!isset($preassignedFields['email'])) + { + $isParsingEnabled = true; + } + else if (empty($preassignedFields['email'])) + { + $isParsingEnabled = true; + } + else if (isset($preassignedFields['isFromParser']) && $preassignedFields['isFromParser']) + { + $isParsingEnabled = true; + } + else + { + $isParsingEnabled = false; + } + + if (is_array($parsingStatus = LicenseUtility::getParsingStatus()) && + isset($parsingStatus['parseLimit'])) + { + $parsingStatus['parseLimit'] = $parsingStatus['parseLimit'] - 1; + } + + $this->_template->assign('parsingStatus', $parsingStatus); + $this->_template->assign('isParsingEnabled', $isParsingEnabled); + $this->_template->assign('contents', $contents); + $this->_template->assign('extraFieldRS', $extraFieldRS); + $this->_template->assign('active', $this); + $this->_template->assign('subActive', 'Add Candidate'); + $this->_template->assign('sourcesRS', $sourcesRS); + $this->_template->assign('sourcesString', $sourcesString); + $this->_template->assign('preassignedFields', $preassignedFields); + $this->_template->assign('associatedAttachment', $associatedAttachment); + $this->_template->assign('associatedAttachmentRS', $associatedAttachmentRS); + $this->_template->assign('associatedTextResume', $associatedTextResume); + $this->_template->assign('associatedFileResume', $associatedFileResume); + $this->_template->assign('EEOSettingsRS', $EEOSettingsRS); + $this->_template->assign('isModal', false); + + /* REMEMBER TO ALSO UPDATE JobOrdersUI::addCandidateModal() IF + * APPLICABLE. + */ + $this->_template->display('./modules/candidates/Add.tpl'); + } + + public function checkParsingFunctions() + { + if (LicenseUtility::isParsingEnabled()) + { + if (isset($_POST['documentText'])) $contents = $_POST['documentText']; + else $contents = ''; + + // Retain all field data since this isn't done over AJAX (yet) + $fields = array( + 'firstName' => $this->getSanitisedInput('firstName', $_POST), + 'middleName' => $this->getSanitisedInput('middleName', $_POST), + 'lastName' => $this->getSanitisedInput('lastName', $_POST), + 'email1' => $this->getSanitisedInput('email1', $_POST), + 'email2' => $this->getSanitisedInput('email2', $_POST), + 'phoneHome' => $this->getSanitisedInput('phoneHome', $_POST), + 'phoneCell' => $this->getSanitisedInput('phoneCell', $_POST), + 'phoneWork' => $this->getSanitisedInput('phoneWork', $_POST), + 'address' => $this->getSanitisedInput('address', $_POST), + 'city' => $this->getSanitisedInput('city', $_POST), + 'state' => $this->getSanitisedInput('state', $_POST), + 'zip' => $this->getSanitisedInput('zip', $_POST), + 'source' => $this->getTrimmedInput('source', $_POST), + 'keySkills' => $this->getSanitisedInput('keySkills', $_POST), + 'currentEmployer' => $this->getSanitisedInput('currentEmployer', $_POST), + 'currentPay' => $this->getSanitisedInput('currentPay', $_POST), + 'desiredPay' => $this->getSanitisedInput('desiredPay', $_POST), + 'notes' => $this->getSanitisedInput('notes', $_POST), + 'canRelocate' => $this->getSanitisedInput('canRelocate', $_POST), + 'webSite' => $this->getSanitisedInput('webSite', $_POST), + 'bestTimeToCall' => $this->getSanitisedInput('bestTimeToCall', $_POST), + 'gender' => $this->getTrimmedInput('gender', $_POST), + 'race' => $this->getTrimmedInput('race', $_POST), + 'veteran' => $this->getTrimmedInput('veteran', $_POST), + 'disability' => $this->getTrimmedInput('disability', $_POST), + 'documentTempFile'=> $this->getTrimmedInput('documentTempFile', $_POST), + 'isFromParser' => true + ); + + /** + * User is loading a resume from a document. Convert it to a string and paste the contents + * into the textarea field on the add candidate page after validating the form. + */ + if (isset($_POST['loadDocument']) && $_POST['loadDocument'] == 'true') + { + // Get the upload file from the post data + $newFileName = FileUtility::getUploadFileFromPost( + $this->_siteID, // The site ID + 'addcandidate', // Sub-directory of the site's upload folder + 'documentFile' // The DOM "name" from the element + ); + + if ($newFileName !== false) + { + // Get the relative path to the file (to perform operations on) + $newFilePath = FileUtility::getUploadFilePath( + $this->_siteID, // The site ID + 'addcandidate', // The sub-directory + $newFileName + ); + + $documentToText = new DocumentToText(); + $doctype = $documentToText->getDocumentType($newFilePath); + + if ($documentToText->convert($newFilePath, $doctype)) + { + $contents = $documentToText->getString(); + if ($doctype == DOCUMENT_TYPE_DOC) + { + $contents = str_replace('|', "\n", $contents); + } + + // Remove things like _rDOTr for ., etc. + $contents = DatabaseSearch::fulltextDecode($contents); + } + else + { + $contents = @file_get_contents($newFilePath); + $fields['binaryData'] = true; + } + + // Save the short (un-pathed) name + $fields['documentTempFile'] = $newFileName; + + if (isset($_COOKIE['CATS_SP_TEMP_FILE']) && ($oldFile = $_COOKIE['CATS_SP_TEMP_FILE']) != '' && + strcasecmp($oldFile, $newFileName)) + { + // Get the safe, old file they uploaded and didn't use (if exists) and delete + $oldFilePath = FileUtility::getUploadFilePath($this->_siteID, 'addcandidate', $oldFile); + + if ($oldFilePath !== false) + { + @unlink($oldFilePath); + } + } + + // Prevent users from creating more than 1 temp file for single parsing (sp) + setcookie('CATS_SP_TEMP_FILE', $newFileName, time() + (60*60*24*7)); + } + + if (isset($_POST['parseDocument']) && $_POST['parseDocument'] == 'true' && $contents != '') + { + // ... + } + else + { + return array($contents, $fields); + } + } + + /** + * User is parsing the contents of the textarea field on the add candidate page. + */ + if (isset($_POST['parseDocument']) && $_POST['parseDocument'] == 'true' && $contents != '') + { + $pu = new ParseUtility(); + if ($res = $pu->documentParse('untitled', strlen($contents), '', $contents)) + { + if (isset($res['first_name'])) $fields['firstName'] = $res['first_name']; else $fields['firstName'] = ''; + if (isset($res['last_name'])) $fields['lastName'] = $res['last_name']; else $fields['lastName'] = ''; + $fields['middleName'] = ''; + if (isset($res['email_address'])) $fields['email1'] = $res['email_address']; else $fields['email1'] = ''; + $fields['email2'] = ''; + if (isset($res['us_address'])) $fields['address'] = $res['us_address']; else $fields['address'] = ''; + if (isset($res['city'])) $fields['city'] = $res['city']; else $fields['city'] = ''; + if (isset($res['state'])) $fields['state'] = $res['state']; else $fields['state'] = ''; + if (isset($res['zip_code'])) $fields['zip'] = $res['zip_code']; else $fields['zip'] = ''; + if (isset($res['phone_number'])) $fields['phoneHome'] = $res['phone_number']; else $fields['phoneHome'] = ''; + $fields['phoneWork'] = $fields['phoneCell'] = ''; + if (isset($res['skills'])) $fields['keySkills'] = str_replace("\n", ' ', str_replace('"', '\'\'', $res['skills'])); + } + + return array($contents, $fields); + } + } + + return false; + } + + /* + * Called by handleRequest() to process saving / submitting the add page. + */ + private function onAdd() + { + if (is_array($mp = $this->checkParsingFunctions())) + { + return $this->add($mp[0], $mp[1]); + } + + $candidateID = $this->_addCandidate(false); + + if ($candidateID <= 0) + { + CommonErrors::fatal(COMMONERROR_RECORDERROR, $this, 'Failed to add candidate.'); + } + + $activityEntries = new ActivityEntries($this->_siteID); + $activityID = $activityEntries->add( + $candidateID, + DATA_ITEM_CANDIDATE, + 400, + 'Added a new candidate.', + $this->_userID + ); + + CATSUtility::transferRelativeURI( + 'm=candidates&a=show&candidateID=' . $candidateID + ); + } + + /* + * Called by handleRequest() to process loading the edit page. + */ + private function edit() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidateID = $_GET['candidateID']; + + $candidates = new Candidates($this->_siteID); + $data = $candidates->getForEditing($candidateID); + + /* Bail out if we got an empty result set. */ + if (empty($data)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'The specified candidate ID could not be found.'); + } + + if ($data['isAdminHidden'] == 1 && $this->getUserAccessLevel('candidates.hidden') < ACCESS_LEVEL_MULTI_SA) + { + $this->listByView('This candidate is hidden - only a CATS Administrator can unlock the candidate.'); + return; + } + + $users = new Users($this->_siteID); + $usersRS = $users->getSelectList(); + + /* Add an MRU entry. */ + $_SESSION['CATS']->getMRU()->addEntry( + DATA_ITEM_CANDIDATE, $candidateID, $data['firstName'] . ' ' . $data['lastName'] + ); + + /* Get extra fields. */ + $extraFieldRS = $candidates->extraFields->getValuesForEdit($candidateID); + + /* Get possible sources. */ + $sourcesRS = $candidates->getPossibleSources(); + $sourcesString = ListEditor::getStringFromList($sourcesRS, 'name'); + + /* Is current source a possible source? */ + // FIXME: Use array search functions! + $sourceInRS = false; + foreach ($sourcesRS as $sourceData) + { + if ($sourceData['name'] == $data['source']) + { + $sourceInRS = true; + } + } + + // TODO - improve for permission who can send email + if ($this->getUserAccessLevel('candidates.emailCandidates') == ACCESS_LEVEL_DEMO) + { + $canEmail = false; + } + else + { + $canEmail = true; + } + + $emailTemplates = new EmailTemplates($this->_siteID); + $statusChangeTemplateRS = $emailTemplates->getByTag( + 'EMAIL_TEMPLATE_OWNERSHIPASSIGNCANDIDATE' + ); + if ($statusChangeTemplateRS['disabled'] == 1) + { + $emailTemplateDisabled = true; + } + else + { + $emailTemplateDisabled = false; + } + + /* Date format for DateInput()s. */ + if ($_SESSION['CATS']->isDateDMY()) + { + $data['dateAvailableMDY'] = DateUtility::convert( + '-', $data['dateAvailable'], DATE_FORMAT_DDMMYY, DATE_FORMAT_MMDDYY + ); + } + else + { + $data['dateAvailableMDY'] = $data['dateAvailable']; + } + + if (!eval(Hooks::get('CANDIDATE_EDIT'))) return; + + $EEOSettings = new EEOSettings($this->_siteID); + $EEOSettingsRS = $EEOSettings->getAll(); + + $this->_template->assign('active', $this); + $this->_template->assign('data', $data); + $this->_template->assign('usersRS', $usersRS); + $this->_template->assign('extraFieldRS', $extraFieldRS); + $this->_template->assign('sourcesRS', $sourcesRS); + $this->_template->assign('sourcesString', $sourcesString); + $this->_template->assign('sourceInRS', $sourceInRS); + $this->_template->assign('candidateID', $candidateID); + $this->_template->assign('canEmail', $canEmail); + $this->_template->assign('EEOSettingsRS', $EEOSettingsRS); + $this->_template->assign('emailTemplateDisabled', $emailTemplateDisabled); + $this->_template->display('./modules/candidates/Edit.tpl'); + } + + /* + * Called by handleRequest() to process saving / submitting the edit page. + */ + private function onEdit() + { + $candidates = new Candidates($this->_siteID); + + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_POST)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + return; + } + + /* Bail out if we don't have a valid owner user ID. */ + if (!$this->isOptionalIDValid('owner', $_POST)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid owner user ID.'); + } + + /* Bail out if we received an invalid availability date; if not, go + * ahead and convert the date to MySQL format. + */ + $dateAvailable = $this->getTrimmedInput('dateAvailable', $_POST); + if (!empty($dateAvailable)) + { + if (!DateUtility::validate('-', $dateAvailable, DATE_FORMAT_MMDDYY)) + { + CommonErrors::fatal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid availability date.'); + } + + /* Convert start_date to something MySQL can understand. */ + $dateAvailable = DateUtility::convert( + '-', $dateAvailable, DATE_FORMAT_MMDDYY, DATE_FORMAT_YYYYMMDD + ); + } + + $formattedPhoneHome = StringUtility::extractPhoneNumber( + $this->getSanitisedInput('phoneHome', $_POST) + ); + if (!empty($formattedPhoneHome)) + { + $phoneHome = $formattedPhoneHome; + } + else + { + $phoneHome = $this->getSanitisedInput('phoneHome', $_POST); + } + + $formattedPhoneCell = StringUtility::extractPhoneNumber( + $this->getSanitisedInput('phoneCell', $_POST) + ); + if (!empty($formattedPhoneCell)) + { + $phoneCell = $formattedPhoneCell; + } + else + { + $phoneCell = $this->getSanitisedInput('phoneCell', $_POST); + } + + $formattedPhoneWork = StringUtility::extractPhoneNumber( + $this->getSanitisedInput('phoneWork', $_POST) + ); + if (!empty($formattedPhoneWork)) + { + $phoneWork = $formattedPhoneWork; + } + else + { + $phoneWork = $this->getSanitisedInput('phoneWork', $_POST); + } + + $candidateID = $_POST['candidateID']; + $owner = $_POST['owner']; + + /* Can Relocate */ + $canRelocate = $this->isChecked('canRelocate', $_POST); + + $isHot = $this->isChecked('isHot', $_POST); + + /* Change ownership email? */ + if ($this->isChecked('ownershipChange', $_POST) && $owner > 0) + { + $candidateDetails = $candidates->get($candidateID); + + $users = new Users($this->_siteID); + $ownerDetails = $users->get($owner); + + if (!empty($ownerDetails)) + { + $emailAddress = $ownerDetails['email']; + + /* Get the change status email template. */ + $emailTemplates = new EmailTemplates($this->_siteID); + $statusChangeTemplateRS = $emailTemplates->getByTag( + 'EMAIL_TEMPLATE_OWNERSHIPASSIGNCANDIDATE' + ); + + if (empty($statusChangeTemplateRS) || + empty($statusChangeTemplateRS['textReplaced'])) + { + $statusChangeTemplate = ''; + } + else + { + $statusChangeTemplate = $statusChangeTemplateRS['textReplaced']; + } + /* Replace e-mail template variables. */ + $stringsToFind = array( + '%CANDOWNER%', + '%CANDFIRSTNAME%', + '%CANDFULLNAME%', + '%CANDCATSURL%' + ); + $replacementStrings = array( + $ownerDetails['fullName'], + $candidateDetails['firstName'], + $candidateDetails['firstName'] . ' ' . $candidateDetails['lastName'], + ''. + 'http://' . $_SERVER['HTTP_HOST'] . substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?')) . '?m=candidates&a=show&candidateID=' . $candidateID . '' + ); + $statusChangeTemplate = str_replace( + $stringsToFind, + $replacementStrings, + $statusChangeTemplate + ); + + $email = $statusChangeTemplate; + } + else + { + $email = ''; + $emailAddress = ''; + } + } + else + { + $email = ''; + $emailAddress = ''; + } + + $isActive = $this->isChecked('isActive', $_POST); + $firstName = $this->getSanitisedInput('firstName', $_POST); + $middleName = $this->getSanitisedInput('middleName', $_POST); + $lastName = $this->getSanitisedInput('lastName', $_POST); + $email1 = $this->getSanitisedInput('email1', $_POST); + $email2 = $this->getSanitisedInput('email2', $_POST); + $address = $this->getSanitisedInput('address', $_POST); + $city = $this->getSanitisedInput('city', $_POST); + $state = $this->getSanitisedInput('state', $_POST); + $zip = $this->getSanitisedInput('zip', $_POST); + $source = $this->getSanitisedInput('source', $_POST); + $keySkills = $this->getSanitisedInput('keySkills', $_POST); + $currentEmployer = $this->getSanitisedInput('currentEmployer', $_POST); + $currentPay = $this->getSanitisedInput('currentPay', $_POST); + $desiredPay = $this->getSanitisedInput('desiredPay', $_POST); + $notes = $this->getSanitisedInput('notes', $_POST); + $webSite = $this->getSanitisedInput('webSite', $_POST); + $bestTimeToCall = $this->getTrimmedInput('bestTimeToCall', $_POST); + $gender = $this->getTrimmedInput('gender', $_POST); + $race = $this->getTrimmedInput('race', $_POST); + $veteran = $this->getTrimmedInput('veteran', $_POST); + $disability = $this->getTrimmedInput('disability', $_POST); + + /* Candidate source list editor. */ + $sourceCSV = $this->getTrimmedInput('sourceCSV', $_POST); + + /* Bail out if any of the required fields are empty. */ + if (empty($firstName) || empty($lastName)) + { + CommonErrors::fatal(COMMONERROR_MISSINGFIELDS, $this, 'Required fields are missing.'); + } + + if (!eval(Hooks::get('CANDIDATE_ON_EDIT_PRE'))) return; + + /* Update the candidate record. */ + $updateSuccess = $candidates->update( + $candidateID, + $isActive, + $firstName, + $middleName, + $lastName, + $email1, + $email2, + $phoneHome, + $phoneCell, + $phoneWork, + $address, + $city, + $state, + $zip, + $source, + $keySkills, + $dateAvailable, + $currentEmployer, + $canRelocate, + $currentPay, + $desiredPay, + $notes, + $webSite, + $bestTimeToCall, + $owner, + $isHot, + $email, + $emailAddress, + $gender, + $race, + $veteran, + $disability + ); + if (!$updateSuccess) + { + CommonErrors::fatal(COMMONERROR_RECORDERROR, $this, 'Failed to update candidate.'); + } + + /* Update extra fields. */ + $candidates->extraFields->setValuesOnEdit($candidateID); + + /* Update possible source list */ + $sources = $candidates->getPossibleSources(); + $sourcesDifferences = ListEditor::getDifferencesFromList( + $sources, 'name', 'sourceID', $sourceCSV + ); + + $candidates->updatePossibleSources($sourcesDifferences); + + if (!eval(Hooks::get('CANDIDATE_ON_EDIT_POST'))) return; + + CATSUtility::transferRelativeURI( + 'm=candidates&a=show&candidateID=' . $candidateID + ); + } + + /* + * Called by handleRequest() to process deleting a candidate. + */ + private function onDelete() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidateID = $_GET['candidateID']; + + if (!eval(Hooks::get('CANDIDATE_DELETE'))) return; + + $candidates = new Candidates($this->_siteID); + $candidates->delete($candidateID); + + /* Delete the MRU entry if present. */ + $_SESSION['CATS']->getMRU()->removeEntry( + DATA_ITEM_CANDIDATE, $candidateID + ); + + CATSUtility::transferRelativeURI('m=candidates&a=listByView'); + } + + /* + * Called by handleRequest() to handle processing an "Add to a Job Order + * Pipeline" search and displaying the results in the modal dialog, or + * to show the initial dialog. + */ + private function considerForJobSearch($candidateIDArray = array()) + { + + /* Get list of candidates. */ + if (isset($_REQUEST['candidateIDArrayStored']) && $this->isRequiredIDValid('candidateIDArrayStored', $_REQUEST, true)) + { + $candidateIDArray = $_SESSION['CATS']->retrieveData($_REQUEST['candidateIDArrayStored']); + } + else if($this->isRequiredIDValid('candidateID', $_REQUEST)) + { + $candidateIDArray = array($_REQUEST['candidateID']); + } + else if ($candidateIDArray === array()) + { + $dataGrid = DataGrid::getFromRequest(); + + $candidateIDArray = $dataGrid->getExportIDs(); + } + + if (!is_array($candidateIDArray)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid variable type.'); + return; + } + + /* Validate each ID */ + foreach ($candidateIDArray as $index => $candidateID) + { + if (!$this->isRequiredIDValid($index, $candidateIDArray)) + { + echo('&'.$candidateID.'>'); + + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + return; + } + } + + /* Bail out to prevent an error if the POST string doesn't even contain + * a field named 'wildCardString' at all. + */ + if (!isset($_POST['wildCardString']) && isset($_POST['mode'])) + { + CommonErrors::fatal(COMMONERROR_WILDCARDSTRING, $this, 'No wild card string specified.'); + } + + $query = $this->getTrimmedInput('wildCardString', $_POST); + $mode = $this->getTrimmedInput('mode', $_POST); + + /* Execute the search. */ + $search = new SearchJobOrders($this->_siteID); + switch ($mode) + { + case 'searchByJobTitle': + $rs = $search->byTitle($query, 'title', 'ASC', true); + $resultsMode = true; + break; + + case 'searchByCompanyName': + $rs = $search->byCompanyName($query, 'title', 'ASC', true); + $resultsMode = true; + break; + + default: + $rs = $search->recentlyModified('DESC', true, 5); + $resultsMode = false; + break; + } + + $pipelines = new Pipelines($this->_siteID); + $pipelinesRS = $pipelines->getCandidatePipeline($candidateIDArray[0]); + + foreach ($rs as $rowIndex => $row) + { + if (ResultSetUtility::findRowByColumnValue($pipelinesRS, + 'jobOrderID', $row['jobOrderID']) !== false && count($candidateIDArray) == 1) + { + $rs[$rowIndex]['inPipeline'] = true; + } + else + { + $rs[$rowIndex]['inPipeline'] = false; + } + + /* Convert '00-00-00' dates to empty strings. */ + $rs[$rowIndex]['startDate'] = DateUtility::fixZeroDate( + $row['startDate'] + ); + + if ($row['isHot'] == 1) + { + $rs[$rowIndex]['linkClass'] = 'jobLinkHot'; + } + else + { + $rs[$rowIndex]['linkClass'] = 'jobLinkCold'; + } + + $rs[$rowIndex]['recruiterAbbrName'] = StringUtility::makeInitialName( + $row['recruiterFirstName'], + $row['recruiterLastName'], + false, + LAST_NAME_MAXLEN + ); + + $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( + $row['ownerFirstName'], + $row['ownerLastName'], + false, + LAST_NAME_MAXLEN + ); + } + + if (!eval(Hooks::get('CANDIDATE_ON_CONSIDER_FOR_JOB_SEARCH'))) return; + + $this->_template->assign('rs', $rs); + $this->_template->assign('isFinishedMode', false); + $this->_template->assign('isResultsMode', $resultsMode); + $this->_template->assign('candidateIDArray', $candidateIDArray); + $this->_template->assign('candidateIDArrayStored', $_SESSION['CATS']->storeData($candidateIDArray)); + $this->_template->display('./modules/candidates/ConsiderSearchModal.tpl'); + } + + /* + * Called by handleRequest() to process adding a candidate to a pipeline + * in the modal dialog. + */ + private function onAddToPipeline() + { + /* Bail out if we don't have a valid job order ID. */ + if (!$this->isRequiredIDValid('jobOrderID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid job order ID.'); + } + + if (isset($_GET['candidateID'])) + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidateIDArray = array($_GET['candidateID']); + } + else + { + if (!isset($_REQUEST['candidateIDArrayStored']) || !$this->isRequiredIDValid('candidateIDArrayStored', $_REQUEST, true)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidateIDArrayStored parameter.'); + return; + } + + $candidateIDArray = $_SESSION['CATS']->retrieveData($_REQUEST['candidateIDArrayStored']); + + if (!is_array($candidateIDArray)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid variable type.'); + return; + } + + /* Validate each ID */ + foreach ($candidateIDArray as $index => $candidateID) + { + if (!$this->isRequiredIDValid($index, $candidateIDArray)) + { + echo ($dataItemID); + + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + return; + } + } + } + + + $jobOrderID = $_GET['jobOrderID']; + + if (!eval(Hooks::get('CANDIDATE_ADD_TO_PIPELINE_PRE'))) return; + + $pipelines = new Pipelines($this->_siteID); + $activityEntries = new ActivityEntries($this->_siteID); + + /* Drop candidate ID's who are already in the pipeline */ + $pipelinesRS = $pipelines->getJobOrderPipeline($jobOrderID); + + foreach($pipelinesRS as $data) + { + $arrayPos = array_search($data['candidateID'], $candidateIDArray); + if ($arrayPos !== false) + { + unset($candidateIDArray[$arrayPos]); + } + } + + /* Add to pipeline */ + foreach($candidateIDArray as $candidateID) + { + if (!$pipelines->add($candidateID, $jobOrderID, $this->_userID)) + { + CommonErrors::fatalModal(COMMONERROR_RECORDERROR, $this, 'Failed to add candidate to Job Order.'); + } + + $activityID = $activityEntries->add( + $candidateID, + DATA_ITEM_CANDIDATE, + 400, + 'Added candidate to job order.', + $this->_userID, + $jobOrderID + ); + + if (!eval(Hooks::get('CANDIDATE_ADD_TO_PIPELINE_POST_IND'))) return; + } + + if (!eval(Hooks::get('CANDIDATE_ADD_TO_PIPELINE_POST'))) return; + + $this->_template->assign('isFinishedMode', true); + $this->_template->assign('jobOrderID', $jobOrderID); + $this->_template->assign('candidateIDArray', $candidateIDArray); + $this->_template->display( + './modules/candidates/ConsiderSearchModal.tpl' + ); + } + + private function addActivityChangeStatus() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + /* Bail out if we don't have a valid job order ID. */ + if (!$this->isOptionalIDValid('jobOrderID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid job order ID.'); + } + + $selectedJobOrderID = $_GET['jobOrderID']; + $candidateID = $_GET['candidateID']; + + $candidates = new Candidates($this->_siteID); + $candidateData = $candidates->get($candidateID); + + /* Bail out if we got an empty result set. */ + if (empty($candidateData)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); + return; + } + + $pipelines = new Pipelines($this->_siteID); + $pipelineRS = $pipelines->getCandidatePipeline($candidateID); + + $statusRS = $pipelines->getStatusesForPicking(); + + if ($selectedJobOrderID != -1) + { + $selectedStatusID = ResultSetUtility::getColumnValueByIDValue( + $pipelineRS, 'jobOrderID', $selectedJobOrderID, 'statusID' + ); + } + else + { + $selectedStatusID = -1; + } + + /* Get the change status email template. */ + $emailTemplates = new EmailTemplates($this->_siteID); + $statusChangeTemplateRS = $emailTemplates->getByTag( + 'EMAIL_TEMPLATE_STATUSCHANGE' + ); + if (empty($statusChangeTemplateRS) || + empty($statusChangeTemplateRS['textReplaced'])) + { + $statusChangeTemplate = ''; + $emailDisabled = '1'; + } + else + { + $statusChangeTemplate = $statusChangeTemplateRS['textReplaced']; + $emailDisabled = $statusChangeTemplateRS['disabled']; + } + + /* Replace e-mail template variables. '%CANDSTATUS%', '%JBODTITLE%', + * '%JBODCLIENT%' are replaced by JavaScript. + */ + $stringsToFind = array( + '%CANDOWNER%', + '%CANDFIRSTNAME%', + '%CANDFULLNAME%' + ); + $replacementStrings = array( + $candidateData['ownerFullName'], + $candidateData['firstName'], + $candidateData['firstName'] . ' ' . $candidateData['lastName'], + $candidateData['firstName'], + $candidateData['firstName'] + ); + $statusChangeTemplate = str_replace( + $stringsToFind, + $replacementStrings, + $statusChangeTemplate + ); + + /* Are we in "Only Schedule Event" mode? */ + $onlyScheduleEvent = $this->isChecked('onlyScheduleEvent', $_GET); + + $calendar = new Calendar($this->_siteID); + $calendarEventTypes = $calendar->getAllEventTypes(); + + if (!eval(Hooks::get('CANDIDATE_ADD_ACTIVITY_CHANGE_STATUS'))) return; + + if (SystemUtility::isSchedulerEnabled() && !$_SESSION['CATS']->isDemo()) + { + $allowEventReminders = true; + } + else + { + $allowEventReminders = false; + } + + $this->_template->assign('candidateID', $candidateID); + $this->_template->assign('pipelineRS', $pipelineRS); + $this->_template->assign('statusRS', $statusRS); + $this->_template->assign('selectedJobOrderID', $selectedJobOrderID); + $this->_template->assign('selectedStatusID', $selectedStatusID); + $this->_template->assign('allowEventReminders', $allowEventReminders); + $this->_template->assign('userEmail', $_SESSION['CATS']->getEmail()); + $this->_template->assign('calendarEventTypes', $calendarEventTypes); + $this->_template->assign('statusChangeTemplate', $statusChangeTemplate); + $this->_template->assign('onlyScheduleEvent', $onlyScheduleEvent); + $this->_template->assign('emailDisabled', $emailDisabled); + $this->_template->assign('isFinishedMode', false); + $this->_template->assign('isJobOrdersMode', false); + $this->_template->display( + './modules/candidates/AddActivityChangeStatusModal.tpl' + ); + } + + private function onAddCandidateTags() + { + /* Bail out if we don't have a valid regardingjob order ID. */ + if (!$this->isOptionalIDValid('candidateID', $_POST)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid Candidate ID.'); + } + + /* Bail out if we don't have a valid regardingjob order ID. */ + if (!isset($_POST['candidate_tags']) || !is_array($_POST['candidate_tags'])) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid Tag ID.'); + } + + $candidateID = $_POST['candidateID']; + $tagIDs = $_POST['candidate_tags']; + + $tags = new Tags($this->_siteID); + $tags->AddTagsToCandidate($candidateID, $tagIDs); + + $this->_template->assign('candidateID', $candidateID); + $this->_template->assign('isFinishedMode', true); + $this->_template->display( + './modules/candidates/AssignCandidateTagModal.tpl' + ); + + } + + + private function addCandidateTags() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidateID = $_GET['candidateID']; + + $candidates = new Candidates($this->_siteID); + $candidateData = $candidates->get($candidateID); + + /* Bail out if we got an empty result set. */ + if (empty($candidateData)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); + return; + /*$this->fatalModal( + 'The specified candidate ID could not be found.' + );*/ + } + + $tags = new Tags($this->_siteID); + $tagsRS = $tags->getAll(); + + $this->_template->assign('candidateID', $candidateID); + $this->_template->assign('assignedTags', $tags->getCandidateTagsID($candidateID)); + $this->_template->assign('isFinishedMode', false); + + $this->_template->assign('tagsRS', $tagsRS); + $this->_template->display( + './modules/candidates/AssignCandidateTagModal.tpl' + ); + + } + + + private function onAddActivityChangeStatus() + { + /* Bail out if we don't have a valid regardingjob order ID. */ + if (!$this->isOptionalIDValid('regardingID', $_POST)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid job order ID.'); + } + + $regardingID = $_POST['regardingID']; + + $this->_addActivityChangeStatus(false, $regardingID); + } + + /* + * Called by handleRequest() to process removing a candidate from the + * pipeline for a job order. + */ + private function onRemoveFromPipeline() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + /* Bail out if we don't have a valid job order ID. */ + if (!$this->isRequiredIDValid('jobOrderID', $_GET)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid job order ID.'); + } + + $candidateID = $_GET['candidateID']; + $jobOrderID = $_GET['jobOrderID']; + + if (!eval(Hooks::get('CANDIDATE_REMOVE_FROM_PIPELINE_PRE'))) return; + + $pipelines = new Pipelines($this->_siteID); + $pipelines->remove($candidateID, $jobOrderID); + + if (!eval(Hooks::get('CANDIDATE_REMOVE_FROM_PIPELINE_POST'))) return; + + CATSUtility::transferRelativeURI( + 'm=candidates&a=show&candidateID=' . $candidateID + ); + } + + /* + * Called by handleRequest() to process loading the search page. + */ + private function search() + { + $savedSearches = new SavedSearches($this->_siteID); + $savedSearchRS = $savedSearches->get(DATA_ITEM_CANDIDATE); + + if (!eval(Hooks::get('CANDIDATE_SEARCH'))) return; + + $this->_template->assign('wildCardString', ''); + $this->_template->assign('savedSearchRS', $savedSearchRS); + $this->_template->assign('active', $this); + $this->_template->assign('subActive', 'Search Candidates'); + $this->_template->assign('isResultsMode', false); + $this->_template->assign('isResumeMode', false); + $this->_template->assign('resumeWildCardString', ''); + $this->_template->assign('keySkillsWildCardString', ''); + $this->_template->assign('fullNameWildCardString', ''); + $this->_template->assign('phoneNumberWildCardString', ''); + $this->_template->assign('mode', ''); + $this->_template->display('./modules/candidates/Search.tpl'); + } + + /* + * Called by handleRequest() to process displaying the search results. + */ + private function onSearch() + { + /* Bail out to prevent an error if the GET string doesn't even contain + * a field named 'wildCardString' at all. + */ + if (!isset($_GET['wildCardString'])) + { + $this->listByView('No wild card string specified.'); + return; + } + + $query = trim($_GET['wildCardString']); + + /* Initialize stored wildcard strings to safe default values. */ + $resumeWildCardString = ''; + $keySkillsWildCardString = ''; + $phoneNumberWildCardString = ''; + $fullNameWildCardString = ''; + + /* Set up sorting. */ + if ($this->isRequiredIDValid('page', $_GET)) + { + $currentPage = $_GET['page']; + } + else + { + $currentPage = 1; + } + + $searchPager = new SearchPager( + CANDIDATES_PER_PAGE, $currentPage, $this->_siteID + ); + + if ($searchPager->isSortByValid('sortBy', $_GET)) + { + $sortBy = $_GET['sortBy']; + } + else + { + $sortBy = 'lastName'; + } + + if ($searchPager->isSortDirectionValid('sortDirection', $_GET)) + { + $sortDirection = $_GET['sortDirection']; + } + else + { + $sortDirection = 'ASC'; + } + + $baseURL = CATSUtility::getFilteredGET( + array('sortBy', 'sortDirection', 'page'), '&' + ); + $searchPager->setSortByParameters($baseURL, $sortBy, $sortDirection); + + $candidates = new Candidates($this->_siteID); + + /* Get our current searching mode. */ + $mode = $this->getTrimmedInput('mode', $_GET); + + /* Execute the search. */ + $search = new SearchCandidates($this->_siteID); + switch ($mode) + { + case 'searchByFullName': + $rs = $search->byFullName($query, $sortBy, $sortDirection); + + foreach ($rs as $rowIndex => $row) + { + if (!empty($row['ownerFirstName'])) + { + $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( + $row['ownerFirstName'], + $row['ownerLastName'], + false, + LAST_NAME_MAXLEN + ); + } + else + { + $rs[$rowIndex]['ownerAbbrName'] = 'None'; + } + + $rsResume = $candidates->getResumes($row['candidateID']); + if (isset($rsResume[0])) + { + $rs[$rowIndex]['resumeID'] = $rsResume[0]['attachmentID']; + } + } + + $isResumeMode = false; + + $fullNameWildCardString = $query; + break; + + case 'searchByKeySkills': + $rs = $search->byKeySkills($query, $sortBy, $sortDirection); + + foreach ($rs as $rowIndex => $row) + { + if (!empty($row['ownerFirstName'])) + { + $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( + $row['ownerFirstName'], + $row['ownerLastName'], + false, + LAST_NAME_MAXLEN + ); + } + else + { + $rs[$rowIndex]['ownerAbbrName'] = 'None'; + } + + $rsResume = $candidates->getResumes($row['candidateID']); + if (isset($rsResume[0])) + { + $rs[$rowIndex]['resumeID'] = $rsResume[0]['attachmentID']; + } + } + + $isResumeMode = false; + + $keySkillsWildCardString = $query; + + break; + + case 'searchByResume': + $searchPager = new SearchByResumePager( + 20, + $currentPage, + $this->_siteID, + $query, + $sortBy, + $sortDirection + ); + + $baseURL = 'm=candidates&a=search&getback=getback&mode=searchByResume&wildCardString=' + . urlencode($query) + . '&searchByResume=Search'; + + $searchPager->setSortByParameters( + $baseURL, $sortBy, $sortDirection + ); + + $rs = $searchPager->getPage(); + + $currentPage = $searchPager->getCurrentPage(); + $totalPages = $searchPager->getTotalPages(); + + $pageStart = $searchPager->getThisPageStartRow() + 1; + + if (($searchPager->getThisPageStartRow() + 20) <= $searchPager->getTotalRows()) + { + $pageEnd = $searchPager->getThisPageStartRow() + 20; + } + else + { + $pageEnd = $searchPager->getTotalRows(); + } + + foreach ($rs as $rowIndex => $row) + { + $rs[$rowIndex]['excerpt'] = SearchUtility::searchExcerpt( + $query, $row['text'] + ); + + if (!empty($row['ownerFirstName'])) + { + $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( + $row['ownerFirstName'], + $row['ownerLastName'], + false, + LAST_NAME_MAXLEN + ); + } + else + { + $rs[$rowIndex]['ownerAbbrName'] = 'None'; + } + } + + $isResumeMode = true; + + $this->_template->assign('active', $this); + $this->_template->assign('currentPage', $currentPage); + $this->_template->assign('pageStart', $pageStart); + $this->_template->assign('totalResults', $searchPager->getTotalRows()); + $this->_template->assign('pageEnd', $pageEnd); + $this->_template->assign('totalPages', $totalPages); + + $resumeWildCardString = $query; + break; + + case 'phoneNumber': + $rs = $search->byPhone($query, $sortBy, $sortDirection); + + foreach ($rs as $rowIndex => $row) + { + if (!empty($row['ownerFirstName'])) + { + $rs[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( + $row['ownerFirstName'], + $row['ownerLastName'], + false, + LAST_NAME_MAXLEN + ); + } + else + { + $rs[$rowIndex]['ownerAbbrName'] = 'None'; + } + + $rsResume = $candidates->getResumes($row['candidateID']); + if (isset($rsResume[0])) + { + $rs[$rowIndex]['resumeID'] = $rsResume[0]['attachmentID']; + } + } + + $isResumeMode = false; + + $phoneNumberWildCardString = $query; + break; + + default: + $this->listByView('Invalid search mode.'); + return; + break; + } + + $candidateIDs = implode(',', ResultSetUtility::getColumnValues($rs, 'candidateID')); + $exportForm = ExportUtility::getForm( + DATA_ITEM_CANDIDATE, $candidateIDs, 32, 9 + ); + + if (!eval(Hooks::get('CANDIDATE_ON_SEARCH'))) return; + + /* Save the search. */ + $savedSearches = new SavedSearches($this->_siteID); + $savedSearches->add( + DATA_ITEM_CANDIDATE, + $query, + $_SERVER['REQUEST_URI'], + false + ); + $savedSearchRS = $savedSearches->get(DATA_ITEM_CANDIDATE); + + $this->_template->assign('savedSearchRS', $savedSearchRS); + $this->_template->assign('exportForm', $exportForm); + $this->_template->assign('active', $this); + $this->_template->assign('rs', $rs); + $this->_template->assign('pager', $searchPager); + $this->_template->assign('isResultsMode', true); + $this->_template->assign('isResumeMode', $isResumeMode); + $this->_template->assign('wildCardString', $query); + $this->_template->assign('resumeWildCardString', $resumeWildCardString); + $this->_template->assign('keySkillsWildCardString', $keySkillsWildCardString); + $this->_template->assign('fullNameWildCardString', $fullNameWildCardString); + $this->_template->assign('phoneNumberWildCardString', $phoneNumberWildCardString); + $this->_template->assign('mode', $mode); + $this->_template->display('./modules/candidates/Search.tpl'); + } + + /* + * Called by handleRequest() to process showing a resume preview. + */ + private function viewResume() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('attachmentID', $_GET)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid attachment ID.'); + } + + $attachmentID = $_GET['attachmentID']; + + /* Get the search string. */ + $query = $this->getTrimmedInput('wildCardString', $_GET); + + /* Get resume text. */ + $candidates = new Candidates($this->_siteID); + $data = $candidates->getResume($attachmentID); + + if (!empty($data)) + { + /* Keyword highlighting. */ + $data['text'] = SearchUtility::makePreview($query, $data['text']); + } + + if (!eval(Hooks::get('CANDIDATE_VIEW_RESUME'))) return; + + $this->_template->assign('active', $this); + $this->_template->assign('data', $data); + $this->_template->display('./modules/candidates/ResumeView.tpl'); + } + + private function addEditImage() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidateID = $_GET['candidateID']; + + $attachments = new Attachments($this->_siteID); + $attachmentsRS = $attachments->getAll( + DATA_ITEM_CANDIDATE, $candidateID + ); + + if (!eval(Hooks::get('CANDIDATE_ADD_EDIT_IMAGE'))) return; + + $this->_template->assign('isFinishedMode', false); + $this->_template->assign('candidateID', $candidateID); + $this->_template->assign('attachmentsRS', $attachmentsRS); + $this->_template->display( + './modules/candidates/CreateImageAttachmentModal.tpl' + ); + } + + /* + * Called by handleRequest() to process creating an attachment. + */ + private function onAddEditImage() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_POST)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidateID = $_POST['candidateID']; + + if (!eval(Hooks::get('CANDIDATE_ON_ADD_EDIT_IMAGE_PRE'))) return; + + $attachmentCreator = new AttachmentCreator($this->_siteID); + $attachmentCreator->createFromUpload( + DATA_ITEM_CANDIDATE, $candidateID, 'file', true, false + ); + + if ($attachmentCreator->isError()) + { + CommonErrors::fatalModal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); + return; + //$this->fatalModal($attachmentCreator->getError()); + } + + if (!eval(Hooks::get('CANDIDATE_ON_ADD_EDIT_IMAGE_POST'))) return; + + $this->_template->assign('isFinishedMode', true); + $this->_template->assign('candidateID', $candidateID); + $this->_template->display( + './modules/candidates/CreateImageAttachmentModal.tpl' + ); + } + + /* + * Called by handleRequest() to process loading the create attachment + * modal dialog. + */ + private function createAttachment() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidateID = $_GET['candidateID']; + + if (!eval(Hooks::get('CANDIDATE_CREATE_ATTACHMENT'))) return; + + $this->_template->assign('isFinishedMode', false); + $this->_template->assign('candidateID', $candidateID); + $this->_template->display( + './modules/candidates/CreateAttachmentModal.tpl' + ); + } + + /* + * Called by handleRequest() to process creating an attachment. + */ + private function onCreateAttachment() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_POST)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + /* Bail out if we don't have a valid resume status. */ + if (!$this->isRequiredIDValid('resume', $_POST, true) || + $_POST['resume'] < 0 || $_POST['resume'] > 1) + { + CommonErrors::fatalModal(COMMONERROR_RECORDERROR, $this, 'Invalid resume status.'); + } + + $candidateID = $_POST['candidateID']; + + if ($_POST['resume'] == '1') + { + $isResume = true; + } + else + { + $isResume = false; + } + + if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_PRE'))) return; + + $attachmentCreator = new AttachmentCreator($this->_siteID); + $attachmentCreator->createFromUpload( + DATA_ITEM_CANDIDATE, $candidateID, 'file', false, $isResume + ); + + if ($attachmentCreator->isError()) + { + CommonErrors::fatalModal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); + return; + //$this->fatalModal($attachmentCreator->getError()); + } + + if ($attachmentCreator->duplicatesOccurred()) + { + $this->fatalModal( + 'This attachment has already been added to this candidate.' + ); + } + + $isTextExtractionError = $attachmentCreator->isTextExtractionError(); + $textExtractionErrorMessage = $attachmentCreator->getTextExtractionError(); + $resumeText = $attachmentCreator->getExtractedText(); + + if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_POST'))) return; + + $this->_template->assign('resumeText', $resumeText); + $this->_template->assign('isFinishedMode', true); + $this->_template->assign('candidateID', $candidateID); + $this->_template->display( + './modules/candidates/CreateAttachmentModal.tpl' + ); + } + + /* + * Called by handleRequest() to process deleting an attachment. + */ + private function onDeleteAttachment() + { + /* Bail out if we don't have a valid attachment ID. */ + if (!$this->isRequiredIDValid('attachmentID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid attachment ID.'); + } + + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + $candidateID = $_GET['candidateID']; + $attachmentID = $_GET['attachmentID']; + + if (!eval(Hooks::get('CANDIDATE_ON_DELETE_ATTACHMENT_PRE'))) return; + + $attachments = new Attachments($this->_siteID); + $attachments->delete($attachmentID); + + if (!eval(Hooks::get('CANDIDATE_ON_DELETE_ATTACHMENT_POST'))) return; + + CATSUtility::transferRelativeURI( + 'm=candidates&a=show&candidateID=' . $candidateID + ); + } + + //TODO: Document me. + //Only accessable by MSA users - hides this job order from everybody by + private function administrativeHideShow() + { + /* Bail out if we don't have a valid joborder ID. */ + if (!$this->isRequiredIDValid('candidateID', $_GET)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid Job Order ID.'); + } + + /* Bail out if we don't have a valid status ID. */ + if (!$this->isRequiredIDValid('state', $_GET, true)) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Invalid state ID.'); + } + + $candidateID = $_GET['candidateID']; + + // FIXME: Checkbox? + $state = (boolean) $_GET['state']; + + $candidates = new Candidates($this->_siteID); + $candidates->administrativeHideShow($candidateID, $state); + + CATSUtility::transferRelativeURI('m=candidates&a=show&candidateID='.$candidateID); + } + + /** + * Formats SQL result set for display. This is factored out for code + * clarity. + * + * @param array result set from listByView() + * @return array formatted result set + */ + private function _formatListByViewResults($resultSet) + { + if (empty($resultSet)) + { + return $resultSet; + } + + foreach ($resultSet as $rowIndex => $row) + { + if ($resultSet[$rowIndex]['isHot'] == 1) + { + $resultSet[$rowIndex]['linkClass'] = 'jobLinkHot'; + } + else + { + $resultSet[$rowIndex]['linkClass'] = 'jobLinkCold'; + } + + if (!empty($resultSet[$rowIndex]['ownerFirstName'])) + { + $resultSet[$rowIndex]['ownerAbbrName'] = StringUtility::makeInitialName( + $resultSet[$rowIndex]['ownerFirstName'], + $resultSet[$rowIndex]['ownerLastName'], + false, + LAST_NAME_MAXLEN + ); + } + else + { + $resultSet[$rowIndex]['ownerAbbrName'] = 'None'; + } + + if ($resultSet[$rowIndex]['submitted'] == 1) + { + $resultSet[$rowIndex]['iconTag'] = ''; + } + else + { + $resultSet[$rowIndex]['iconTag'] = ''; + } + + if ($resultSet[$rowIndex]['attachmentPresent'] == 1) + { + $resultSet[$rowIndex]['iconTag'] .= ''; + } + else + { + $resultSet[$rowIndex]['iconTag'] .= ''; + } + + + if (empty($resultSet[$rowIndex]['keySkills'])) + { + $resultSet[$rowIndex]['keySkills'] = ' '; + } + else + { + $resultSet[$rowIndex]['keySkills'] = htmlspecialchars( + $resultSet[$rowIndex]['keySkills'] + ); + } + + /* Truncate Key Skills to fit the column width */ + if (strlen($resultSet[$rowIndex]['keySkills']) > self::TRUNCATE_KEYSKILLS) + { + $resultSet[$rowIndex]['keySkills'] = substr( + $resultSet[$rowIndex]['keySkills'], + 0, + self::TRUNCATE_KEYSKILLS + ) . "..."; + } + } + + return $resultSet; + } + + /** + * Adds a candidate. This is factored out for code clarity. + * + * @param boolean is modal window + * @param string module directory + * @return integer candidate ID + */ + private function _addCandidate($isModal, $directoryOverride = '') + { + /* Module directory override for fatal() calls. */ + if ($directoryOverride != '') + { + $moduleDirectory = $directoryOverride; + } + else + { + $moduleDirectory = $this->_moduleDirectory; + } + + /* Modal override for fatal() calls. */ + if ($isModal) + { + $fatal = 'fatalModal'; + } + else + { + $fatal = 'fatal'; + } + + /* Bail out if we received an invalid availability date; if not, go + * ahead and convert the date to MySQL format. + */ + $dateAvailable = $this->getTrimmedInput('dateAvailable', $_POST); + if (!empty($dateAvailable)) + { + if (!DateUtility::validate('-', $dateAvailable, DATE_FORMAT_MMDDYY)) + { + $this->$fatal('Invalid availability date.', $moduleDirectory); + } + + /* Convert start_date to something MySQL can understand. */ + $dateAvailable = DateUtility::convert( + '-', $dateAvailable, DATE_FORMAT_MMDDYY, DATE_FORMAT_YYYYMMDD + ); + } + + $formattedPhoneHome = StringUtility::extractPhoneNumber( + $this->getTrimmedInput('phoneHome', $_POST) + ); + if (!empty($formattedPhoneHome)) + { + $phoneHome = $formattedPhoneHome; + } + else + { + $phoneHome = $this->getTrimmedInput('phoneHome', $_POST); + } + + $formattedPhoneCell = StringUtility::extractPhoneNumber( + $this->getTrimmedInput('phoneCell', $_POST) + ); + if (!empty($formattedPhoneCell)) + { + $phoneCell = $formattedPhoneCell; + } + else + { + $phoneCell = $this->getTrimmedInput('phoneCell', $_POST); + } + + $formattedPhoneWork = StringUtility::extractPhoneNumber( + $this->getTrimmedInput('phoneWork', $_POST) + ); + if (!empty($formattedPhoneWork)) + { + $phoneWork = $formattedPhoneWork; + } + else + { + $phoneWork = $this->getTrimmedInput('phoneWork', $_POST); + } + + /* Can Relocate */ + $canRelocate = $this->isChecked('canRelocate', $_POST); + + $lastName = $this->getTrimmedInput('lastName', $_POST); + $middleName = $this->getTrimmedInput('middleName', $_POST); + $firstName = $this->getTrimmedInput('firstName', $_POST); + $email1 = $this->getTrimmedInput('email1', $_POST); + $email2 = $this->getTrimmedInput('email2', $_POST); + $address = $this->getTrimmedInput('address', $_POST); + $city = $this->getTrimmedInput('city', $_POST); + $state = $this->getTrimmedInput('state', $_POST); + $zip = $this->getTrimmedInput('zip', $_POST); + $source = $this->getTrimmedInput('source', $_POST); + $keySkills = $this->getTrimmedInput('keySkills', $_POST); + $currentEmployer = $this->getTrimmedInput('currentEmployer', $_POST); + $currentPay = $this->getTrimmedInput('currentPay', $_POST); + $desiredPay = $this->getTrimmedInput('desiredPay', $_POST); + $notes = $this->getTrimmedInput('notes', $_POST); + $webSite = $this->getTrimmedInput('webSite', $_POST); + $bestTimeToCall = $this->getTrimmedInput('bestTimeToCall', $_POST); + $gender = $this->getTrimmedInput('gender', $_POST); + $race = $this->getTrimmedInput('race', $_POST); + $veteran = $this->getTrimmedInput('veteran', $_POST); + $disability = $this->getTrimmedInput('disability', $_POST); + + /* Candidate source list editor. */ + $sourceCSV = $this->getTrimmedInput('sourceCSV', $_POST); + + /* Text resume. */ + $textResumeBlock = $this->getTrimmedInput('textResumeBlock', $_POST); + $textResumeFilename = $this->getTrimmedInput('textResumeFilename', $_POST); + + /* File resume. */ + $associatedFileResumeID = $this->getTrimmedInput('associatedbFileResumeID', $_POST); + + /* Bail out if any of the required fields are empty. */ + if (empty($firstName) || empty($lastName)) + { + CommonErrors::fatal(COMMONERROR_MISSINGFIELDS, $this); + } + + if (!eval(Hooks::get('CANDIDATE_ON_ADD_PRE'))) return; + + $candidates = new Candidates($this->_siteID); + + $duplicatesID = $candidates->checkDuplicity($firstName, $middleName, $lastName, $email1, $email2, $phoneHome, $phoneCell, $phoneWork, $address, $city); + + $candidateID = $candidates->add( + $firstName, + $middleName, + $lastName, + $email1, + $email2, + $phoneHome, + $phoneCell, + $phoneWork, + $address, + $city, + $state, + $zip, + $source, + $keySkills, + $dateAvailable, + $currentEmployer, + $canRelocate, + $currentPay, + $desiredPay, + $notes, + $webSite, + $bestTimeToCall, + $this->_userID, + $this->_userID, + $gender, + $race, + $veteran, + $disability + ); + + + if ($candidateID <= 0) + { + return $candidateID; + } + + if(sizeof($duplicatesID) > 0) + { + $candidates->addDuplicates($candidateID, $duplicatesID); + } + + /* Update extra fields. */ + $candidates->extraFields->setValuesOnEdit($candidateID); + + /* Update possible source list. */ + $sources = $candidates->getPossibleSources(); + $sourcesDifferences = ListEditor::getDifferencesFromList( + $sources, 'name', 'sourceID', $sourceCSV + ); + $candidates->updatePossibleSources($sourcesDifferences); + + /* Associate an exsisting resume if the user created a candidate with one. (Bulk) */ + if (isset($_POST['associatedAttachment'])) + { + $attachmentID = $_POST['associatedAttachment']; + + $attachments = new Attachments($this->_siteID); + $attachments->setDataItemID($attachmentID, $candidateID, DATA_ITEM_CANDIDATE); + } + + /* Attach a resume if the user uploaded one. (http POST) */ + /* NOTE: This function cannot be called if parsing is enabled */ + else if (isset($_FILES['file']) && !empty($_FILES['file']['name'])) + { + if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_PRE'))) return; + + $attachmentCreator = new AttachmentCreator($this->_siteID); + $attachmentCreator->createFromUpload( + DATA_ITEM_CANDIDATE, $candidateID, 'file', false, true + ); + + if ($attachmentCreator->isError()) + { + CommonErrors::fatal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); + } + + + if ($attachmentCreator->duplicatesOccurred()) + { + $this->listByView( + 'This attachment has already been added to this candidate.' + ); + return; + } + + $isTextExtractionError = $attachmentCreator->isTextExtractionError(); + $textExtractionErrorMessage = $attachmentCreator->getTextExtractionError(); + + // FIXME: Show parse errors! + + if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_POST'))) return; + } + + /** + * User has loaded and/or parsed a resume. The attachment is saved in a temporary + * file already and just needs to be attached. The attachment has also successfully + * been DocumentToText converted, so we know it's a good file. + */ + else if (LicenseUtility::isParsingEnabled()) + { + /** + * Description: User clicks "browse" and selects a resume file. User doesn't click + * upload. The resume file is STILL uploaded. + * Controversial: User uploads a resume, parses, etc. User selects a new file with + * "Browse" but doesn't click "Upload". New file is accepted. + * It's technically correct either way, I'm opting for the "use whats in "file" + * box over what's already uploaded method to avoid losing resumes on candidate + * additions. + */ + $newFile = FileUtility::getUploadFileFromPost($this->_siteID, 'addcandidate', 'documentFile'); + + if ($newFile !== false) + { + $newFilePath = FileUtility::getUploadFilePath($this->_siteID, 'addcandidate', $newFile); + + $tempFile = $newFile; + $tempFullPath = $newFilePath; + } + else + { + $attachmentCreated = false; + + $tempFile = false; + $tempFullPath = false; + + if (isset($_POST['documentTempFile']) && !empty($_POST['documentTempFile'])) + { + $tempFile = $_POST['documentTempFile']; + // Get the path of the file they uploaded already to attach + $tempFullPath = FileUtility::getUploadFilePath( + $this->_siteID, // ID of the containing site + 'addcandidate', // Sub-directory in their storage + $tempFile // Name of the file (not pathed) + ); + } + } + + if ($tempFile !== false && $tempFullPath !== false) + { + if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_PRE'))) return; + + $attachmentCreator = new AttachmentCreator($this->_siteID); + $attachmentCreator->createFromFile( + DATA_ITEM_CANDIDATE, $candidateID, $tempFullPath, $tempFile, '', true, true + ); + + if ($attachmentCreator->isError()) + { + CommonErrors::fatal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); + } + + + if ($attachmentCreator->duplicatesOccurred()) + { + $this->listByView( + 'This attachment has already been added to this candidate.' + ); + return; + } + + $isTextExtractionError = $attachmentCreator->isTextExtractionError(); + $textExtractionErrorMessage = $attachmentCreator->getTextExtractionError(); + + if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_POST'))) return; + + // Remove the cleanup cookie since the file no longer exists + setcookie('CATS_SP_TEMP_FILE', ''); + + $attachmentCreated = true; + } + + if (!$attachmentCreated && isset($_POST['documentText']) && !empty($_POST['documentText'])) + { + // Resume was pasted into the form and not uploaded from a file + + if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_PRE'))) return; + + $attachmentCreator = new AttachmentCreator($this->_siteID); + $attachmentCreator->createFromText( + DATA_ITEM_CANDIDATE, $candidateID, $_POST['documentText'], 'MyResume.txt', true + ); + + if ($attachmentCreator->isError()) + { + CommonErrors::fatal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); + } + + if ($attachmentCreator->duplicatesOccurred()) + { + $this->listByView( + 'This attachment has already been added to this candidate.' + ); + return; + } + + if (!eval(Hooks::get('CANDIDATE_ON_CREATE_ATTACHMENT_POST'))) return; + } + } + + /* Create a text resume if the user posted one. (automated tool) */ + else if (!empty($textResumeBlock)) + { + $attachmentCreator = new AttachmentCreator($this->_siteID); + $attachmentCreator->createFromText( + DATA_ITEM_CANDIDATE, $candidateID, $textResumeBlock, $textResumeFilename, true + ); + + if ($attachmentCreator->isError()) + { + CommonErrors::fatal(COMMONERROR_FILEERROR, $this, $attachmentCreator->getError()); + return; + //$this->fatal($attachmentCreator->getError()); + } + $isTextExtractionError = $attachmentCreator->isTextExtractionError(); + $textExtractionErrorMessage = $attachmentCreator->getTextExtractionError(); + + // FIXME: Show parse errors! + } + + if (!eval(Hooks::get('CANDIDATE_ON_ADD_POST'))) return; + + return $candidateID; + } + + /** + * Processes an Add Activity / Change Status form and displays + * candidates/AddActivityChangeStatusModal.tpl. This is factored out + * for code clarity. + * + * @param boolean from joborders module perspective + * @param integer "regarding" job order ID or -1 + * @param string module directory + * @return void + */ + private function _addActivityChangeStatus($isJobOrdersMode, $regardingID, + $directoryOverride = '') + { + $notificationHTML = ''; + + $pipelines = new Pipelines($this->_siteID); + $statusRS = $pipelines->getStatusesForPicking(); + + /* Module directory override for fatal() calls. */ + if ($directoryOverride != '') + { + $moduleDirectory = $directoryOverride; + } + else + { + $moduleDirectory = $this->_moduleDirectory; + } + + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('candidateID', $_POST)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + } + + /* Do we have a valid status ID. */ + if (!$this->isOptionalIDValid('statusID', $_POST)) + { + $statusID = -1; + } + else + { + $statusID = $_POST['statusID']; + if($statusID == PIPELINE_STATUS_PLACED) + { + $jobOrders = new JobOrders($this->_siteID); + $canBeHired = $jobOrders->checkOpenings($regardingID); + if(!$canBeHired) + { + $this->fatalModal( + 'This job order has been filled. Cannot assign the status Placed to any other candidate.' + ); + } + } + } + + $candidateID = $_POST['candidateID']; + + if (!eval(Hooks::get('CANDIDATE_ON_ADD_ACTIVITY_CHANGE_STATUS_PRE'))) return; + + if ($this->isChecked('addActivity', $_POST)) + { + /* Bail out if we don't have a valid job order ID. */ + if (!$this->isOptionalIDValid('activityTypeID', $_POST)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid activity type ID.'); + } + + $activityTypeID = $_POST['activityTypeID']; + + $activityNote = $this->getTrimmedInput('activityNote', $_POST); + + $activityNote = htmlspecialchars($activityNote); + + // FIXME: Move this to a highlighter-method? */ + if (strpos($activityNote, 'Status change: ') === 0) + { + foreach ($statusRS as $data) + { + $activityNote = StringUtility::replaceOnce( + $data['status'], + '' . $data['status'] . '', + $activityNote + ); + } + } + + /* Add the activity entry. */ + $activityEntries = new ActivityEntries($this->_siteID); + $activityID = $activityEntries->add( + $candidateID, + DATA_ITEM_CANDIDATE, + $activityTypeID, + $activityNote, + $this->_userID, + $regardingID + ); + $activityTypes = $activityEntries->getTypes(); + $activityTypeDescription = ResultSetUtility::getColumnValueByIDValue( + $activityTypes, 'typeID', $activityTypeID, 'type' + ); + + $activityAdded = true; + } + else + { + $activityAdded = false; + $activityNote = ''; + $activityTypeDescription = ''; + } + + if ($regardingID <= 0 || $statusID == -1) + { + $statusChanged = false; + $oldStatusDescription = ''; + $newStatusDescription = ''; + } + else + { + $data = $pipelines->get($candidateID, $regardingID); + + /* Bail out if we got an empty result set. */ + if (empty($data)) + { + $this->fatalModal( + 'The specified pipeline entry could not be found.' + ); + } + + $validStatus = ResultSetUtility::findRowByColumnValue( + $statusRS, 'statusID', $statusID + ); + + /* If the status is invalid or unchanged, don't mess with it. */ + if ($validStatus === false || $statusID == $data['status']) + { + $oldStatusDescription = ''; + $newStatusDescription = ''; + $statusChanged = false; + } + else + { + $oldStatusDescription = $data['status']; + $newStatusDescription = ResultSetUtility::getColumnValueByIDValue( + $statusRS, 'statusID', $statusID, 'status' + ); + + if ($oldStatusDescription != $newStatusDescription) + { + $statusChanged = true; + } + else + { + $statusChanged = false; + } + } + + if ($statusChanged && $this->isChecked('triggerEmail', $_POST)) + { + $customMessage = $this->getTrimmedInput('customMessage', $_POST); + + // FIXME: Actually validate the e-mail address? + if (empty($data['candidateEmail'])) + { + $email = ''; + $notificationHTML = '

Error: An e-mail notification' + . ' could not be sent to the candidate because the candidate' + . ' does not have a valid e-mail address.

'; + } + else if (empty($customMessage)) + { + $email = ''; + $notificationHTML = '

Error: An e-mail notification' + . ' will not be sent because the message text specified was blank.

'; + } + else if ($this->getUserAccessLevel('candidates.emailCandidates') == ACCESS_LEVEL_DEMO) + { + $email = ''; + $notificationHTML = '

Error: Demo users can not send' + . ' E-Mails. No E-Mail was sent.

'; + } + else + { + $email = $data['candidateEmail']; + $notificationHTML = '

An e-mail notification has been sent to the candidate.

'; + } + } + else + { + $email = ''; + $customMessage = ''; + $notificationHTML = '

No e-mail notification has been sent to the candidate.

'; + } + + /* Set the pipeline entry's status, but don't send e-mails for now. */ + $pipelines->setStatus( + $candidateID, $regardingID, $statusID, $email, $customMessage + ); + + /* If status = placed, and open positions > 0, reduce number of open positions by one. */ + if ($statusID == PIPELINE_STATUS_PLACED && is_numeric($data['openingsAvailable']) && $data['openingsAvailable'] > 0) + { + $jobOrders = new JobOrders($this->_siteID); + $jobOrders->updateOpeningsAvailable($regardingID, $data['openingsAvailable'] - 1); + } + + /* If status is changed from placed to something else, increase number of open positions by one. */ + if ($statusID != PIPELINE_STATUS_PLACED && $data['statusID'] == PIPELINE_STATUS_PLACED) + { + $jobOrders = new JobOrders($this->_siteID); + $jobOrders->updateOpeningsAvailable($regardingID, $data['openingsAvailable'] + 1); + } + } + + if ($this->isChecked('scheduleEvent', $_POST)) + { + /* Bail out if we received an invalid date. */ + $trimmedDate = $this->getTrimmedInput('dateAdd', $_POST); + if (empty($trimmedDate) || + !DateUtility::validate('-', $trimmedDate, DATE_FORMAT_MMDDYY)) + { + CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid date.'); + } + + /* Bail out if we don't have a valid event type. */ + if (!$this->isRequiredIDValid('eventTypeID', $_POST)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid event type ID.'); + } + + /* Bail out if we don't have a valid time format ID. */ + if (!isset($_POST['allDay']) || + ($_POST['allDay'] != '0' && $_POST['allDay'] != '1')) + { + CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid time format ID.'); + } + + $eventTypeID = $_POST['eventTypeID']; + + if ($_POST['allDay'] == 1) + { + $allDay = true; + } + else + { + $allDay = false; + } + + $publicEntry = $this->isChecked('publicEntry', $_POST); + + $reminderEnabled = $this->isChecked('reminderToggle', $_POST); + $reminderEmail = $this->getTrimmedInput('sendEmail', $_POST); + $reminderTime = $this->getTrimmedInput('reminderTime', $_POST); + $duration = $this->getTrimmedInput('duration', $_POST);; + + /* Is this a scheduled event or an all day event? */ + if ($allDay) + { + $date = DateUtility::convert( + '-', $trimmedDate, DATE_FORMAT_MMDDYY, DATE_FORMAT_YYYYMMDD + ); + + $hour = 12; + $minute = 0; + $meridiem = 'AM'; + } + else + { + /* Bail out if we don't have a valid hour. */ + if (!isset($_POST['hour'])) + { + CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid hour.'); + } + + /* Bail out if we don't have a valid minute. */ + if (!isset($_POST['minute'])) + { + CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this, 'Invalid minute.'); + } + + /* Bail out if we don't have a valid meridiem value. */ + if (!isset($_POST['meridiem']) || + ($_POST['meridiem'] != 'AM' && $_POST['meridiem'] != 'PM')) + { + $this->fatalModal( + 'Invalid meridiem value.', $moduleDirectory + ); + } + + $hour = $_POST['hour']; + $minute = $_POST['minute']; + $meridiem = $_POST['meridiem']; + + /* Convert formatted time to UNIX timestamp. */ + $time = strtotime( + sprintf('%s:%s %s', $hour, $minute, $meridiem) + ); + + /* Create MySQL date string w/ 24hr time (YYYY-MM-DD HH:MM:SS). */ + $date = sprintf( + '%s %s', + DateUtility::convert( + '-', + $trimmedDate, + DATE_FORMAT_MMDDYY, + DATE_FORMAT_YYYYMMDD + ), + date('H:i:00', $time) + ); + } + + $description = $this->getTrimmedInput('description', $_POST); + $title = $this->getTrimmedInput('title', $_POST); + + /* Bail out if any of the required fields are empty. */ + if (empty($title)) + { + CommonErrors::fatalModal(COMMONERROR_MISSINGFIELDS, $this); + return; + /*$this->fatalModal( + 'Required fields are missing.', $moduleDirectory + );*/ + } + + if ($regardingID > 0) + { + $eventJobOrderID = $regardingID; + } + else + { + $eventJobOrderID = -1; + } + + $calendar = new Calendar($this->_siteID); + $eventID = $calendar->addEvent( + $eventTypeID, $date, $description, $allDay, $this->_userID, + $candidateID, DATA_ITEM_CANDIDATE, $eventJobOrderID, $title, + $duration, $reminderEnabled, $reminderEmail, $reminderTime, + $publicEntry, $_SESSION['CATS']->getTimeZoneOffset() + ); + + if ($eventID <= 0) + { + $this->fatalModal( + 'Failed to add calendar event.', $moduleDirectory + ); + } + + /* Extract the date parts from the specified date. */ + $parsedDate = strtotime($date); + $formattedDate = date('l, F jS, Y', $parsedDate); + + $calendar = new Calendar($this->_siteID); + $calendarEventTypes = $calendar->getAllEventTypes(); + + $eventTypeDescription = ResultSetUtility::getColumnValueByIDValue( + $calendarEventTypes, 'typeID', $eventTypeID, 'description' + ); + + $eventHTML = sprintf( + '

An event of type %s has been scheduled on %s.

', + htmlspecialchars($eventTypeDescription), + htmlspecialchars($formattedDate) + + ); + $eventScheduled = true; + } + else + { + $eventHTML = '

No event has been scheduled.

'; + $eventScheduled = false; + } + + if (isset($_GET['onlyScheduleEvent'])) + { + $onlyScheduleEvent = true; + } + else + { + $onlyScheduleEvent = false; + } + + if (!$statusChanged && !$activityAdded && !$eventScheduled) + { + $changesMade = false; + } + else + { + $changesMade = true; + } + + if (!eval(Hooks::get('CANDIDATE_ON_ADD_ACTIVITY_CHANGE_STATUS_POST'))) return; + + $this->_template->assign('candidateID', $candidateID); + $this->_template->assign('regardingID', $regardingID); + $this->_template->assign('oldStatusDescription', $oldStatusDescription); + $this->_template->assign('newStatusDescription', $newStatusDescription); + $this->_template->assign('statusChanged', $statusChanged); + $this->_template->assign('activityAdded', $activityAdded); + $this->_template->assign('activityDescription', $activityNote); + $this->_template->assign('activityType', $activityTypeDescription); + $this->_template->assign('eventScheduled', $eventScheduled); + $this->_template->assign('eventHTML', $eventHTML); + $this->_template->assign('notificationHTML', $notificationHTML); + $this->_template->assign('onlyScheduleEvent', $onlyScheduleEvent); + $this->_template->assign('changesMade', $changesMade); + $this->_template->assign('isFinishedMode', true); + $this->_template->assign('isJobOrdersMode', $isJobOrdersMode); + $this->_template->display( + './modules/candidates/AddActivityChangeStatusModal.tpl' + ); + } + + /* + * Sends mass emails from the datagrid + */ + private function onEmailCandidates() + { + if (isset($_POST['postback'])) + { + $emailTo = $_POST['emailTo']; + $emailSubject = $_POST['emailSubject']; + $emailBody = $_POST['emailBody']; + + $tmpDestination = explode(', ', $emailTo); + $destination = array(); + foreach($tmpDestination as $emailDest) + { + $destination[] = array($emailDest, $emailDest); + } + + $mailer = new Mailer(CATS_ADMIN_SITE); + + if($_POST['emailTemplate'] == "-1") + { + $mailerStatus = $mailer->send( + array($_SESSION['CATS']->getEmail(), $_SESSION['CATS']->getEmail()), + $destination, + $emailSubject, + $emailBody, + true, + true + ); + } + else + { + $emailTemplates = new EmailTemplates($this->_siteID); + $candidates = new Candidates($this->_siteID); + + $emailsToIDs = $_POST['candidateID']; + $candidateIDs = array(); + foreach($emailsToIDs as $email) + { + $temp = explode('=', $email); + $candidateIDs[$temp[0]] = $temp[1]; + } + foreach($candidateIDs as $email => $ID) + { + $candidateData = $candidates->get($ID); + $emailTextSubstituted = $emailTemplates->replaceVariables($emailBody); + $stringsToFind = array( + '%CANDOWNER%', + '%CANDFIRSTNAME%', + '%CANDFULLNAME%' + ); + $replacementStrings = array( + $candidateData['ownerFullName'], + $candidateData['firstName'], + $candidateData['candidateFullName'] + ); + $emailTextSubstituted = str_replace( + $stringsToFind, + $replacementStrings, + $emailTextSubstituted + ); + + $mailerStatus = $mailer->sendToOne( + array($email, $candidateData['candidateFullName']), + $emailSubject, + $emailTextSubstituted, + true + ); + } + } + + $this->_template->assign('active', $this); + $this->_template->assign('success', true); + $this->_template->assign('success_to', $emailTo); + $this->_template->display('./modules/candidates/SendEmail.tpl'); + } + else + { + $dataGrid = DataGrid::getFromRequest(); + + $candidateIDs = $dataGrid->getExportIDs(); + + /* Validate each ID */ + foreach ($candidateIDs as $index => $candidateID) + { + if (!$this->isRequiredIDValid($index, $candidateIDs)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid candidate ID.'); + return; + } + } + + $db_str = implode(", ", $candidateIDs); + + $db = DatabaseConnection::getInstance(); + + $rs = $db->getAllAssoc(sprintf( + 'SELECT candidate_id, first_name, last_name, email1, email2 ' + . 'FROM candidate ' + . 'WHERE candidate_id IN (%s)', + $db_str + )); + + $emailTemplates = new EmailTemplates($this->_siteID); + $emailTemplatesRS = $emailTemplates->getAllCustom(); + + //$this->_template->assign('privledgedUser', $privledgedUser); + $this->_template->assign('active', $this); + $this->_template->assign('success', false); + $this->_template->assign('emailTemplatesRS', $emailTemplatesRS); + $this->_template->assign('recipients', $rs); + $this->_template->assign('sessionCookie', $_SESSION['CATS']->getCookie()); + $this->_template->display('./modules/candidates/SendEmail.tpl'); + } + } + + private function onShowQuestionnaire() + { + $candidateID = isset($_GET[$id='candidateID']) ? $_GET[$id] : false; + $title = isset($_GET[$id='questionnaireTitle']) ? urldecode($_GET[$id]) : false; + $printOption = isset($_GET[$id='print']) ? $_GET[$id] : ''; + $printValue = !strcasecmp($printOption, 'yes') ? true : false; + + if (!$candidateID || !$title) + { + CommonErrors::fatal(COMMONERROR_BADINDEX, $this, 'Bad Server Information.'); + } + + $candidates = new Candidates($this->_siteID); + $cData = $candidates->get($candidateID); + + $questionnaire = new Questionnaire($this->_siteID); + $qData = $questionnaire->getCandidateQuestionnaire($candidateID, $title); + + $attachment = new Attachments($this->_siteID); + $attachments = $attachment->getAll(DATA_ITEM_CANDIDATE, $candidateID); + if (!empty($attachments)) + { + $resume = $candidates->getResume($attachments[0]['attachmentID']); + $this->_template->assign('resumeText', str_replace("\n", "
\n", htmlentities(DatabaseSearch::fulltextDecode($resume['text'])))); + $this->_template->assign('resumeTitle', htmlentities($resume['title'])); + } + + $this->_template->assign('active', $this); + $this->_template->assign('candidateID', $candidateID); + $this->_template->assign('title', $title); + $this->_template->assign('cData', $cData); + $this->_template->assign('qData', $qData); + $this->_template->assign('print', $printValue); + + $this->_template->display('./modules/candidates/Questionnaire.tpl'); + } + + private function findDuplicateCandidateSearch() + { + $duplicateCandidateID = $_GET['candidateID']; + if($duplicateCandidateID == "") + { + $duplicateCandidateID = $_POST['candidateID']; + } + $query = $this->getSanitisedInput('wildCardString', $_POST); + $mode = $this->getSanitisedInput('mode', $_POST); + + /* Execute the search. */ + $search = new SearchCandidates($this->_siteID); + switch ($mode) + { + case 'searchByCandidateName': + $rs = $search->byFullName($query, 'candidate.last_name', 'ASC', true); + $resultsMode = true; + break; + + default: + $rs = $search->all($query, 'candidate.last_name', 'ASC', 'true'); + $resultsMode = false; + break; + } + + $candidates = new Candidates($this->_siteID); + + foreach ($rs as $rowIndex => $row) + { + $rs[$rowIndex]['duplicateCandidateID'] = $duplicateCandidateID; + if ($candidates->checkIfLinked($rs[$rowIndex]['candidateID'], $duplicateCandidateID)) + { + $rs[$rowIndex]['linked'] = true; + } + else + { + $rs[$rowIndex]['linked'] = false; + } + + if ($row['isHot'] == 1) + { + $rs[$rowIndex]['linkClass'] = 'jobLinkHot'; + } + else + { + $rs[$rowIndex]['linkClass'] = 'jobLinkCold'; + } + } + + if (!eval(Hooks::get('DUPLICATE_ON_LINK_DUPLICATES'))) return; + + $this->_template->assign('rs', $rs); + $this->_template->assign('isFinishedMode', false); + $this->_template->assign('isResultsMode', $resultsMode); + $this->_template->assign('duplicateCandidateID', $duplicateCandidateID); + $this->_template->display('./modules/candidates/LinkDuplicity.tpl'); + } + + private function mergeDuplicates() + { + $candidates = new Candidates($this->_siteID); + $oldCandidateID = $_GET['oldCandidateID']; + $newCandidateID = $_GET['newCandidateID']; + + $rsOld = $candidates->getWithDuplicity($oldCandidateID); + $rsNew = $candidates->getWithDuplicity($newCandidateID); + + $this->_template->assign('isFinishedMode', false); + $this->_template->assign('rsOld', $rsOld); + $this->_template->assign('rsNew', $rsNew); + $this->_template->assign('oldCandidateID', $oldCandidateID); + $this->_template->assign('newCandidateID', $newCandidateID); + $this->_template->display('./modules/candidates/Merge.tpl'); + } + + private function mergeDuplicatesInfo() + { + $candidates = new Candidates($this->_siteID); + $params = array(); + $params['firstName'] = $_POST['firstName']; + $params['middleName'] = $_POST['middleName']; + $params['lastName'] = $_POST['lastName']; + if(isset($_POST['email'])) + { + $params['emails'] = $_POST['email']; + } + else + { + $params['emails'] = array(); + } + $params['phoneCell'] = $_POST['phoneCell']; + $params['phoneWork'] = $_POST['phoneWork']; + $params['phoneHome'] = $_POST['phoneHome']; + $params['address'] = $_POST['address']; + $params['website'] = $_POST['website']; + $params['oldCandidateID'] = $_POST['oldCandidateID']; + $params['newCandidateID'] = $_POST['newCandidateID']; + + $candidates->mergeDuplicates($params, $candidates->getWithDuplicity($params['newCandidateID'])); + $this->_template->assign('isFinishedMode', true); + $this->_template->display('./modules/candidates/Merge.tpl'); + } + + private function removeDuplicity() + { + $candidates = new Candidates($this->_siteID); + $oldCandidateID = $_GET['oldCandidateID']; + $newCandidateID = $_GET['newCandidateID']; + $candidates->removeDuplicity($oldCandidateID, $newCandidateID); + $url = CATSUtility::getIndexName()."?m=candidates"; + header("Location: " . $url); /* Redirect browser */ + exit(); + } + + + private function addDuplicates() + { + $candidates = new Candidates($this->_siteID); + $oldCandidateID = $_GET['candidateID']; + $newCandidateID = $_GET['duplicateCandidateID']; + $candidates->addDuplicates($newCandidateID, $oldCandidateID); + $this->_template->assign('isFinishedMode', true); + $this->_template->display('./modules/candidates/LinkDuplicity.tpl'); + } +} + +?> diff --git a/modules/careers/Blank.tpl b/modules/careers/Blank.tpl index 42e66ea6..906e27f0 100755 --- a/modules/careers/Blank.tpl +++ b/modules/careers/Blank.tpl @@ -1,45 +1,45 @@ - - - - - <?php $this->_($this->siteName); ?> - Careers - - - - - - - - - - - - - - - - template['Header']); ?> - - - template['Content']); ?> - - - template['Footer']); ?> -
-



-
-
- - -
- Powered by: OpenCATS - Applicant Tracking System -
-
- - - + + + + + <?php $this->_($this->siteName); ?> - Careers + + + + + + + + + + + + + + + + template['Header']); ?> + + + template['Content']); ?> + + + template['Footer']); ?> +
+



+
+
+ + +
+ Powered by: OpenCATS - Applicant Tracking System +
+
+ + + diff --git a/modules/contacts/AddActivityScheduleEventModal.tpl b/modules/contacts/AddActivityScheduleEventModal.tpl index c3014441..3a36dbf9 100755 --- a/modules/contacts/AddActivityScheduleEventModal.tpl +++ b/modules/contacts/AddActivityScheduleEventModal.tpl @@ -1,180 +1,180 @@ - - -onlyScheduleEvent): ?> - - - - - -isFinishedMode): ?> - - - -
- - - - - onlyScheduleEvent): ?>style="display:none;"> - - - - - onlyScheduleEvent): ?>style="display:none;"> - - - - - - - - - -
- - - -
- - - onlyScheduleEvent): ?>checked onclick="AS_onAddActivityChange('addActivity', 'activityTypeID', 'activityNote', 'addActivitySpanA', 'addActivitySpanB');" />Log an Activity
-
- Activity Type
-
- Activity Notes
- -
-
- - - onlyScheduleEvent): ?>checked/>onlyScheduleEvent): ?>Schedule Event -
- - - - - - -
-
- -
- -
- -
- -
- -   -   - -
- -
- All Day / No Specific Time
-
- -
- Public Entry -
-
-
-
- -
-
-
- -
- -
allowEventReminders): ?>style="display:none;"> -  
-
- - -
-
-
-   - -
- - - - - changesMade): ?> -

No changes have been made.

- - onlyScheduleEvent): ?> - activityAdded): ?> - activityDescription)): ?> -

An activity entry of type _($this->activityType); ?> has been added with the following note: "activityDescription); ?>".

- -

An activity entry of type _($this->activityType); ?> has been added with no notes.

- - -

No activity entries have been added.

- - - - - eventHTML); ?> - -
- -
- - - - + + +onlyScheduleEvent): ?> + + + + + +isFinishedMode): ?> + + + +
+ + + + + onlyScheduleEvent): ?>style="display:none;"> + + + + + onlyScheduleEvent): ?>style="display:none;"> + + + + + + + + + +
+ + + +
+ + + onlyScheduleEvent): ?>checked onclick="AS_onAddActivityChange('addActivity', 'activityTypeID', 'activityNote', 'addActivitySpanA', 'addActivitySpanB');" />Log an Activity
+
+ Activity Type
+
+ Activity Notes
+ +
+
+ + + onlyScheduleEvent): ?>checked/>onlyScheduleEvent): ?>Schedule Event +
+ + + + + + +
+
+ +
+ +
+ +
+ +
+ +   +   + +
+ +
+ All Day / No Specific Time
+
+ +
+ Public Entry +
+
+
+
+ +
+
+
+ +
+ +
allowEventReminders): ?>style="display:none;"> +  
+
+ + +
+
+
+   + +
+ + + + + changesMade): ?> +

No changes have been made.

+ + onlyScheduleEvent): ?> + activityAdded): ?> + activityDescription)): ?> +

An activity entry of type _($this->activityType); ?> has been added with the following note: "activityDescription); ?>".

+ +

An activity entry of type _($this->activityType); ?> has been added with no notes.

+ + +

No activity entries have been added.

+ + + + + eventHTML); ?> + +
+ +
+ + + + diff --git a/modules/home/Error.tpl b/modules/home/Error.tpl index c07b4865..fa0bde84 100755 --- a/modules/home/Error.tpl +++ b/modules/home/Error.tpl @@ -1,25 +1,25 @@ - - - -active); ?> -
- - -
- - - - - -
- Candidates  -

CATS: Error

- -

- A fatal error has occurred.
-
- errorMessage); ?> -

-
-
- + + + +active); ?> +
+ + +
+ + + + + +
+ Candidates  +

CATS: Error

+ +

+ A fatal error has occurred.
+
+ errorMessage); ?> +

+
+
+ diff --git a/modules/lists/List.tpl b/modules/lists/List.tpl index 8b22f196..8f8f6b56 100755 --- a/modules/lists/List.tpl +++ b/modules/lists/List.tpl @@ -1,49 +1,49 @@ - - - -active); ?> -
- - -
- - - - - - -
- Job Orders  -

Lists: _($this->listRS['description']); ?>

- - -  Delete List -
- -

- _($this->listRS['description']); ?> - - Page dataGrid->getCurrentPageHTML()); ?> - (dataGrid->getNumberOfRows()); ?> Items) - - - dataGrid->drawRowsPerPageSelector(); ?> - dataGrid->drawShowFilterControl(); ?> -   -

- - dataGrid->drawFilterArea(); ?> - dataGrid->draw(); ?> - -
- - dataGrid->printActionArea(); ?> - - - dataGrid->printNavigation(true); ?> -   -
- -
-
- - + + + +active); ?> +
+ + +
+ + + + + + +
+ Job Orders  +

Lists: _($this->listRS['description']); ?>

+ + +  Delete List +
+ +

+ _($this->listRS['description']); ?> - + Page dataGrid->getCurrentPageHTML()); ?> + (dataGrid->getNumberOfRows()); ?> Items) + + + dataGrid->drawRowsPerPageSelector(); ?> + dataGrid->drawShowFilterControl(); ?> +   +

+ + dataGrid->drawFilterArea(); ?> + dataGrid->draw(); ?> + +
+ + dataGrid->printActionArea(); ?> + + + dataGrid->printNavigation(true); ?> +   +
+ +
+
+ + diff --git a/modules/lists/Lists.tpl b/modules/lists/Lists.tpl index ed8a51f7..44f027a4 100755 --- a/modules/lists/Lists.tpl +++ b/modules/lists/Lists.tpl @@ -1,80 +1,80 @@ - - - -active); ?> -
- - -
dataGrid->getNumberOfRows() ? ' style="background-color: #E6EEFF; padding: 0px;"' : ''; ?>> - dataGrid->getNumberOfRows()): ?> - - - - - - -
- Job Orders  -

Lists: Home

-
- - - - - - - -
-
-
-
- -

- Lists - - Page dataGrid->getCurrentPageHTML()); ?> (dataGrid->getNumberOfRows()); ?> Items) - - - dataGrid->drawRowsPerPageSelector(); ?> -   -

- - dataGrid->drawFilterArea(); ?> - dataGrid->draw(); ?> - -
- - - - - dataGrid->printNavigation(true); ?> -   -
- - -



-
-   -
-

- - - - - -
- -
- Create lists to group candidates, job orders, companies and contacts and perform actions on them quickly. -

- - Create lists from the job orders, candidates, companies or contacts tab. - -
-
- - - -
-
- - + + + +active); ?> +
+ + +
dataGrid->getNumberOfRows() ? ' style="background-color: #E6EEFF; padding: 0px;"' : ''; ?>> + dataGrid->getNumberOfRows()): ?> + + + + + + +
+ Job Orders  +

Lists: Home

+
+ + + + + + + +
+
+
+
+ +

+ Lists - + Page dataGrid->getCurrentPageHTML()); ?> (dataGrid->getNumberOfRows()); ?> Items) + + + dataGrid->drawRowsPerPageSelector(); ?> +   +

+ + dataGrid->drawFilterArea(); ?> + dataGrid->draw(); ?> + +
+ + + + + dataGrid->printNavigation(true); ?> +   +
+ + +



+
+   +
+

+ + + + + +
+ +
+ Create lists to group candidates, job orders, companies and contacts and perform actions on them quickly. +

+ + Create lists from the job orders, candidates, companies or contacts tab. + +
+
+ + + +
+
+ + diff --git a/modules/lists/ListsUI.php b/modules/lists/ListsUI.php index b5f132c8..d3f452ca 100755 --- a/modules/lists/ListsUI.php +++ b/modules/lists/ListsUI.php @@ -1,378 +1,378 @@ -_authenticationRequired = true; - $this->_moduleDirectory = 'lists'; - $this->_moduleName = 'lists'; - $this->_moduleTabText = 'Lists'; - $this->_subTabs = array( - 'Show Lists' => CATSUtility::getIndexName() . '?m=lists' - /* 'New Static List' => CATSUtility::getIndexName() . '?m=lists&a=newListStatic*al=' . ACCESS_LEVEL_EDIT . '@lists.newListStatic', */ - /* 'New Dynamic List' => CATSUtility::getIndexName() . '?m=lists&a=newListDynamic*al=' . ACCESS_LEVEL_EDIT . '@lists.newListDynamic' */ - ); - } - - - public function handleRequest() - { - $action = $this->getAction(); - - if (!eval(Hooks::get('LISTS_HANDLE_REQUEST'))) return; - - switch ($action) - { - /* FIXME: function show() undefined - case 'show': - $this->show(); - break; - */ - - case 'showList': - $this->showList(); - break; - - /* Add to list popup. */ - case 'quickActionAddToListModal': - $this->quickActionAddToListModal(); - break; - - /* Add to list popup via datagrid. */ - case 'addToListFromDatagridModal': - $this->addToListFromDatagridModal(); - break; - - case 'removeFromListDatagrid': - $this->removeFromListDatagrid(); - break; - - case 'deleteStaticList': - $this->onDeleteStaticList(); - break; - - /* Main list page. */ - case 'listByView': - default: - $this->listByView(); - break; - } - } - - /* - * Called by handleRequest() to process loading the list / main page. - */ - private function listByView() - { - /* First, if we are operating in HR mode we will never see the - companies pager. Immediantly forward to My Company. */ - - $dataGridProperties = DataGrid::getRecentParamaters("lists:ListsDataGrid"); - - /* If this is the first time we visited the datagrid this session, the recent paramaters will - * be empty. Fill in some default values. */ - if ($dataGridProperties == array()) - { - $dataGridProperties = array('rangeStart' => 0, - 'maxResults' => 15, - 'filterVisible' => false); - } - - $dataGrid = DataGrid::get("lists:ListsDataGrid", $dataGridProperties); - - $this->_template->assign('active', $this); - $this->_template->assign('dataGrid', $dataGrid); - $this->_template->assign('userID', $_SESSION['CATS']->getUserID()); - - if (!eval(Hooks::get('LISTS_LIST_BY_VIEW'))) return; - - $this->_template->display('./modules/lists/Lists.tpl'); - } - - /* - * Called by handleRequest() to process loading the static list display. - */ - - private function showList() - { - /* Bail out if we don't have a valid candidate ID. */ - if (!$this->isRequiredIDValid('savedListID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); - return; - //$this->fatalModal('Invalid saved list ID.'); - } - - //$dateAvailable = $this->getTrimmedInput('dateAvailable', $_POST); - - $savedListID = $_GET['savedListID']; - - $savedLists = new SavedLists($this->_siteID); - - $listRS = $savedLists->get($savedListID); - - if ($listRS['isDynamic'] == 0) - { - // Handle each kind of static list here: - - switch($listRS['dataItemType']) - { - case DATA_ITEM_CANDIDATE: - $dataGridInstance = 'candidates:candidatesSavedListByViewDataGrid'; - break; - - case DATA_ITEM_COMPANY: - $dataGridInstance = 'companies:companiesSavedListByViewDataGrid'; - break; - - case DATA_ITEM_CONTACT: - $dataGridInstance = 'contacts:contactSavedListByViewDataGrid'; - break; - - case DATA_ITEM_JOBORDER: - $dataGridInstance = 'joborders:joborderSavedListByViewDataGrid'; - break; - } - } - - $dataGridProperties = DataGrid::getRecentParamaters($dataGridInstance, $savedListID); - - /* If this is the first time we visited the datagrid this session, the recent paramaters will - * be empty. Fill in some default values. */ - if ($dataGridProperties == array()) - { - $dataGridProperties = array('rangeStart' => 0, - 'maxResults' => 15, - 'filterVisible' => false, - 'savedListStatic' => true); - } - - /* Add an MRU entry. */ - $_SESSION['CATS']->getMRU()->addEntry( - DATA_ITEM_LIST, $savedListID, $listRS['description'] - ); - - $dataGrid = DataGrid::get($dataGridInstance, $dataGridProperties, $savedListID); - - $this->_template->assign('active', $this); - $this->_template->assign('dataGrid', $dataGrid); - $this->_template->assign('listRS', $listRS); - $this->_template->assign('userID', $_SESSION['CATS']->getUserID()); - - $this->_template->display('./modules/lists/List.tpl'); - - } - - /* - * Called by handleRequest to process loading the add to list popup window. - */ - private function quickActionAddToListModal() - { - /* Bail out if we don't have a valid type. */ - if (!$this->isRequiredIDValid('dataItemType', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); - return; - } - - /* Bail out if we don't have a valid id. */ - if (!$this->isRequiredIDValid('dataItemID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); - return; - } - - $dataItemType = $_GET['dataItemType']; - $dataItemID = $_GET['dataItemID']; - $dataItemIDArray = array($dataItemID); - - $savedLists = new SavedLists($this->_siteID); - - $savedListsRS = $savedLists->getAll($dataItemType, STATIC_LISTS); - - $dataItemDesc = TemplateUtility::getDataItemTypeDescription($dataItemType); - - $this->_template->assign('dataItemDesc', $dataItemDesc); - $this->_template->assign('savedListsRS', $savedListsRS); - $this->_template->assign('dataItemType', $dataItemType); - $this->_template->assign('dataItemIDArray', $dataItemIDArray); - $this->_template->assign('sessionCookie', $_SESSION['CATS']->getCookie()); - - $this->_template->display('./modules/lists/QuickActionAddToListModal.tpl'); - } - - /* - * Called by handleRequest to process loading the add to list popup window from a datagrid. - */ - private function addToListFromDatagridModal() - { - /* Bail out if we don't have a valid type. */ - if (!$this->isRequiredIDValid('dataItemType', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); - return; - } - - $dataGrid = DataGrid::getFromRequest(); - - $dataItemIDArray = $dataGrid->getExportIDs(); - - /* Validate each ID */ - foreach ($dataItemIDArray as $index => $dataItemID) - { - if (!$this->isRequiredIDValid($index, $dataItemIDArray)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid data item ID.'); - return; - } - } - - $dataItemType = $_GET['dataItemType']; - - $savedLists = new SavedLists($this->_siteID); - - $savedListsRS = $savedLists->getAll($dataItemType, STATIC_LISTS); - - $dataItemDesc = TemplateUtility::getDataItemTypeDescription($dataItemType); - - $this->_template->assign('dataItemDesc', $dataItemDesc); - $this->_template->assign('savedListsRS', $savedListsRS); - $this->_template->assign('dataItemType', $dataItemType); - $this->_template->assign('dataItemIDArray', $dataItemIDArray); - $this->_template->assign('sessionCookie', $_SESSION['CATS']->getCookie()); - - $this->_template->display('./modules/lists/QuickActionAddToListModal.tpl'); - } - - /* - * Called by handleRequest to process the remove items from datagrid popup. - */ - private function removeFromListDatagrid() - { - /* Bail out if we don't have a valid type. */ - if (!$this->isRequiredIDValid('dataItemType', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); - return; - } - - $dataGrid = DataGrid::getFromRequest(); - - $dataItemIDArray = $dataGrid->getExportIDs(); - - /* Validate each ID */ - foreach ($dataItemIDArray as $index => $dataItemID) - { - if (!$this->isRequiredIDValid($index, $dataItemIDArray)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid data item ID.'); - return; - } - } - - $dataItemType = $_GET['dataItemType']; - - $dataItemDesc = TemplateUtility::getDataItemTypeDescription($dataItemType); - - if (!$this->isRequiredIDValid('savedListID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid saved list ID.'); - return; - } - - $savedListID = $_GET['savedListID']; - - /* Remove the items */ - $savedLists = new SavedLists($this->_siteID); - - $dataItemIDArrayTemp = array(); - foreach ($dataItemIDArray as $dataItemID) - { - $dataItemIDArrayTemp[] = $dataItemID; - /* Because its too slow adding 1 item at a time, we do it in spurts of 200 items. */ - if (count($dataItemIDArrayTemp) > 200) - { - $savedLists->removeEntryMany($savedListID, $dataItemIDArrayTemp); - $dataItemIDArrayTemp = array(); - } - } - if (count($dataItemIDArrayTemp) > 0) - { - $savedLists->removeEntryMany($savedListID, $dataItemIDArrayTemp); - } - - /* Redirect to the saved list page we were on. */ - /* FIXME: What if we are on the last page? */ - CATSUtility::transferRelativeURI('m=lists&a=showList&savedListID='.$savedListID); - } - - /* - * Called by handleRequest to delete a list. - */ - private function onDeleteStaticList() - { - /* Bail out if we don't have a valid type. */ - if (!$this->isRequiredIDValid('savedListID', $_GET)) - { - CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); - return; - } - - $savedListID = $_GET['savedListID']; - - $savedLists = new SavedLists($this->_siteID); - - /* Write changes. */ - $savedLists->delete($savedListID); - - - CATSUtility::transferRelativeURI('m=lists'); - } -} - -?> +_authenticationRequired = true; + $this->_moduleDirectory = 'lists'; + $this->_moduleName = 'lists'; + $this->_moduleTabText = 'Lists'; + $this->_subTabs = array( + 'Show Lists' => CATSUtility::getIndexName() . '?m=lists' + /* 'New Static List' => CATSUtility::getIndexName() . '?m=lists&a=newListStatic*al=' . ACCESS_LEVEL_EDIT . '@lists.newListStatic', */ + /* 'New Dynamic List' => CATSUtility::getIndexName() . '?m=lists&a=newListDynamic*al=' . ACCESS_LEVEL_EDIT . '@lists.newListDynamic' */ + ); + } + + + public function handleRequest() + { + $action = $this->getAction(); + + if (!eval(Hooks::get('LISTS_HANDLE_REQUEST'))) return; + + switch ($action) + { + /* FIXME: function show() undefined + case 'show': + $this->show(); + break; + */ + + case 'showList': + $this->showList(); + break; + + /* Add to list popup. */ + case 'quickActionAddToListModal': + $this->quickActionAddToListModal(); + break; + + /* Add to list popup via datagrid. */ + case 'addToListFromDatagridModal': + $this->addToListFromDatagridModal(); + break; + + case 'removeFromListDatagrid': + $this->removeFromListDatagrid(); + break; + + case 'deleteStaticList': + $this->onDeleteStaticList(); + break; + + /* Main list page. */ + case 'listByView': + default: + $this->listByView(); + break; + } + } + + /* + * Called by handleRequest() to process loading the list / main page. + */ + private function listByView() + { + /* First, if we are operating in HR mode we will never see the + companies pager. Immediantly forward to My Company. */ + + $dataGridProperties = DataGrid::getRecentParamaters("lists:ListsDataGrid"); + + /* If this is the first time we visited the datagrid this session, the recent paramaters will + * be empty. Fill in some default values. */ + if ($dataGridProperties == array()) + { + $dataGridProperties = array('rangeStart' => 0, + 'maxResults' => 15, + 'filterVisible' => false); + } + + $dataGrid = DataGrid::get("lists:ListsDataGrid", $dataGridProperties); + + $this->_template->assign('active', $this); + $this->_template->assign('dataGrid', $dataGrid); + $this->_template->assign('userID', $_SESSION['CATS']->getUserID()); + + if (!eval(Hooks::get('LISTS_LIST_BY_VIEW'))) return; + + $this->_template->display('./modules/lists/Lists.tpl'); + } + + /* + * Called by handleRequest() to process loading the static list display. + */ + + private function showList() + { + /* Bail out if we don't have a valid candidate ID. */ + if (!$this->isRequiredIDValid('savedListID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); + return; + //$this->fatalModal('Invalid saved list ID.'); + } + + //$dateAvailable = $this->getTrimmedInput('dateAvailable', $_POST); + + $savedListID = $_GET['savedListID']; + + $savedLists = new SavedLists($this->_siteID); + + $listRS = $savedLists->get($savedListID); + + if ($listRS['isDynamic'] == 0) + { + // Handle each kind of static list here: + + switch($listRS['dataItemType']) + { + case DATA_ITEM_CANDIDATE: + $dataGridInstance = 'candidates:candidatesSavedListByViewDataGrid'; + break; + + case DATA_ITEM_COMPANY: + $dataGridInstance = 'companies:companiesSavedListByViewDataGrid'; + break; + + case DATA_ITEM_CONTACT: + $dataGridInstance = 'contacts:contactSavedListByViewDataGrid'; + break; + + case DATA_ITEM_JOBORDER: + $dataGridInstance = 'joborders:joborderSavedListByViewDataGrid'; + break; + } + } + + $dataGridProperties = DataGrid::getRecentParamaters($dataGridInstance, $savedListID); + + /* If this is the first time we visited the datagrid this session, the recent paramaters will + * be empty. Fill in some default values. */ + if ($dataGridProperties == array()) + { + $dataGridProperties = array('rangeStart' => 0, + 'maxResults' => 15, + 'filterVisible' => false, + 'savedListStatic' => true); + } + + /* Add an MRU entry. */ + $_SESSION['CATS']->getMRU()->addEntry( + DATA_ITEM_LIST, $savedListID, $listRS['description'] + ); + + $dataGrid = DataGrid::get($dataGridInstance, $dataGridProperties, $savedListID); + + $this->_template->assign('active', $this); + $this->_template->assign('dataGrid', $dataGrid); + $this->_template->assign('listRS', $listRS); + $this->_template->assign('userID', $_SESSION['CATS']->getUserID()); + + $this->_template->display('./modules/lists/List.tpl'); + + } + + /* + * Called by handleRequest to process loading the add to list popup window. + */ + private function quickActionAddToListModal() + { + /* Bail out if we don't have a valid type. */ + if (!$this->isRequiredIDValid('dataItemType', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); + return; + } + + /* Bail out if we don't have a valid id. */ + if (!$this->isRequiredIDValid('dataItemID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); + return; + } + + $dataItemType = $_GET['dataItemType']; + $dataItemID = $_GET['dataItemID']; + $dataItemIDArray = array($dataItemID); + + $savedLists = new SavedLists($this->_siteID); + + $savedListsRS = $savedLists->getAll($dataItemType, STATIC_LISTS); + + $dataItemDesc = TemplateUtility::getDataItemTypeDescription($dataItemType); + + $this->_template->assign('dataItemDesc', $dataItemDesc); + $this->_template->assign('savedListsRS', $savedListsRS); + $this->_template->assign('dataItemType', $dataItemType); + $this->_template->assign('dataItemIDArray', $dataItemIDArray); + $this->_template->assign('sessionCookie', $_SESSION['CATS']->getCookie()); + + $this->_template->display('./modules/lists/QuickActionAddToListModal.tpl'); + } + + /* + * Called by handleRequest to process loading the add to list popup window from a datagrid. + */ + private function addToListFromDatagridModal() + { + /* Bail out if we don't have a valid type. */ + if (!$this->isRequiredIDValid('dataItemType', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); + return; + } + + $dataGrid = DataGrid::getFromRequest(); + + $dataItemIDArray = $dataGrid->getExportIDs(); + + /* Validate each ID */ + foreach ($dataItemIDArray as $index => $dataItemID) + { + if (!$this->isRequiredIDValid($index, $dataItemIDArray)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid data item ID.'); + return; + } + } + + $dataItemType = $_GET['dataItemType']; + + $savedLists = new SavedLists($this->_siteID); + + $savedListsRS = $savedLists->getAll($dataItemType, STATIC_LISTS); + + $dataItemDesc = TemplateUtility::getDataItemTypeDescription($dataItemType); + + $this->_template->assign('dataItemDesc', $dataItemDesc); + $this->_template->assign('savedListsRS', $savedListsRS); + $this->_template->assign('dataItemType', $dataItemType); + $this->_template->assign('dataItemIDArray', $dataItemIDArray); + $this->_template->assign('sessionCookie', $_SESSION['CATS']->getCookie()); + + $this->_template->display('./modules/lists/QuickActionAddToListModal.tpl'); + } + + /* + * Called by handleRequest to process the remove items from datagrid popup. + */ + private function removeFromListDatagrid() + { + /* Bail out if we don't have a valid type. */ + if (!$this->isRequiredIDValid('dataItemType', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); + return; + } + + $dataGrid = DataGrid::getFromRequest(); + + $dataItemIDArray = $dataGrid->getExportIDs(); + + /* Validate each ID */ + foreach ($dataItemIDArray as $index => $dataItemID) + { + if (!$this->isRequiredIDValid($index, $dataItemIDArray)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid data item ID.'); + return; + } + } + + $dataItemType = $_GET['dataItemType']; + + $dataItemDesc = TemplateUtility::getDataItemTypeDescription($dataItemType); + + if (!$this->isRequiredIDValid('savedListID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this, 'Invalid saved list ID.'); + return; + } + + $savedListID = $_GET['savedListID']; + + /* Remove the items */ + $savedLists = new SavedLists($this->_siteID); + + $dataItemIDArrayTemp = array(); + foreach ($dataItemIDArray as $dataItemID) + { + $dataItemIDArrayTemp[] = $dataItemID; + /* Because its too slow adding 1 item at a time, we do it in spurts of 200 items. */ + if (count($dataItemIDArrayTemp) > 200) + { + $savedLists->removeEntryMany($savedListID, $dataItemIDArrayTemp); + $dataItemIDArrayTemp = array(); + } + } + if (count($dataItemIDArrayTemp) > 0) + { + $savedLists->removeEntryMany($savedListID, $dataItemIDArrayTemp); + } + + /* Redirect to the saved list page we were on. */ + /* FIXME: What if we are on the last page? */ + CATSUtility::transferRelativeURI('m=lists&a=showList&savedListID='.$savedListID); + } + + /* + * Called by handleRequest to delete a list. + */ + private function onDeleteStaticList() + { + /* Bail out if we don't have a valid type. */ + if (!$this->isRequiredIDValid('savedListID', $_GET)) + { + CommonErrors::fatalModal(COMMONERROR_BADINDEX, $this); + return; + } + + $savedListID = $_GET['savedListID']; + + $savedLists = new SavedLists($this->_siteID); + + /* Write changes. */ + $savedLists->delete($savedListID); + + + CATSUtility::transferRelativeURI('m=lists'); + } +} + +?> diff --git a/modules/settings/downloads.css b/modules/settings/downloads.css index e68bd808..597383c8 100755 --- a/modules/settings/downloads.css +++ b/modules/settings/downloads.css @@ -1,9 +1,9 @@ -/* Downloads Supported Types > Settings tab > Downloads */ - -#settingsDownloads { clear: both; width: 600px; } -#settingsDownloads h4 { margin: 15px 0 0 0;font: bold 14px Arial, sans-serif; color: #000; } -table.downloadSupportedGrid { margin: 0 0 15px 0; padding: 0; border: 1px solid #ccc; border-left: none; text-align: left; width: 600px; } -table.downloadSupportedGrid tr.headers { background: #f3e1d2; } -table.downloadSupportedGrid tr.headers span { vertical-align: super; } -table.downloadSupportedGrid td { padding: 0 0 0 10px; border-left: 1px solid #ccc; height: 25px; } +/* Downloads Supported Types > Settings tab > Downloads */ + +#settingsDownloads { clear: both; width: 600px; } +#settingsDownloads h4 { margin: 15px 0 0 0;font: bold 14px Arial, sans-serif; color: #000; } +table.downloadSupportedGrid { margin: 0 0 15px 0; padding: 0; border: 1px solid #ccc; border-left: none; text-align: left; width: 600px; } +table.downloadSupportedGrid tr.headers { background: #f3e1d2; } +table.downloadSupportedGrid tr.headers span { vertical-align: super; } +table.downloadSupportedGrid td { padding: 0 0 0 10px; border-left: 1px solid #ccc; height: 25px; } table.downloadSupportedGrid td.category { width: 125px; font: normal 14px Arial, sans-serif; text-align: left; } \ No newline at end of file diff --git a/modules/settings/tags.tpl b/modules/settings/tags.tpl index 6712d83f..aae8b12f 100644 --- a/modules/settings/tags.tpl +++ b/modules/settings/tags.tpl @@ -1,150 +1,150 @@ - - - - -active, $this->subActive); ?> -
- - -
- - - - - -
- Settings  -

Settings: Administration

- -

Tags Settings

- - - - - -
- - - - - - - - - -
- - -
-
    - tagsRS as $index => $data){ ?> - - -
  • -
    - - - -
    -
  • - -
- - -
    • - -
    • - -
      -
      -
      -
    • - -
    • -
      - - - -
      -
    • -
    -
  • -
  • - -
    - - -
    -
  • -
    -
    -
    -
    -
    - + + + + +active, $this->subActive); ?> +
    + + +
    + + + + + +
    + Settings  +

    Settings: Administration

    + +

    Tags Settings

    + + + + + +
    + + + + + + + + + +
    + + +
    +
      + tagsRS as $index => $data){ ?> + + +
    • +
      + + + +
      +
    • + +
    + + +
    • + +
    • + +
      +
      +
      +
    • + +
    • +
      + + + +
      +
    • +
    +
  • +
  • + +
    + + +
    +
  • +
    +
    +
    +
    +
    + diff --git a/modules/tests/SampleAddressesToParse.txt b/modules/tests/SampleAddressesToParse.txt index 4966c986..ad8c0415 100755 --- a/modules/tests/SampleAddressesToParse.txt +++ b/modules/tests/SampleAddressesToParse.txt @@ -1,85 +1,85 @@ -John Mast -1666 North Park Ln -Alpharetta, GA 30004 -US -dfwefl@yahoo.com - Mobile: 404-483-1324 -Contact Preference: Telephone ------------------------------------------------------------ - -Graham Smith -1334 Greenfield Place -O Fallon, IL 62269 -US -gsmith@yahoo.com - -Mobile: (843)123-1234 -Contact Preference: E-Mail ------------------------------------------------------------ - -Jane Sutton -1226 Whaleview Dr. -St.Paul MN, 55302 -US -jsutton@gmail.com - -Mobile: (803)840-5290 -Contact Preference: E-Mail ------------------------------------------------------------ -Graham John Graham -52560 Decora Park -New Haven, MI 48028 -US -grcurio@wowway.com - -Mobile: 522-332-2522 -Work: -Home: -Contact Preference: E-Mail ------------------------------------------------------------ -Asif Saif -150 South Fox Road -Sterling, VA 20164 -US -asif@abusaif.com - -Mobile: (203) 939-6364 -Home: (203) 420-3888 ------------------------------------------------------------ - -Lee Ann James -4148 Stanton Blvd -Plano, TX 75093 -US -ljsud@yahoo.com - -Primary Phone: (974) 456-4564 ------------------------------------------------------------ -Michael Nicholas O'Malley -57570 Decora Park -Address2 -My Really Long City , MI 48048 -US -mikeomalleyo@wowway.com - -Mobile: 586-212-4456 -Work: -Home: -Contact Preference: E-Mail ------------------------------------------------------------ -Brian Schuweiler -schuw004@umn.edu -5890 Highlands Trail North -Lake Elmo, MN 55042 -(651) 770-0453 - - -...hard to parse: -Todd Daft 159 Acalypha -Punta Gorda, FL 45678 -US -todd.daft@smartbinary.com - Mobile: 787.481.5035 Fax: 787.214.9224 -Contact Preference: E-Mail -URL: http://smartbinary.com ------------------------------------------------------------ +John Mast +1666 North Park Ln +Alpharetta, GA 30004 +US +dfwefl@yahoo.com + Mobile: 404-483-1324 +Contact Preference: Telephone +----------------------------------------------------------- + +Graham Smith +1334 Greenfield Place +O Fallon, IL 62269 +US +gsmith@yahoo.com + +Mobile: (843)123-1234 +Contact Preference: E-Mail +----------------------------------------------------------- + +Jane Sutton +1226 Whaleview Dr. +St.Paul MN, 55302 +US +jsutton@gmail.com + +Mobile: (803)840-5290 +Contact Preference: E-Mail +----------------------------------------------------------- +Graham John Graham +52560 Decora Park +New Haven, MI 48028 +US +grcurio@wowway.com + +Mobile: 522-332-2522 +Work: +Home: +Contact Preference: E-Mail +----------------------------------------------------------- +Asif Saif +150 South Fox Road +Sterling, VA 20164 +US +asif@abusaif.com + +Mobile: (203) 939-6364 +Home: (203) 420-3888 +----------------------------------------------------------- + +Lee Ann James +4148 Stanton Blvd +Plano, TX 75093 +US +ljsud@yahoo.com + +Primary Phone: (974) 456-4564 +----------------------------------------------------------- +Michael Nicholas O'Malley +57570 Decora Park +Address2 +My Really Long City , MI 48048 +US +mikeomalleyo@wowway.com + +Mobile: 586-212-4456 +Work: +Home: +Contact Preference: E-Mail +----------------------------------------------------------- +Brian Schuweiler +schuw004@umn.edu +5890 Highlands Trail North +Lake Elmo, MN 55042 +(651) 770-0453 + + +...hard to parse: +Todd Daft 159 Acalypha +Punta Gorda, FL 45678 +US +todd.daft@smartbinary.com + Mobile: 787.481.5035 Fax: 787.214.9224 +Contact Preference: E-Mail +URL: http://smartbinary.com +----------------------------------------------------------- diff --git a/modules/xml/xml_templates/indeed.xtpl b/modules/xml/xml_templates/indeed.xtpl index 8a3aadf3..7e6027f4 100755 --- a/modules/xml/xml_templates/indeed.xtpl +++ b/modules/xml/xml_templates/indeed.xtpl @@ -1,29 +1,29 @@ -# This is Indeed.com's XML export template to be used when automatically -# adding jobs to their database from OPENCATS' career portal site. - ->>header - - -OPENCATS Applicant Tracking System -http://www.opencats.org -$[date] -<
    >job - -<![CDATA[$[jobTitle]]]> - - - - - - - - - - -<>footer - -<