From: bradymiller Date: Sun, 28 Apr 2013 17:43:35 +0000 (-0700) Subject: Document module improvements, take 3. X-Git-Tag: whats-been-changed~326 X-Git-Url: https://repo.or.cz/w/openemr.git/commitdiff_plain/65c166b84d51621b4cdd253b815294f84ce763a9 Document module improvements, take 3. -Can now store more than one level of directory structure within the documents directory. (this information is stored in the new path_depth field in the documents sql table entry) -Incorporated into Rod's pdf report creation in custom report and in the Document module CCD/CCR document viewer. -Also will use/create random directories (0-10000) when importing a document that is not mapped to a patient to avoid all the documents being placed into one directory. -Also created some document functions (such as addNewDocument()) in library/documents.php to ease importing new documents in API etc. -Incorporated addNewDocument() function in phimail direct module. NOTE that there is a previous bug noted where documents within the CouchDB server will not work in the Document module CCD/CCR viewer. I did not address this bug on this commit. --- diff --git a/ccr/display.php b/ccr/display.php index 2635c5d08..d66827f0a 100644 --- a/ccr/display.php +++ b/ccr/display.php @@ -7,10 +7,17 @@ $document_id = $_GET['doc_id']; $d = new Document($document_id); $url = $d->get_url(); $url = preg_replace("|^(.*)://|","",$url); + +// Collect filename and path $from_all = explode("/",$url); $from_filename = array_pop($from_all); -$from_patientid = array_pop($from_all); -$temp_url = $GLOBALS['OE_SITE_DIR'] . '/documents/' . $from_patientid . '/' . $from_filename; +$from_pathname_array = array(); +for ($i=0;$i<$d->get_path_depth();$i++) { + $from_pathname_array[] = array_pop($from_all); +} +$from_pathname_array = array_reverse($from_pathname_array); +$from_pathname = implode("/",$from_pathname_array); +$temp_url = $GLOBALS['OE_SITE_DIR'] . '/documents/' . $from_pathname . '/' . $from_filename; if (!file_exists($temp_url)) { echo xl('The requested document is not present at the expected location on the filesystem or there are not sufficient permissions to access it.','','',' ') . $temp_url; }else{ @@ -38,4 +45,4 @@ if (!file_exists($temp_url)) { echo $html; } } -?> \ No newline at end of file +?> diff --git a/controllers/C_Document.class.php b/controllers/C_Document.class.php index 5032c9680..da37285ea 100644 --- a/controllers/C_Document.class.php +++ b/controllers/C_Document.class.php @@ -34,7 +34,26 @@ class C_Document extends Controller { $this->file_path = $GLOBALS['OE_SITE_DIR'].'/documents/temp/'; } else{ - $this->file_path = $this->_config['repository'] . preg_replace("/[^A-Za-z0-9]/","_",$_GET['patient_id']) . "/"; + if ( (!empty($_GET['higher_level_path'])) && (is_numeric($_GET['patient_id']) && $_GET['patient_id']>0) ) { + // Allow higher level directory structure in documents directory and a patient is mapped + $this->file_path = $this->_config['repository'] . preg_replace("/[^A-Za-z0-9\/]/","_",$_GET['higher_level_path']) . "/"; + } + else if (!empty($_GET['higher_level_path'])) { + // Allow higher level directory structure in documents directory and there is no patient mapping + // (Since a patient is not mapped, will create up to 10000 random directories and increment the path_depth by 1) + $this->file_path = $this->_config['repository'] . preg_replace("/[^A-Za-z0-9\/]/","_",$_GET['higher_level_path']) . "/" . rand(1,10000) . "/"; + $_POST['path_depth'] = $_POST['path_depth'] + 1; + } + else if ( !(is_numeric($_GET['patient_id'])) || !($_GET['patient_id']>0) ) { + // This is the default action except there is no patient mapping (when patient_id is 00 or direct) + // (Since a patient is not mapped, will create up to 10000 random directories and set the path_depth to 2) + $this->file_path = $this->_config['repository'] . preg_replace("/[^A-Za-z0-9]/","_",$_GET['patient_id']) . "/" . rand(1,10000) . "/"; + $_POST['path_depth'] = 2; + } + else { + // This is the default action where the patient is is used as one level directory structure in documents directory + $this->file_path = $this->_config['repository'] . preg_replace("/[^A-Za-z0-9]/","_",$_GET['patient_id']) . "/"; + } } $this->_args = array("patient_id" => $_GET['patient_id']); @@ -104,7 +123,7 @@ class C_Document extends Controller { }else{ if (!file_exists($this->file_path)) { - if (!mkdir($this->file_path,0700)) { + if (!mkdir($this->file_path,0700,true)) { $error .= "The system was unable to create the directory for this upload, '" . $this->file_path . "'.\n"; } } @@ -192,10 +211,16 @@ class C_Document extends Controller { $this->assign("upload_success", "true"); $d = new Document(); $d->storagemethod = $GLOBALS['document_storage_method']; - if($harddisk == true) + if($harddisk == true) { $d->url = "file://" .$this->file_path.$fname; - else + if (is_numeric($_POST['path_depth'])) { + // this is for when directory structure is more than one level + $d->path_depth = $_POST['path_depth']; + } + } + else { $d->url = $fname; + } if($couchDB == true){ $d->couch_docid = $docid; $d->couch_revid = $revid; @@ -443,18 +468,27 @@ class C_Document extends Controller { //change full path to current webroot. this is for documents that may have //been moved from a different filesystem and the full path in the database //is not current. this is also for documents that may of been moved to - //different patients + //different patients. Note that the path_depth is used to see how far down + //the path to go. For example, originally the path_depth was always 1, which + //only allowed things like documents/1/, but now can have more structured + //directories. For example a path_depth of 2 can give documents/encounters/1/ + // etc. // NOTE that $from_filename and basename($url) are the same thing $from_all = explode("/",$url); $from_filename = array_pop($from_all); - $from_patientid = array_pop($from_all); + $from_pathname_array = array(); + for ($i=0;$i<$d->get_path_depth();$i++) { + $from_pathname_array[] = array_pop($from_all); + } + $from_pathname_array = array_reverse($from_pathname_array); + $from_pathname = implode("/",$from_pathname_array); if($couch_docid && $couch_revid){ //for couchDB no URL is available in the table, hence using the foreign_id which is patientID $temp_url = $GLOBALS['OE_SITE_DIR'] . '/documents/temp/' . $d->get_foreign_id() . '_' . $from_filename; } else{ - $temp_url = $GLOBALS['OE_SITE_DIR'] . '/documents/' . $from_patientid . '/' . $from_filename; + $temp_url = $GLOBALS['OE_SITE_DIR'] . '/documents/' . $from_pathname . '/' . $from_filename; } if (file_exists($temp_url)) { @@ -505,7 +539,7 @@ class C_Document extends Controller { $url = $GLOBALS['OE_SITE_DIR'] . '/documents/temp/' . $convertedFile; } else{ - $url = $GLOBALS['OE_SITE_DIR'] . '/documents/' . $from_patientid . '/' . $convertedFile; + $url = $GLOBALS['OE_SITE_DIR'] . '/documents/' . $from_pathname . '/' . $convertedFile; } header("Pragma: public"); header("Expires: 0"); @@ -776,12 +810,21 @@ class C_Document extends Controller { //change full path to current webroot. this is for documents that may have //been moved from a different filesystem and the full path in the database //is not current. this is also for documents that may of been moved to - //different patients + //different patients. Note that the path_depth is used to see how far down + //the path to go. For example, originally the path_depth was always 1, which + //only allowed things like documents/1/, but now can have more structured + //directories. For example a path_depth of 2 can give documents/encounters/1/ + // etc. // NOTE that $from_filename and basename($url) are the same thing $from_all = explode("/",$url); $from_filename = array_pop($from_all); - $from_patientid = array_pop($from_all); - $temp_url = $GLOBALS['OE_SITE_DIR'] . '/documents/' . $from_patientid . '/' . $from_filename; + $from_pathname_array = array(); + for ($i=0;$i<$d->get_path_depth();$i++) { + $from_pathname_array[] = array_pop($from_all); + } + $from_pathname_array = array_reverse($from_pathname_array); + $from_pathname = implode("/",$from_pathname_array); + $temp_url = $GLOBALS['OE_SITE_DIR'] . '/documents/' . $from_pathname . '/' . $from_filename; if (file_exists($temp_url)) { $url = $temp_url; } diff --git a/interface/patient_file/report/custom_report.php b/interface/patient_file/report/custom_report.php index 87975f3e7..6bfcd2a86 100644 --- a/interface/patient_file/report/custom_report.php +++ b/interface/patient_file/report/custom_report.php @@ -758,17 +758,23 @@ foreach ($ar as $key => $val) { if($couch_docid && $couch_revid){ $url_file = $d->get_couch_url($pid,$encounter); } - // just grab the last two levels, which contain filename and patientid + // Collect filename and path $from_all = explode("/",$url_file); $from_filename = array_pop($from_all); - $from_patientid = array_pop($from_all); + $from_pathname_array = array(); + for ($i=0;$i<$d->get_path_depth();$i++) { + $from_pathname_array[] = array_pop($from_all); + } + $from_pathname_array = array_reverse($from_pathname_array); + $from_pathname = implode("/",$from_pathname_array); + if($couch_docid && $couch_revid) { $from_file = $GLOBALS['OE_SITE_DIR'] . '/documents/temp/' . $from_filename; $to_file = substr($from_file, 0, strrpos($from_file, '.')) . '_converted.jpg'; } else { $from_file = $GLOBALS["fileroot"] . "/sites/" . $_SESSION['site_id'] . - '/documents/' . $from_patientid . '/' . $from_filename; + '/documents/' . $from_pathname . '/' . $from_filename; $to_file = substr($from_file, 0, strrpos($from_file, '.')) . '_converted.jpg'; } diff --git a/library/classes/Document.class.php b/library/classes/Document.class.php index 5bcb9d33d..f449df4fd 100644 --- a/library/classes/Document.class.php +++ b/library/classes/Document.class.php @@ -301,6 +301,12 @@ class Document extends ORDataObject{ function get_url_path() { return dirname(preg_replace("|^(.*)://|","",$this->url)) ."/"; } + function get_path_depth() { + return $this->path_depth; + } + function set_path_depth($path_depth) { + $this->path_depth = $path_depth; + } function set_mimetype($mimetype) { $this->mimetype = $mimetype; } diff --git a/library/direct_message_check.inc b/library/direct_message_check.inc index c2a93cca9..968b32460 100644 --- a/library/direct_message_check.inc +++ b/library/direct_message_check.inc @@ -27,6 +27,7 @@ require_once(dirname(__FILE__) . "/log.inc"); require_once(dirname(__FILE__) . "/sql.inc"); require_once(dirname(__FILE__) . "/pnotes.inc"); require_once(dirname(__FILE__) . "/../controllers/C_Document.class.php"); +require_once(dirname(__FILE__) . "/documents.php"); /** * Connect to a phiMail Direct Messaging server and check for any incoming status @@ -375,27 +376,17 @@ function phimail_service_userID($name='phimail-service') { */ function phimail_store($name,$mime_type,$fn) { - //upload using existing controller framework - $_FILES['file']['name'][0]=$name; - $_FILES['file']['type'][0]=$mime_type; - $_FILES['file']['tmp_name'][0]=$fn; - $_FILES['file']['error'][0]=0; - $_FILES['file']['size'][0]=filesize($fn); - $_GET['patient_id']='direct'; //new documents get put into in [fileroot]/sites/[site]/documents/direct/ - $_POST['destination']=''; - $_POST['submit']='Upload'; - $_POST['patient_id']='00'; //workaround because '0' becomes a Null and not a zero in documents.foreign_id - $_POST['category_id']='1'; //since we don't know what kind of document; these show up in root Documents folder - $_POST['process']='true'; - - $user = phimail_service_userID(); - - $cd = new C_Document(); - $cd->upload_action_process($user); - @unlink($fn); - $v = $cd->get_template_vars("file"); - if (!isset($v) || !$v) return false; - return array ("doc_id" => $v[0]->id, "url" => $v[0]->url); + // Collect phimail user id + $user = phimail_service_userID(); + + // Import the document + $return = addNewDocument($name,$mime_type,$fn,0,filesize($fn),$user,'direct'); + + // Remove the temporary file + @unlink($fn); + + // Return the result + return $return; } /** diff --git a/library/documents.php b/library/documents.php new file mode 100644 index 000000000..2bfd1b53d --- /dev/null +++ b/library/documents.php @@ -0,0 +1,88 @@ + + * + * LICENSE: This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see ;. + * + * @package OpenEMR + * @author Brady Miller + * @link http://www.open-emr.org + */ + +require_once($GLOBALS['fileroot']."/controllers/C_Document.class.php"); + +/** + * Function to add a document via the C_Document class. + * + * @param string $name Name of the document + * @param string $type Mime type of file + * @param string $tmp_name Temporary file name + * @param string $error Errors in file upload + * @param string $size Size of file + * @param int $owner Owner/user/service that imported the file + * @param string $patient_id_or_simple_directory Patient id or simple directory for storage when patient id not known (such as '00' or 'direct') + * @param int $category_id Document category id + * @param string $higher_level_path Can set a higher level path here (and then place the path depth in $path_depth) + * @param int $path_depth Path depth when using the $higher_level_path feature + * @return array/boolean Array(doc_id,url) of the file as stored in documents table, false = failure + */ +function addNewDocument($name,$type,$tmp_name,$error,$size,$owner='',$patient_id_or_simple_directory="00",$category_id='1',$higher_level_path='',$path_depth='1') { + + if (empty($owner)) { + $owner = $_SESSION['authUserID']; + } + + // Build the $_FILES array + $TEMP_FILES = array(); + $TEMP_FILES['file']['name'][0]=$name; + $TEMP_FILES['file']['type'][0]=$type; + $TEMP_FILES['file']['tmp_name'][0]=$tmp_name; + $TEMP_FILES['file']['error'][0]=$error; + $TEMP_FILES['file']['size'][0]=$size; + $_FILES = $TEMP_FILES; + + // Build the parameters + $_GET['higher_level_path']=$higher_level_path; + $_GET['patient_id']=$patient_id_or_simple_directory; + $_POST['destination']=''; + $_POST['submit']='Upload'; + $_POST['path_depth']=$path_depth; + $_POST['patient_id']=(is_numeric($patient_id_or_simple_directory) && $patient_id_or_simple_directory>0) ? $patient_id_or_simple_directory : "00"; + $_POST['category_id']=$category_id; + $_POST['process']='true'; + + // Add the Document and return the newly added document id + $cd = new C_Document(); + $cd->upload_action_process($owner); + $v = $cd->get_template_vars("file"); + if (!isset($v) || !$v) return false; + return array ("doc_id" => $v[0]->id, "url" => $v[0]->url); +} + +/** + * Function to return the category id of a category title. + * + * @param string $category_title category title + * @return int/boolean category id (returns false if the category title does not exist) + */ +function document_category_to_id($category_title) { + $ret = sqlQuery("SELECT `id` FROM `categories` WHERE `name`=?", array($category_title) ); + if ($ret['id']) { + return $ret['id']; + } + else { + return false; + } +} +?> diff --git a/sql/4_1_1-to-4_1_2_upgrade.sql b/sql/4_1_1-to-4_1_2_upgrade.sql index c06e8b5cf..a5acb7c1c 100644 --- a/sql/4_1_1-to-4_1_2_upgrade.sql +++ b/sql/4_1_1-to-4_1_2_upgrade.sql @@ -442,3 +442,7 @@ ALTER TABLE `immunizations` ADD COLUMN `added_erroneously` tinyint(1) NOT NULL DEFAULT '0'; #EndIf +#IfMissingColumn documents path_depth +ALTER TABLE `documents` ADD COLUMN `path_depth` TINYINT DEFAULT '1' COMMENT 'Depth of path to use in url to find document. Not applicable for CouchDB.'; +#Endif + diff --git a/sql/database.sql b/sql/database.sql index a27b78cae..1ac538891 100644 --- a/sql/database.sql +++ b/sql/database.sql @@ -671,6 +671,7 @@ CREATE TABLE `documents` ( `couch_docid` VARCHAR(100) DEFAULT NULL, `couch_revid` VARCHAR(100) DEFAULT NULL, `storagemethod` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '0->Harddisk,1->CouchDB', + `path_depth` TINYINT DEFAULT '1' COMMENT 'Depth of path to use in url to find document. Not applicable for CouchDB.', PRIMARY KEY (`id`), KEY `revision` (`revision`), KEY `foreign_id` (`foreign_id`), diff --git a/version.php b/version.php index e4cc9759f..1437517dc 100644 --- a/version.php +++ b/version.php @@ -17,7 +17,7 @@ $v_realpatch = '0'; // is a database change in the course of development. It is used // internally to determine when a database upgrade is needed. // -$v_database = 94; +$v_database = 95; // Access control version identifier, this is to be incremented whenever there // is a access control change in the course of development. It is used