vtenext/modules/Documents/storage/StorageBackendUtils.php
2021-04-28 20:10:26 +02:00

512 lines
14 KiB
PHP

<?php
/*************************************
* SPDX-FileCopyrightText: 2009-2020 Vtenext S.r.l. <info@vtenext.com>
* SPDX-License-Identifier: AGPL-3.0-only
************************************/
/* crmv@95157 */
require_once('BackendBase.php');
class StorageBackendUtils extends SDKExtendableUniqueClass {
// list of supported backends
// !!! IF YOU CHANGE THIS ARRAY YOU HAVE TO EXECUTE THE METHOD syncDB()
public $storageBackends = array(
'file' => array('class' => 'BackendFile'),
//'alfresco' => array('class' => 'BackendAlfresco'),
);
// the default backend to use
public $defaultBackend = 'file';
/**
* Insert into the picklist table _backend_name the list of supported backends
*/
public function syncDB() {
global $adb, $table_prefix;
$picklist_table = $table_prefix.'_backend_name';
if (Vtecrm_Utils::CheckTable($picklist_table)) {
$adb->query("delete from $picklist_table");
}
$values = array_keys($this->storageBackends);
if (!empty($values)) {
$fieldInstance = Vtecrm_Field::getInstance('backend_name',Vtecrm_Module::getInstance('Documents'));
$fieldInstance->setNoRolePicklistValues($values);
}
}
/**
* If module is specified, check backends restricted to the specified module
*/
public function getAvailableBackends($module = null) {
$list = array();
$backends = $this->storageBackends;
if ($module && isModuleInstalled($module)) {
$focus = CRMEntity::getInstance($module);
if ($focus && !empty($focus->storageBackends)) {
$backends = array_intersect_key($backends, $focus->storageBackends);
}
}
foreach ($backends as $name => $info) {
$label = $this->getBackendLabel($name);
if ($label) {
$list[$name] = $label;
}
}
return $list;
}
/**
* Return the label for the specified backend
*/
public function getBackendLabel($name) {
$inst = $this->getBackendClass($name);
if ($inst) {
return $inst->getLabel();
}
return '';
}
/**
* Return an instance to the backend class specified
*/
public function getBackendClass($name) {
$class = $this->storageBackends[$name]['class'];
$file = $this->storageBackends[$name]['file'] ?: $class.'.php';
$inst = null;
if (!empty($class)) {
require_once($file);
$inst = $class::getInstance();
}
return $inst;
}
/**
* Return the backend used by the attachment of a record
*/
public function getBackendForCrmid($module, $crmid) {
global $adb, $table_prefix;
$FS = FileStorage::getInstance();
$attid = $FS->getAttachmentId($crmid);
if ($attid) {
$sql = "SELECT backend_name FROM ".$table_prefix."_attachments WHERE attachmentsid = ?" ;
$res = $adb->pquery($sql, array($attid));
if ($res) {
return $adb->query_result_no_html($res, 0, 'backend_name');
}
}
return null;
}
/**
* Upload an attachment
*/
public function uploadFile($backend, $module, &$focus = null, $backendOptions = null) {
global $adb, $table_prefix;
$bclass = $this->getBackendClass($backend);
$attid = null;
$ekey = $bclass->saveFile($focus, $backendOptions, $attid);
if ($ekey && $attid) {
// update the key info
$adb->pquery("UPDATE {$table_prefix}_attachments SET backend_name = ?, backend_key = ? WHERE attachmentsid = ?", array($backend, $ekey, $attid));
unset($_REQUEST['upload_error']);
return true;
}
// error occurred!
$_REQUEST['upload_error'] = true;
return false;
}
/**
* Upload a new revision for an existing attachment
*/
public function uploadRevision($backend, $module, &$focus = null, $userEmail = null) {
global $adb, $table_prefix, $current_user;
$record = $focus->id;
$bclass = $this->getBackendClass($backend);
$now = date('Y-m-d H:i:s'); //crmv@125395
$FS = FileStorage::getInstance();
$info = $FS->getFileInfoByCrmid($record);
$oldkey = $info['backend_key'];
$doc_precedente = intval($info['attachmentsid']);
$attid = null;
$ekey = $bclass->saveFileRevision($oldkey, $focus, null, $attid);
if ($ekey && $attid) {
// update the key info
$adb->pquery("UPDATE {$table_prefix}_attachments SET backend_name = ?, backend_key = ? WHERE attachmentsid = ?", array($backend, $ekey, $attid));
} else {
return false;
}
// Update revision table
if ($doc_precedente > 0){
$q = "SELECT MAX(revision)+1 as rev FROM crmv_docs_revisioned WHERE crmid = ?";
$res = $adb->pquery($q, array($record));
if ($res) {
$revision = $adb->query_result_no_html($res,0,'rev') ?: '1';
}
$ins = "INSERT INTO crmv_docs_revisioned (crmid, attachmentid, revision, userid, revisiondate, user_email) VALUES (?,?,?,?,?,?)";
$params = Array($record, $doc_precedente, $revision,$current_user->id,$adb->formatDate($now, true),$userEmail); //crmv@125395
$adb->pquery($ins,$params);
}
return true;
}
/**
* Get all the revisions for an attachment
*/
public function getRevisions($module, $crmid) {
global $adb, $table_prefix;
$q = "SELECT attachmentid,revision,userid,revisiondate,NAME,path,user_email
FROM crmv_docs_revisioned c
LEFT JOIN {$table_prefix}_attachments a ON c.attachmentid = a.attachmentsid
WHERE crmid = ?
ORDER BY revision desc";
$res = $adb->pquery($q, array($crmid));
$revisions = array();
if ($res && $adb->num_rows($res) > 0) {
while($row = $adb->fetchByAssoc($res)){
$revisions[] = $row;
}
}
return $revisions;
}
/**
* Check if the provided record supports metadata
*/
public function checkMetadata($module, $crmid) {
$backend = $this->getBackendForCrmid($module, $crmid);
if ($backend) {
$bclass = $this->getBackendClass($backend);
return $bclass->hasMetadata;
}
return false;
}
/**
* Reads the metadata
*/
public function readMetadata($module, $crmid) {
$FS = FileStorage::getInstance();
$info = $FS->getFileInfoByCrmid($crmid);
$attid = $info['attachmentsid'];
$backend = $info['backend_name'];
$key = $info['backend_key'];
$bclass = $this->getBackendClass($backend);
return $bclass->readMetadata($attid, $key);
}
/**
* Updates the metadata
*/
public function updateMetadata($module, $crmid, $data) {
$FS = FileStorage::getInstance();
$info = $FS->getFileInfoByCrmid($crmid);
$attid = $info['attachmentsid'];
$backend = $info['backend_name'];
$key = $info['backend_key'];
$bclass = $this->getBackendClass($backend);
return $bclass->updateMetadata($attid, $key, $data);
}
/**
* Retrieve a list of all the attachments (usually limited to 1) of a record
*/
public function getAttachments($module, $crmid) {
global $adb, $table_prefix;
$list = array();
$res = $adb->pquery(
"SELECT a.* FROM {$table_prefix}_attachments a
INNER JOIN {$table_prefix}_crmentity c ON c.crmid = a.attachmentsid
INNER JOIN {$table_prefix}_seattachmentsrel sa ON sa.attachmentsid = a.attachmentsid
WHERE c.deleted = 0 AND sa.crmid = $crmid",
array($crmid)
);
if ($res && $adb->num_rows($res) > 0) {
while ($row = $adb->fetchByAssoc($res, -1, false)) {
$list[] = $row;
}
}
return $list;
}
/**
* Delete permanently all the file attachments for the given record
*/
public function deleteAttachments($module, $crmid) {
global $adb, $table_prefix;
// first get the attachments
$list = $this->getAttachments($module, $crmid);
if (!is_array($list)) return false;
foreach ($list as $attinfo) {
$attid = $attinfo['attachmentsid'];
$backend = $attinfo['backend_name'];
$bkey = $attinfo['backend_key'];
$bclass = $this->getBackendClass($backend);
if (!$bclass) continue;
$r = $bclass->deleteFile($attid, $bkey);
if (!$r) return false;
// delete the attachment entry
$adb->pquery("DELETE FROM {$table_prefix}_attachments WHERE attachmentsid = ?", array($attid));
$adb->pquery("DELETE FROM {$table_prefix}_crmentity WHERE crmid = ?", array($attid));
}
// delete all relations
$adb->pquery("DELETE FROM {$table_prefix}_seattachmentsrel WHERE crmid = ?", array($crmid));
return true;
}
/**
* Delete all attachments not attached to anything
*/
public function deleteOrphanAttachments() {
global $adb, $table_prefix;
$list = array();
$res = $adb->query(
"SELECT a.* FROM {$table_prefix}_attachments a
INNER JOIN {$table_prefix}_seattachmentsrel sa ON sa.attachmentsid = a.attachmentsid
LEFT JOIN {$table_prefix}_crmentity c ON c.crmid = sa.crmid
WHERE c.crmid IS NULL"
);
if ($res && $adb->num_rows($res) > 0) {
while ($attinfo = $adb->fetchByAssoc($res, -1, false)) {
$attid = $attinfo['attachmentsid'];
$backend = $attinfo['backend_name'];
$bkey = $attinfo['backend_key'];
$bclass = $this->getBackendClass($backend);
if (!$bclass) continue;
$r = $bclass->deleteFile($attid, $bkey);
if (!$r) return false;
// delete the attachment entry
$adb->pquery("DELETE FROM {$table_prefix}_attachments WHERE attachmentsid = ?", array($attid));
$adb->pquery("DELETE FROM {$table_prefix}_crmentity WHERE crmid = ?", array($attid));
$adb->pquery("DELETE FROM {$table_prefix}_seattachmentsrel WHERE attachmentsid = ?", array($attid));
}
}
return $list;
}
/**
* Download a file using the appropriate backend
*/
public function downloadFile($module, $crmid, $attid, $raw=false) { // crmv@189246
global $adb, $table_prefix;
$dbQuery = "SELECT backend_name, backend_key, path, name FROM ".$table_prefix."_attachments WHERE attachmentsid = ?" ;
$result = $adb->pquery($dbQuery, array($attid)) or die("Couldn't get file list");
if ($adb->num_rows($result) == 1) {
$backend = $adb->query_result_no_html($result, 0, "backend_name");
$ekey = $adb->query_result_no_html($result, 0, "backend_key");
if (!$backend) {
// fallback on the file backend
$backend = 'file';
$path = $adb->query_result_no_html($result, 0, "path");
$name = $adb->query_result_no_html($result, 0, "name");
$bclass = $this->getBackendClass($backend);
if ($bclass && method_exists($bclass, 'generateKey')) {
$ekey = $bclass->generateKey($attid);
}
} else {
$bclass = $this->getBackendClass($backend);
}
if (!$ekey) {
echo "Record is not saved correctly.";
return false;
}
$bclass->retrieveFile($attid, $ekey, array('raw'=>$raw)); // crmv@189246
} else {
echo "Record doesn't exist.";
return false;
}
return true;
}
/**
* Increment by 1 the download counter
*/
public function incrementDownloadCount($module, $crmid, $attid = null) {
global $adb, $table_prefix;
$FS = FileStorage::getInstance();
$info = $FS->getFileInfoByCrmid($crmid);
if (empty($attid)) {
$attid = $info['attachmentsid'];
}
$backend = $info['backend_name'];
$key = $info['backend_key'];
if ($backend && $key) {
$bclass = $this->getBackendClass($backend);
$bclass->incrementDownloadCount($key); // crmv@167234
}
// now increment it locally
if ($module == 'Documents') {
$sql = "UPDATE {$table_prefix}_notes SET filedownloadcount = COALESCE(filedownloadcount,0)+1 WHERE notesid= ?"; // crmv@152087
$res = $adb->pquery($sql,array($crmid));
} elseif ($module == 'Myfiles') {
$sql = "UPDATE {$table_prefix}_myfiles SET filedownloadcount = COALESCE(filedownloadcount,0)+1 WHERE myfilesid= ?"; // crmv@152087
$res = $adb->pquery($sql,array($crmid));
}
}
// crmv@152087
public function saveDownloadChangelog($module, $crmid) {
global $adb, $table_prefix, $current_user;
if ($current_user && vtlib_isModuleActive('ChangeLog')) {
// crmv@164120
$obj = ChangeLog::getInstance();
$obj->column_fields['modified_date'] = date('Y-m-d H:i:s');
$obj->column_fields['audit_no'] = $obj->get_revision_id($crmid);
$obj->column_fields['user_id'] = $current_user->id;
$obj->column_fields['parent_id'] = $crmid;
$obj->column_fields['user_name'] = $current_user->column_fields['user_name'];
$obj->column_fields['description'] = Zend_Json::encode(array('DownloadFile',$module,$crmid));
$obj->save();
// crmv@164120e
}
}
// crmv@152087e
/**
* Return values: 0 = ok, 1 = corrupted, 2 = not found, 3 = other error
*/
public function checkIntegrity($module, $crmid, $attid = null) {
$FS = FileStorage::getInstance();
$info = $FS->getFileInfoByCrmid($crmid);
if (empty($attid)) {
$attid = $info['attachmentsid'];
}
if (empty($attid)) return 2;
$backend = $info['backend_name'];
$key = $info['backend_key'];
$bclass = $this->getBackendClass($backend);
if (!$bclass) return 3;
return $bclass->checkIntegrity($attid, $key, null);
}
/**
* Convert all legacy backends (ie: 'I') to the new ones
*/
public function convertLegacyBackends() {
global $adb, $table_prefix;
$oldLocation = 'I';
$newBackend = 'file';
$bclass = $this->getBackendClass($newBackend);
$modules = array('Documents', 'Myfiles');
foreach ($modules as $module) {
$currentModule = $module;
$focus = CRMEntity::getInstance($module);
$table = $focus->table_name;
$index = $focus->table_index;
$res = $adb->pquery(
"SELECT c.crmid, a.attachmentsid
FROM $table t
INNER JOIN {$table_prefix}_crmentity c ON c.crmid = t.{$index}
INNER JOIN {$table_prefix}_seattachmentsrel sa ON sa.crmid = c.crmid
INNER JOIN {$table_prefix}_attachments a ON a.attachmentsid = sa.attachmentsid
WHERE t.filelocationtype = ?",
array($oldLocation)
);
if ($res && $adb->num_rows($res) > 0) {
while ($row = $adb->fetchByAssoc($res, -1, false)) {
$crmid = $row['crmid'];
$attid = $row['attachmentsid'];
// generate and update the backend key
$ekey = $bclass->generateKey($attid);
if ($ekey) {
$adb->pquery("UPDATE {$table_prefix}_attachments set backend_key = ?, backend_name = ? WHERE attachmentsid = ?", array($ekey, $newBackend, $attid));
}
// update the info
$adb->pquery("UPDATE {$table} set filelocationtype = ?, backend_name = ? WHERE {$index} = ?", array('B', $newBackend, $crmid));
}
}
}
}
}
function checkMetadata($instance) {
// extract the record
if (preg_match('#\([\'"]?([0-9]+)[\'"]?\)#', $instance->linkurl, $matches)) {
$module = $instance->module();
$crmid = intval($matches[1]);
if ($module && $crmid) {
$SBU = StorageBackendUtils::getInstance();
return $SBU->checkMetadata($module, $crmid);
}
}
return false;
}