* @author Romain Quetiez * @author Denis Flaven * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL */ class Attachment extends DBObject { public static function Init() { $aParams = array ( "category" => "addon", "key_type" => "autoincrement", "name_attcode" => array('item_class', 'temp_id'), "state_attcode" => "", "reconc_keys" => array(), "db_table" => "attachment", "db_key_field" => "id", "db_finalclass_field" => "", ); MetaModel::Init_Params($aParams); MetaModel::Init_InheritAttributes(); MetaModel::Init_AddAttribute(new AttributeDateTime("expire", array("allowed_values"=>null, "sql"=>"expire", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("temp_id", array("allowed_values"=>null, "sql"=>"temp_id", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("item_class", array("allowed_values"=>null, "sql"=>"item_class", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("item_id", array("allowed_values"=>null, "sql"=>"item_id", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeBlob("contents", array("depends_on"=>array()))); MetaModel::Init_SetZListItems('details', array('temp_id', 'item_class', 'item_id')); MetaModel::Init_SetZListItems('advanced_search', array('temp_id', 'item_class', 'item_id')); MetaModel::Init_SetZListItems('standard_search', array('temp_id', 'item_class', 'item_id')); MetaModel::Init_SetZListItems('list', array('temp_id', 'item_class', 'item_id')); } // Todo - implement a cleanup function (see a way to do that generic !) } class AttachmentPlugIn implements iApplicationUIExtension, iApplicationObjectExtension { public function OnDisplayProperties($oObject, WebPage $oPage, $bEditMode = false) { if ($this->GetAttachmentsPosition() == 'properties') { $this->DisplayAttachments($oObject, $oPage, $bEditMode); } } public function OnDisplayRelations($oObject, WebPage $oPage, $bEditMode = false) { if ($this->GetAttachmentsPosition() == 'relations') { $this->DisplayAttachments($oObject, $oPage, $bEditMode); } } public function OnFormSubmit($oObject, $sFormPrefix = '') { if ($this->IsTargetObject($oObject)) { // For new objects attachments are processed in OnDBInsert if (!$oObject->IsNew()) { self::UpdateAttachments($oObject); } } } protected function GetMaxUpload() { $iMaxUpload = ini_get('upload_max_filesize'); if (!$iMaxUpload) { $sRet = Dict::S('Attachments:UploadNotAllowedOnThisSystem'); } else { $iMaxUpload = utils::ConvertToBytes($iMaxUpload); if ($iMaxUpload > 1024*1024*1024) { $sRet = Dict::Format('Attachment:Max_Go', sprintf('%0.2f', $iMaxUpload/(1024*1024*1024))); } else if ($iMaxUpload > 1024*1024) { $sRet = Dict::Format('Attachment:Max_Mo', sprintf('%0.2f', $iMaxUpload/(1024*1024))); } else { $sRet = Dict::Format('Attachment:Max_Ko', sprintf('%0.2f', $iMaxUpload/(1024))); } } return $sRet; } public function OnFormCancel($sTempId) { // Delete all "pending" attachments for this form $sOQL = 'SELECT Attachment WHERE temp_id = :temp_id'; $oSearch = DBObjectSearch::FromOQL($sOQL); $oSet = new DBObjectSet($oSearch, array(), array('temp_id' => $sTempId)); while($oAttachment = $oSet->Fetch()) { $oAttachment->DBDelete(); // Pending attachment, don't mention it in the history } } public function EnumUsedAttributes($oObject) { return array(); } public function GetIcon($oObject) { return ''; } public function GetHilightClass($oObject) { // Possible return values are: // HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE return HILIGHT_CLASS_NONE; } public function EnumAllowedActions(DBObjectSet $oSet) { // No action return array(); } public function OnIsModified($oObject) { if ($this->IsTargetObject($oObject)) { $aAttachmentIds = utils::ReadParam('attachments', array()); $aRemovedAttachmentIds = utils::ReadParam('removed_attachments', array()); if ( (count($aAttachmentIds) > 0) || (count($aRemovedAttachmentIds) > 0) ) { return true; } } return false; } public function OnCheckToWrite($oObject) { return array(); } public function OnCheckToDelete($oObject) { return array(); } public function OnDBUpdate($oObject, $oChange = null) { } public function OnDBInsert($oObject, $oChange = null) { if ($this->IsTargetObject($oObject)) { self::UpdateAttachments($oObject, $oChange); } } public function OnDBDelete($oObject, $oChange = null) { if ($this->IsTargetObject($oObject)) { $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_class = :class AND item_id = :item_id"); $oSet = new DBObjectSet($oSearch, array(), array('class' => get_class($oObject), 'item_id' => $oObject->GetKey())); while ($oAttachment = $oSet->Fetch()) { $oAttachment->DBDelete(); } } } /////////////////////////////////////////////////////////////////////////////////////////////////////// // // Plug-ins specific functions // /////////////////////////////////////////////////////////////////////////////////////////////////////// protected function IsTargetObject($oObject) { $aAllowedClasses = MetaModel::GetModuleSetting('itop-attachments', 'allowed_classes', array('Ticket')); foreach($aAllowedClasses as $sAllowedClass) { if ($oObject instanceof $sAllowedClass) { return true; } } return false; } protected function GetAttachmentsPosition() { return MetaModel::GetModuleSetting('itop-attachments', 'position', 'relations'); } var $m_bDeleteEnabled = true; public function EnableDelete($bEnabled) { $this->m_bDeleteEnabled = $bEnabled; } public function DisplayAttachments($oObject, WebPage $oPage, $bEditMode = false) { // Exit here if the class is not allowed if (!$this->IsTargetObject($oObject)) return; $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_class = :class AND item_id = :item_id"); $oSet = new DBObjectSet($oSearch, array(), array('class' => get_class($oObject), 'item_id' => $oObject->GetKey())); if ($this->GetAttachmentsPosition() == 'relations') { $sTitle = ($oSet->Count() > 0)? Dict::Format('Attachments:TabTitle_Count', $oSet->Count()) : Dict::S('Attachments:EmptyTabTitle'); $oPage->SetCurrentTab($sTitle); } $oPage->add_style( <<add('
'); $oPage->add(''.Dict::S('Attachments:FieldsetTitle').''); if ($bEditMode) { $sIsDeleteEnabled = $this->m_bDeleteEnabled ? 'true' : 'false'; $iTransactionId = $oPage->GetTransactionId(); $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'modules/itop-attachments/ajaxfileupload.js'); $sClass = get_class($oObject); $sTempId = session_id().'_'.$iTransactionId; $sDeleteBtn = Dict::S('Attachments:DeleteBtn'); $oPage->add_script( <<
'+data.msg+'

'); if($sIsDeleteEnabled) { $('#display_attachment_'+data.att_id).hover( function() { $(this).children(':button').toggleClass('btn_hidden'); } ); } //alert(data.msg); } } }, error: function (data, status, e) { alert(e); } } ) return false; } EOF ); $oPage->add(''); while ($oAttachment = $oSet->Fetch()) { $iAttId = $oAttachment->GetKey(); $oDoc = $oAttachment->Get('contents'); $sFileName = $oDoc->GetFileName(); $sIcon = utils::GetAbsoluteUrlAppRoot().AttachmentPlugIn::GetFileIcon($sFileName); $sDownloadLink = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php/?operation=download_document&class=Attachment&id='.$iAttId.'&field=contents'; $oPage->add(''); } $oPage->add(''); $oPage->add('
'); $sMaxUpload = $this->GetMaxUpload(); $oPage->p(Dict::S('Attachments:AddAttachment').' '.$sMaxUpload); //$oPage->p(''); $oPage->p(''); $oPage->add('
'); if ($this->m_bDeleteEnabled) { $oPage->add_ready_script('$(".attachment").hover( function() {$(this).children(":button").toggleClass("btn_hidden"); } );'); } } else { $oPage->add(''); while ($oAttachment = $oSet->Fetch()) { $iAttId = $oAttachment->GetKey(); $oDoc = $oAttachment->Get('contents'); $sFileName = $oDoc->GetFileName(); $sIcon = utils::GetAbsoluteUrlAppRoot().AttachmentPlugIn::GetFileIcon($sFileName); $sDownloadLink = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php/?operation=download_document&class=Attachment&id='.$iAttId.'&field=contents'; $oPage->add(''); } } } protected static function UpdateAttachments($oObject, $oChange = null) { $iTransactionId = utils::ReadParam('transaction_id', null); if (!is_null($iTransactionId)) { $aActions = array(); $aAttachmentIds = utils::ReadParam('attachments', array()); // Get all current attachments $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_class = :class AND item_id = :item_id"); $oSet = new DBObjectSet($oSearch, array(), array('class' => get_class($oObject), 'item_id' => $oObject->GetKey())); while ($oAttachment = $oSet->Fetch()) { // Remove attachments that are no longer attached to the current object if (!in_array($oAttachment->GetKey(), $aAttachmentIds)) { $oAttachment->DBDelete(); $aActions[] = self::GetActionDescription($oAttachment, false /* false => deletion */); } } // Attach new (temporary) attachements $sTempId = session_id().'_'.$iTransactionId; // The object is being created from a form, check if there are pending attachments // for this object, but deleting the "new" ones that were already removed from the form $aRemovedAttachmentIds = utils::ReadParam('removed_attachments', array()); $sOQL = 'SELECT Attachment WHERE temp_id = :temp_id'; $oSearch = DBObjectSearch::FromOQL($sOQL); foreach($aAttachmentIds as $iAttachmentId) { $oSet = new DBObjectSet($oSearch, array(), array('temp_id' => $sTempId)); while($oAttachment = $oSet->Fetch()) { if (in_array($oAttachment->GetKey(),$aRemovedAttachmentIds)) { $oAttachment->DBDelete(); // temporary attachment removed, don't even mention it in the history } else { $oAttachment->Set('item_id', $oObject->GetKey()); $oAttachment->Set('temp_id', ''); $oAttachment->DBUpdate(); // temporary attachment confirmed, list it in the history $aActions[] = self::GetActionDescription($oAttachment, true /* true => creation */); } } } if (count($aActions) > 0) { if ($oChange == null) { // Let's create a change if non is supplied $oChange = MetaModel::NewObject("CMDBChange"); $oChange->Set("date", time()); $sUserString = CMDBChange::GetCurrentUserName(); $oChange->Set("userinfo", $sUserString); $iChangeId = $oChange->DBInsert(); } foreach($aActions as $sActionDescription) { self::RecordHistory($oChange, $oObject, $sActionDescription); } } } } ///////////////////////////////////////////////////////////////////////////////////////// public static function GetFileIcon($sFileName) { $aPathParts = pathinfo($sFileName); switch($aPathParts['extension']) { case 'doc': case 'docx': $sIcon = 'doc.png'; break; case 'xls': case 'xlsx': $sIcon = 'xls.png'; break; case 'ppt': case 'pptx': $sIcon = 'ppt.png'; break; case 'pdf': $sIcon = 'pdf.png'; break; case 'txt': case 'text': $sIcon = 'txt.png'; break; case 'rtf': $sIcon = 'rtf.png'; break; case 'odt': $sIcon = 'odt.png'; break; case 'ods': $sIcon = 'ods.png'; break; case 'odp': $sIcon = 'odp.png'; break; case 'html': case 'htm': $sIcon = 'html.png'; break; case 'png': case 'gif': case 'jpg': case 'jpeg': case 'tiff': case 'tif': case 'bmp': $sIcon = 'image.png'; break; case 'zip': case 'gz': case 'tgz': case 'rar': $sIcon = 'zip.png'; break; default: $sIcon = 'document.png'; break; } return "modules/itop-attachments/icons/$sIcon"; } ///////////////////////////////////////////////////////////////////////// private static function RecordHistory(CMDBChange $oChange, $oTargetObject, $sDescription) { $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpPlugin"); $oMyChangeOp->Set("change", $oChange->GetKey()); $oMyChangeOp->Set("objclass", get_class($oTargetObject)); $oMyChangeOp->Set("objkey", $oTargetObject->GetKey()); $oMyChangeOp->Set("description", $sDescription); $iId = $oMyChangeOp->DBInsertNoReload(); } ///////////////////////////////////////////////////////////////////////// private static function GetActionDescription($oAttachment, $bCreate = true) { $oBlob = $oAttachment->Get('contents'); $sFileName = $oBlob->GetFileName(); if ($bCreate) { $sDescription = Dict::Format('Attachments:History_File_Added', $sFileName); } else { $sDescription = Dict::Format('Attachments:History_File_Removed', $sFileName); } return $sDescription; } } ?>