From cac7608e0b580e126357d1b34ea6af47cdaf4b92 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 18 Aug 2022 13:49:27 +0200 Subject: [PATCH] backport export of search result from 6.0.x --- CHANGELOG | 1 + inc/inc.ClassDownloadMgr.php | 230 +++++++++++++++++++++++++++++++ out/out.Search.php | 29 ++-- views/bootstrap/class.Search.php | 70 +++++++++- 4 files changed, 319 insertions(+), 11 deletions(-) create mode 100644 inc/inc.ClassDownloadMgr.php diff --git a/CHANGELOG b/CHANGELOG index a84406e29..7b32f7c12 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ - link behind logo in header can be set in extension - move attributes for documents and folders on search page into own accordion - search page uses conversion mgr for preview images +- backport export of search result from seeddms 6.0.x -------------------------------------------------------------------------------- Changes in version 5.1.26 diff --git a/inc/inc.ClassDownloadMgr.php b/inc/inc.ClassDownloadMgr.php new file mode 100644 index 000000000..e6636ab0e --- /dev/null +++ b/inc/inc.ClassDownloadMgr.php @@ -0,0 +1,230 @@ + + * @copyright 2015 Uwe Steinmann + * @version Release: @package_version@ + */ + +#require_once("PHPExcel.php"); +require_once("vendor/autoload.php"); + +/** + * Class to represent an download manager + * + * This class provides some very basic methods to download document lists. + * + * @category DMS + * @package SeedDMS + * @author Uwe Steinmann + * @copyright 2015 Uwe Steinmann + * @version Release: @package_version@ + */ +class SeedDMS_Download_Mgr { + /** + * @var string $tmpdir directory where download archive is temp. created + * @access protected + */ + protected $tmpdir; + + /** + * @var array $items list of document content items + * @access protected + */ + protected $items; + + /** + * @var array $extracols list of arrays with extra columns per item + * @access protected + */ + protected $extracols; + + /** + * @var array $rawcontents list of content used instead of document content + * @access protected + */ + protected $rawcontents; + + /** + * @var array $filenames filename used in archive + * @access protected + */ + protected $filnames; + + function __construct($tmpdir = '') { + $this->tmpdir = $tmpdir; + $this->items = array(); + $this->header = array(getMLText('download_header_document_no'), getMLText('download_header_document_name'), getMLText('download_header_filename'), getMLText('download_header_state'), getMLText('download_header_internal_version'), getMLText('download_header_reviewer'), getMLText('download_header_review_date'), getMLText('download_header_review_comment'), getMLText('download_header_review_state'), getMLText('download_header_approver'), getMLText('download_header_approval_date'), getMLText('download_header_approval_comment'), getMLText('download_header_approval_state')); + $this->extracols = array(); + $this->rawcontents = array(); + $this->extraheader = array(); + } + + public function addHeader($extraheader) { /* {{{ */ + $this->extraheader = $extraheader; + } /* }}} */ + + public function addItem($item, $extracols=array(), $rawcontent='', $filename='') { /* {{{ */ + $this->items[$item->getID()] = $item; + $this->extracols[$item->getID()] = $extracols; + $this->rawcontents[$item->getID()] = $rawcontent; + $this->filenames[$item->getID()] = $filename; + } /* }}} */ + + public function createToc($file) { /* {{{ */ + $items = $this->items; + $objPHPExcel = new PhpOffice\PhpSpreadsheet\Spreadsheet(); + $objPHPExcel->getProperties()->setCreator("SeedDMS")->setTitle("Metadata"); + $sheet = $objPHPExcel->setActiveSheetIndex(0); + + $i = 1; + $col = 0; + foreach($this->header as $h) + $sheet->setCellValueByColumnAndRow($col++, $i, $h); + foreach($this->extraheader as $h) + $sheet->setCellValueByColumnAndRow($col++, $i, $h); + $i++; + foreach($items as $item) { + $document = $item->getDocument(); + $dms = $document->_dms; + $status = $item->getStatus(); + $reviewStatus = $item->getReviewStatus(); + $approvalStatus = $item->getApprovalStatus(); + + $col = 0; + $sheet->setCellValueByColumnAndRow($col++, $i, $document->getID()); + $sheet->setCellValueByColumnAndRow($col++, $i, $document->getName()); + $sheet->setCellValueByColumnAndRow($col++, $i, $document->getID()."-".$item->getOriginalFileName()); + $sheet->setCellValueByColumnAndRow($col++, $i, getOverallStatusText($status['status'])); + $sheet->setCellValueByColumnAndRow($col++, $i, $item->getVersion()); + $l = $i; + $k = $i; + if($reviewStatus) { + foreach ($reviewStatus as $r) { + switch ($r["type"]) { + case 0: // Reviewer is an individual. + $required = $dms->getUser($r["required"]); + if (!is_object($required)) { + $reqName = getMLText("unknown_user")." '".$r["required"]."'"; + } else { + $reqName = htmlspecialchars($required->getFullName()." (".$required->getLogin().")"); + } + break; + case 1: // Reviewer is a group. + $required = $dms->getGroup($r["required"]); + if (!is_object($required)) { + $reqName = getMLText("unknown_group")." '".$r["required"]."'"; + } else { + $reqName = htmlspecialchars($required->getName()); + } + break; + } + $tcol = $col; + $sheet->setCellValueByColumnAndRow($tcol++, $l, $reqName); + $sheet->setCellValueByColumnAndRow($tcol, $l, ($r['status']==1 || $r['status']==-1) ? PHPExcel_Shared_Date::PHPToExcel(new DateTime($r['date'])) : null); + $sheet->getStyleByColumnAndRow($tcol++, $l)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22); + $sheet->setCellValueByColumnAndRow($tcol++, $l, $r['comment']); + $sheet->setCellValueByColumnAndRow($tcol++, $l, getReviewStatusText($r["status"])); + $l++; + } + $l--; + } + $col += 4; + if($approvalStatus) { + foreach ($approvalStatus as $r) { + switch ($r["type"]) { + case 0: // Reviewer is an individual. + $required = $dms->getUser($r["required"]); + if (!is_object($required)) { + $reqName = getMLText("unknown_user")." '".$r["required"]."'"; + } else { + $reqName = htmlspecialchars($required->getFullName()." (".$required->getLogin().")"); + } + break; + case 1: // Reviewer is a group. + $required = $dms->getGroup($r["required"]); + if (!is_object($required)) { + $reqName = getMLText("unknown_group")." '".$r["required"]."'"; + } else { + $reqName = htmlspecialchars($required->getName()); + } + break; + } + $tcol = $col; + $sheet->setCellValueByColumnAndRow($tcol++, $k, $reqName); + $sheet->setCellValueByColumnAndRow($tcol, $k, ($r['status']==1 || $r['status']==-1) ?PHPExcel_Shared_Date::PHPToExcel(new DateTime($r['date'])) : null); + $sheet->getStyleByColumnAndRow($tcol++, $k)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22); + $sheet->setCellValueByColumnAndRow($tcol++, $k, $r['comment']); + $sheet->setCellValueByColumnAndRow($tcol++, $k, getApprovalStatusText($r["status"])); + $k++; + } + $k--; + } + $col += 4; + if(isset($this->extracols[$item->getID()]) && $this->extracols[$item->getID()]) { + foreach($this->extracols[$item->getID()] as $column) + $sheet->setCellValueByColumnAndRow($col++, $i, $column); + } + $i = max($l, $k); + $i++; + } + + $objWriter = new PhpOffice\PhpSpreadsheet\Writer\Xlsx($objPHPExcel); + $objWriter->save($file); + + return true; + } /* }}} */ + + public function createArchive($filename) { /* {{{ */ + if(!$this->items) { + return false; + } + + $file = tempnam(sys_get_temp_dir(), "export-list-"); + if(!$file) + return false; + $this->createToc($file); + + $zip = new ZipArchive(); + $prefixdir = date('Y-m-d', time()); + + if(($errcode = $zip->open($filename, ZipArchive::OVERWRITE)) !== TRUE) { + echo $errcode; + return false; + } + + foreach($this->items as $item) { + $document = $item->getDocument(); + $dms = $document->_dms; + if($this->filenames[$item->getID()]) { + $filename = $this->filenames[$item->getID()]; + } else { + $ext = pathinfo($document->getName(), PATHINFO_EXTENSION); + $oext = pathinfo($item->getOriginalFileName(), PATHINFO_EXTENSION); + if($ext == $oext) + $filename = preg_replace('/[^A-Za-z0-9_.-]/', '_', $document->getName()); + else { + $filename = preg_replace('/[^A-Za-z0-9_-]/', '_', $document->getName()).'.'.$oext; + } + $filename = $document->getID().'-'.$item->getVersion().'-'.$filename; //$lc->getOriginalFileName(); + } + $filename = $prefixdir."/".$filename; + if($this->rawcontents[$item->getID()]) { + $zip->addFromString(utf8_decode($filename), $this->rawcontents[$item->getID()]); + } else + $zip->addFile($dms->contentDir.$item->getPath(), utf8_decode($filename)); + } + + $zip->addFile($file, $prefixdir."/metadata.xlsx"); + $zip->close(); + unlink($file); + return true; + } /* }}} */ +} diff --git a/out/out.Search.php b/out/out.Search.php index 9238d56d0..f99a43d1a 100644 --- a/out/out.Search.php +++ b/out/out.Search.php @@ -49,6 +49,10 @@ if (isset($_GET["navBar"])) { } } +$includecontent = false; +if (isset($_GET["includecontent"]) && $_GET["includecontent"]) + $includecontent = true; + $fullsearch = ((!isset($_GET["fullsearch"]) && $settings->_defaultSearchMethod == 'fulltext') || !empty($_GET["fullsearch"])) && $settings->_enableFullSearch; if($fullsearch) { // Search in Fulltext {{{ @@ -460,7 +464,7 @@ if($fullsearch) { $pageNumber = (int) $_GET["pg"]; } elseif (!strcasecmp($_GET["pg"], "all")) { - // $limit = 0; + $pageNumber = "all"; } } @@ -495,11 +499,13 @@ if($fullsearch) { $entries = array(); $fcount = 0; - if($resArr['folders']) { - foreach ($resArr['folders'] as $entry) { - if ($entry->getAccessMode($user) >= M_READ) { - $entries[] = $entry; - $fcount++; + if(!isset($_GET['action']) || $_GET['action'] != 'export') { + if($resArr['folders']) { + foreach ($resArr['folders'] as $entry) { + if ($entry->getAccessMode($user) >= M_READ) { + $entries[] = $entry; + $fcount++; + } } } } @@ -507,13 +513,16 @@ if($fullsearch) { if($resArr['docs']) { foreach ($resArr['docs'] as $entry) { if ($entry->getAccessMode($user) >= M_READ) { - $entry->verifyLastestContentExpriry(); - $entries[] = $entry; - $dcount++; + if($entry->getLatestContent()) { + $entry->verifyLastestContentExpriry(); + $entries[] = $entry; + $dcount++; + } } } } - if (!isset($_GET["pg"]) || strcasecmp($_GET["pg"], "all")) { + $totalPages = 1; + if ((!isset($_GET['action']) || $_GET['action'] != 'export') && (!isset($_GET["pg"]) || strcasecmp($_GET["pg"], "all"))) { $totalPages = (int) (count($entries)/$limit); if(count($entries)%$limit) $totalPages++; diff --git a/views/bootstrap/class.Search.php b/views/bootstrap/class.Search.php index 67d57ef18..85d79736e 100644 --- a/views/bootstrap/class.Search.php +++ b/views/bootstrap/class.Search.php @@ -57,6 +57,14 @@ class SeedDMS_View_Search extends SeedDMS_Theme_Style { parent::jsTranslations(array('cancel', 'splash_move_document', 'confirm_move_document', 'move_document', 'confirm_transfer_link_document', 'transfer_content', 'link_document', 'splash_move_folder', 'confirm_move_folder', 'move_folder')); +?> +$(document).ready( function() { + $('#export').on('click', function(e) { + e.preventDefault(); + window.location.href = $(this).attr('href')+'&includecontent='+($('#includecontent').prop('checked') ? '1' : '0'); + }); +}); +printFolderChooserJs("form1"); $this->printDeleteFolderButtonJs(); $this->printDeleteDocumentButtonJs(); @@ -71,7 +79,48 @@ $(document).ready(function() { params['dms']; + $user = $this->params['user']; + $entries = $this->params['searchhits']; + $includecontent = $this->params['includecontent']; + + include("../inc/inc.ClassDownloadMgr.php"); + $downmgr = new SeedDMS_Download_Mgr(); + if($extraheader = $this->callHook('extraDownloadHeader')) + $downmgr->addHeader($extraheader); + foreach($entries as $entry) { + if($entry->isType('document')) { + $extracols = $this->callHook('extraDownloadColumns', $entry); + $filename = $this->callHook('filenameDownloadItem', $entry->getLatestContent()); + if($includecontent && $rawcontent = $this->callHook('rawcontent', $entry->getLatestContent())) { + $downmgr->addItem($entry->getLatestContent(), $extracols, $rawcontent, $filename); + } else + $downmgr->addItem($entry->getLatestContent(), $extracols, null, $filename); + } + } + $filename = tempnam(sys_get_temp_dir(), ''); + if($includecontent) { + $downmgr->createArchive($filename); + header("Content-Transfer-Encoding: binary"); + header("Content-Length: " . filesize($filename)); + header("Content-Disposition: attachment; filename=\"export-" .date('Y-m-d') . ".zip\""); + header("Content-Type: application/zip"); + header("Cache-Control: must-revalidate"); + } else { + $downmgr->createToc($filename); + header("Content-Transfer-Encoding: binary"); + header("Content-Length: " . filesize($filename)); + header("Content-Disposition: attachment; filename=\"export-" .date('Y-m-d') . ".xlsx\""); + header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + header("Cache-Control: must-revalidate"); + } + + readfile($filename); + unlink($filename); + } /* }}} */ + + function opensearchsuggestion() { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; $query = $this->params['query']; @@ -475,6 +524,25 @@ function typeahead() { /* {{{ */ // }}} $this->formSubmit(" ".getMLText('search')); + + if($totaldocs) { + ob_start(); + $this->formField( + getMLText("include_content"), + array( + 'element'=>'input', + 'type'=>'checkbox', + 'name'=>'includecontent', + 'id'=>'includecontent', + 'value'=>1, + ) + ); + //$this->formSubmit(" ".getMLText('export')); + print $this->html_link('Search', array_merge($_GET, array('action'=>'export')), array('class'=>'btn btn-primary', 'id'=>'export'), " ".getMLText("export"), false, true)."\n"; + $content = ob_get_clean(); + $this->printAccordion(getMLText('export'), $content); + } + ?>