From 1bb850c221f31dd9b44e3bd1d8a5bf1aa3b43e3b Mon Sep 17 00:00:00 2001 From: Stephen Nielson Date: Sat, 17 Jun 2023 11:15:38 -0400 Subject: [PATCH] Fixes #6570 portal pdf document creator class (#6572) Pulls the portal pdf document logic from doc_lib.php into a class so we can use it / consume it in OpenEMR. --- portal/lib/doc_lib.php | 55 ++------------ src/Pdf/PatientPortalPDFDocumentCreator.php | 88 ++++++++++++++++++++++ .../DocumentTemplates/DocumentTemplateService.php | 17 +++-- 3 files changed, 105 insertions(+), 55 deletions(-) create mode 100644 src/Pdf/PatientPortalPDFDocumentCreator.php diff --git a/portal/lib/doc_lib.php b/portal/lib/doc_lib.php index 06e46dc2e..095453eb7 100644 --- a/portal/lib/doc_lib.php +++ b/portal/lib/doc_lib.php @@ -51,6 +51,7 @@ require_once(__DIR__ . "/appsql.class.php"); use Mpdf\Mpdf; use OpenEMR\Common\Csrf\CsrfUtils; +use OpenEMR\Pdf\PatientPortalPDFDocumentCreator; if (!(isset($GLOBALS['portal_onsite_two_enable'])) || !($GLOBALS['portal_onsite_two_enable'])) { echo xlt('Patient Portal is turned off'); @@ -73,24 +74,6 @@ try { $category = $result['id'] ?: 3; } $form_filename = convert_safe_file_dir_name($_REQUEST['docid']) . '_' . convert_safe_file_dir_name($cpid) . '.pdf'; - $config_mpdf = array( - 'tempDir' => $GLOBALS['MPDF_WRITE_DIR'], - 'mode' => $GLOBALS['pdf_language'], - 'format' => $GLOBALS['pdf_size'], - 'default_font_size' => '9', - 'default_font' => 'dejavusans', - 'margin_left' => $GLOBALS['pdf_left_margin'], - 'margin_right' => $GLOBALS['pdf_right_margin'], - 'margin_top' => $GLOBALS['pdf_top_margin'], - 'margin_bottom' => $GLOBALS['pdf_bottom_margin'], - 'margin_header' => '', - 'margin_footer' => '', - 'orientation' => $GLOBALS['pdf_layout'], - 'shrink_tables_to_fit' => 1, - 'use_kwt' => true, - 'autoScriptToLang' => true, - 'keep_table_proportions' => true - ); $len = stripos($htmlin, 'data:application/pdf;base64,'); if ($len !== false) { if ($dispose == "download") { @@ -115,38 +98,12 @@ try { exit(); } } - - $pdf = new mPDF($config_mpdf); - if ($_SESSION['language_direction'] == 'rtl') { - $pdf->SetDirectionality('rtl'); - } - - // snatch style tags content to insert after content purified - $style_flag = preg_match('#<\s*?style\b[^>]*>(.*?)]*>#s', $htmlin, $style_matches); - $style = str_replace('"); - - // purify html - $config = HTMLPurifier_Config::createDefault(); - $config->set('URI.AllowedSchemes', array('data' => true, 'http' => true, 'https' => true)); - $purify = new \HTMLPurifier($config); - $htmlin = $purify->purify($htmlin); - // need to create custom stylesheet for templates - // also our styles_pdf.scss isn't being compiled!!! - // replace existing style tag in template after purifies removes! why!!! - // e,g this scheme gets removed etc - $stylesheet = ""; - if ($pos !== false && $pos1 !== false && !empty($style[0] ?? '')) { - $stylesheet = str_replace('', $stylesheet, $style[0]); - } - $htmlin = "" . $stylesheet . "$htmlin"; - $pdf->writeHtml($htmlin); - + $pdfCreator = new PatientPortalPDFDocumentCreator(); + $pdfObject = $pdfCreator->createPdfObject($htmlin); if ($dispose == 'download') { header('Content-type: application/pdf'); header("Content-Disposition: attachment; filename=$form_filename"); - $pdf->Output($form_filename, 'D'); + $pdfObject->Output($form_filename, 'D'); $logit->portalLog('download document', $cpid, ('document:' . $form_filename)); exit(); } @@ -156,7 +113,7 @@ try { echo js_escape("ERROR " . xla("Missing Patient ID")); exit(); } - $data = $pdf->Output($form_filename, 'S'); + $data = $pdfObject->Output($form_filename, 'S'); $d = new Document(); $rc = $d->createDocument($cpid, $category, $form_filename, 'application/pdf', $data); $logit->portalLog('chart document', $cpid, ('document:' . $form_filename)); @@ -165,7 +122,7 @@ try { if ($dispose == 'fetch_pdf') { try { - $file = $pdf->Output($form_filename, 'S'); + $file = $pdfObject->Output($form_filename, 'S'); $file = base64_encode($file); echo $file; $logit->portalLog('fetched PDF', $cpid, ('document:' . $form_filename)); diff --git a/src/Pdf/PatientPortalPDFDocumentCreator.php b/src/Pdf/PatientPortalPDFDocumentCreator.php new file mode 100644 index 000000000..b3183b176 --- /dev/null +++ b/src/Pdf/PatientPortalPDFDocumentCreator.php @@ -0,0 +1,88 @@ + + * @author Brady Miller + * @author Discover and Change, Inc. + * @copyright Copyright (c) 2016-2022 Jerry Padgett + * @copyright Copyright (c) 2019 Brady Miller + * @copyright Copyright (c) 2023 Discover and Change, Inc. + * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 + */ + +namespace OpenEMR\Pdf; + +use Mpdf\Mpdf; +use HTMLPurifier_Config; + +class PatientPortalPDFDocumentCreator +{ + public function createPdfObject($htmlIn) + { + $config_mpdf = array( + 'tempDir' => $GLOBALS['MPDF_WRITE_DIR'], + 'mode' => $GLOBALS['pdf_language'], + 'format' => $GLOBALS['pdf_size'], + 'default_font_size' => '9', + 'default_font' => 'dejavusans', + 'margin_left' => $GLOBALS['pdf_left_margin'], + 'margin_right' => $GLOBALS['pdf_right_margin'], + 'margin_top' => $GLOBALS['pdf_top_margin'], + 'margin_bottom' => $GLOBALS['pdf_bottom_margin'], + 'margin_header' => '', + 'margin_footer' => '', + 'orientation' => $GLOBALS['pdf_layout'], + 'shrink_tables_to_fit' => 1, + 'use_kwt' => true, + 'autoScriptToLang' => true, + 'keep_table_proportions' => true + ); + + $pdf = new Mpdf($config_mpdf); + if ($_SESSION['language_direction'] == 'rtl') { + $pdf->SetDirectionality('rtl'); + } + + // snatch style tags content to insert after content purified + $style_flag = preg_match('#<\s*?style\b[^>]*>(.*?)]*>#s', $htmlIn, $style_matches); + $style = str_replace('"); + + // purify html + $config = HTMLPurifier_Config::createDefault(); + $config->set('URI.AllowedSchemes', array('data' => true, 'http' => true, 'https' => true)); + $purify = new \HTMLPurifier($config); + $htmlIn = $purify->purify($htmlIn); + // need to create custom stylesheet for templates + // also our styles_pdf.scss isn't being compiled!!! + // replace existing style tag in template after purifies removes! why!!! + // e,g this scheme gets removed etc + $stylesheet = ""; + if ($pos !== false && $pos1 !== false && !empty($style[0] ?? '')) { + $stylesheet = str_replace('', $stylesheet, $style[0]); + } + $htmlIn = "" . $stylesheet . "$htmlIn"; + $pdf->writeHtml($htmlIn); + return $pdf; + } + public function createPdfDocument($cpid, $formFilename, $documentCategory, $htmlIn) + { + + $pdf = $this->createPdfObject($htmlIn); + if (!$cpid) { + throw new \InvalidArgumentException("Missing Patient ID"); + echo js_escape("ERROR " . xla("Missing Patient ID")); + exit(); + } + $data = $pdf->Output($formFilename, 'S'); + $d = new \Document(); + $rc = $d->createDocument($cpid, $documentCategory, $formFilename, 'application/pdf', $data); + return $rc; + } +} diff --git a/src/Services/DocumentTemplates/DocumentTemplateService.php b/src/Services/DocumentTemplates/DocumentTemplateService.php index 52157f3e5..307b35745 100644 --- a/src/Services/DocumentTemplates/DocumentTemplateService.php +++ b/src/Services/DocumentTemplates/DocumentTemplateService.php @@ -21,6 +21,10 @@ use OpenEMR\Services\QuestionnaireService; */ class DocumentTemplateService extends QuestionnaireService { + const DENIAL_STATUS_EDITING = "Editing"; + const DENIAL_STATUS_IN_REVIEW = "In Review"; + const DENIAL_STATUS_LOCKED = "Locked"; + public function __construct($base_table = null) { parent::__construct($base_table ?? null); @@ -203,7 +207,7 @@ class DocumentTemplateService extends QuestionnaireService if (!$result) { return true; } - $in_review = $result['denial_reason'] === 'Locked' || $result['denial_reason'] === 'In Review'; + $in_review = $result['denial_reason'] === self::DENIAL_STATUS_LOCKED || $result['denial_reason'] === self::DENIAL_STATUS_IN_REVIEW; // must be a saved doc pending review so don't show. // patient selects the edited doc from their history. if (!$in_review) { @@ -595,9 +599,9 @@ class DocumentTemplateService extends QuestionnaireService $name = 'Repository'; } - $sql = "INSERT INTO `document_templates` - (`pid`, `provider`,`profile`, `category`, `template_name`, `location`, `status`, `template_content`, `size`, `mime`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + $sql = "INSERT INTO `document_templates` + (`pid`, `provider`,`profile`, `category`, `template_name`, `location`, `status`, `template_content`, `size`, `mime`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE `pid` = ?, `provider`= ?, `template_content`= ?, `size`= ?, `modified_date` = NOW(), `mime` = ?"; return sqlInsert($sql, array($pid, ($_SESSION['authUserID'] ?? null), ($profile ?: ''), $category ?: '', $template, $name, 'New', $content, strlen($content), $mimetype, $pid, ($_SESSION['authUserID'] ?? null), $content, strlen($content), $mimetype)); @@ -760,7 +764,7 @@ class DocumentTemplateService extends QuestionnaireService $form_data[$form['name']] = trim($form['value'] ?? ''); } $rtn = sqlInsert( - "INSERT INTO `document_template_profiles` + "INSERT INTO `document_template_profiles` (`template_id`, `profile`, `template_name`, `category`, `provider`, `recurring`, `event_trigger`, `period`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", array($profile_array['id'], $profile_array['profile'], $profile_array['name'], $profile_array['category'], ($_SESSION['authUserID'] ?? null), @@ -895,7 +899,8 @@ class DocumentTemplateService extends QuestionnaireService if ((int)$template['pid'] === 0) { $template['pid'] = $current_patient; } - $in_edit = sqlQuery("Select `id`, `doc_type`, `denial_reason` From `onsite_documents` Where (`denial_reason` = 'Editing' Or `denial_reason` = 'In Review') And `pid` = ? And `file_path` = ? Limit 1", array($template['pid'], $template['id'])) ?? 0; + $in_edit = sqlQuery("Select `id`, `doc_type`, `denial_reason` From `onsite_documents` Where (`denial_reason` = '" + . self::DENIAL_STATUS_EDITING . "' Or `denial_reason` = '" . self::DENIAL_STATUS_IN_REVIEW . "') And `pid` = ? And `file_path` = ? Limit 1", array($template['pid'], $template['id'])) ?? 0; if (empty($in_edit)) { $test = $this->showTemplateFromEvent($template); if (!$test) { -- 2.11.4.GIT